Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
G
gnss
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Model registry
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
mobile_robotics
wolf_projects
wolf_lib
plugins
gnss
Commits
29ef3ecf
Commit
29ef3ecf
authored
4 years ago
by
Joan Vallvé Navarro
Browse files
Options
Downloads
Patches
Plain Diff
all INFO -> DEBUG
parent
43ea71aa
No related branches found
No related tags found
2 merge requests
!28
release after RAL
,
!27
After 2nd RAL submission
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/processor/processor_tracker_gnss.cpp
+28
-24
28 additions, 24 deletions
src/processor/processor_tracker_gnss.cpp
with
28 additions
and
24 deletions
src/processor/processor_tracker_gnss.cpp
+
28
−
24
View file @
29ef3ecf
...
@@ -28,7 +28,9 @@ void ProcessorTrackerGnss::preProcess()
...
@@ -28,7 +28,9 @@ void ProcessorTrackerGnss::preProcess()
GnssUtils
::
SnapshotPtr
inc_snapshot
=
std
::
static_pointer_cast
<
CaptureGnss
>
(
incoming_ptr_
)
->
getSnapshot
();
GnssUtils
::
SnapshotPtr
inc_snapshot
=
std
::
static_pointer_cast
<
CaptureGnss
>
(
incoming_ptr_
)
->
getSnapshot
();
#ifdef _WOLF_DEBUG
int
n_initial
=
inc_snapshot
->
getObservations
()
->
size
();
int
n_initial
=
inc_snapshot
->
getObservations
()
->
size
();
#endif
// compute satellites positions
// compute satellites positions
if
(
!
inc_snapshot
->
satellitesComputed
())
if
(
!
inc_snapshot
->
satellitesComputed
())
...
@@ -63,7 +65,7 @@ void ProcessorTrackerGnss::preProcess()
...
@@ -63,7 +65,7 @@ void ProcessorTrackerGnss::preProcess()
// Set ECEF-ENU
// Set ECEF-ENU
if
(
!
sensor_gnss_
->
isEnuDefined
()
and
sensor_gnss_
->
isEnuModeAuto
()
and
fix_incoming_
.
success
)
if
(
!
sensor_gnss_
->
isEnuDefined
()
and
sensor_gnss_
->
isEnuModeAuto
()
and
fix_incoming_
.
success
)
{
{
WOLF_
INFO
(
"setting ECEF-ENU: "
,
fix_incoming_
.
pos
.
transpose
());
WOLF_
DEBUG
(
"setting ECEF-ENU: "
,
fix_incoming_
.
pos
.
transpose
());
sensor_gnss_
->
setEcefEnu
(
fix_incoming_
.
pos
,
true
);
sensor_gnss_
->
setEcefEnu
(
fix_incoming_
.
pos
,
true
);
}
}
// Fix ENU-MAP
// Fix ENU-MAP
...
@@ -77,7 +79,7 @@ void ProcessorTrackerGnss::preProcess()
...
@@ -77,7 +79,7 @@ void ProcessorTrackerGnss::preProcess()
WOLF_DEBUG
(
"TS: "
,
incoming_ptr_
->
getTimeStamp
(),
" - Fix solution (ECEF): "
,
fix_incoming_
.
pos
.
transpose
(),
" - Fix solution (GEO): "
,
fix_incoming_
.
lat_lon
.
transpose
());
WOLF_DEBUG
(
"TS: "
,
incoming_ptr_
->
getTimeStamp
(),
" - Fix solution (ECEF): "
,
fix_incoming_
.
pos
.
transpose
(),
" - Fix solution (GEO): "
,
fix_incoming_
.
lat_lon
.
transpose
());
//WOLF_
INFO
("preprocess: RTKLIB excluded observations: ", fix_incoming_.discarded_sats.size());
//WOLF_
DEBUG
("preprocess: RTKLIB excluded observations: ", fix_incoming_.discarded_sats.size());
// filter observations (available ephemeris, constellations and elevation&SNR)
// filter observations (available ephemeris, constellations and elevation&SNR)
inc_snapshot
->
filterObservations
(
fix_incoming_
.
discarded_sats
,
// discarded sats
inc_snapshot
->
filterObservations
(
fix_incoming_
.
discarded_sats
,
// discarded sats
fix_incoming_
.
sat_azel
,
fix_incoming_
.
sat_azel
,
...
@@ -85,7 +87,7 @@ void ProcessorTrackerGnss::preProcess()
...
@@ -85,7 +87,7 @@ void ProcessorTrackerGnss::preProcess()
false
,
// check carrier phase
false
,
// check carrier phase
params_tracker_gnss_
->
gnss_opt
);
params_tracker_gnss_
->
gnss_opt
);
//WOLF_
INFO
("preprocess: filtered observations: ", inc_snapshot->getObservations()->size());
//WOLF_
DEBUG
("preprocess: filtered observations: ", inc_snapshot->getObservations()->size());
// compute corrected Ranges
// compute corrected Ranges
inc_snapshot
->
computeRanges
(
fix_incoming_
.
sat_azel
,
inc_snapshot
->
computeRanges
(
fix_incoming_
.
sat_azel
,
...
@@ -103,7 +105,7 @@ void ProcessorTrackerGnss::preProcess()
...
@@ -103,7 +105,7 @@ void ProcessorTrackerGnss::preProcess()
untracked_incoming_features_
[
feat
->
satNumber
()]
=
feat
;
untracked_incoming_features_
[
feat
->
satNumber
()]
=
feat
;
}
}
WOLF_
INFO
(
"ProcessorTrackerGnss::preProcess()"
,
WOLF_
DEBUG
(
"ProcessorTrackerGnss::preProcess()"
,
"
\n\t
initial observations: "
,
n_initial
,
"
\n\t
initial observations: "
,
n_initial
,
"
\n\t
RTKLIB discarded: "
,
fix_incoming_
.
discarded_sats
.
size
(),
"
\n\t
RTKLIB discarded: "
,
fix_incoming_
.
discarded_sats
.
size
(),
"
\n\t
gnssutils discarded: "
,
n_initial
-
untracked_incoming_features_
.
size
()
-
fix_incoming_
.
discarded_sats
.
size
(),
"
\n\t
gnssutils discarded: "
,
n_initial
-
untracked_incoming_features_
.
size
()
-
fix_incoming_
.
discarded_sats
.
size
(),
...
@@ -118,7 +120,7 @@ unsigned int ProcessorTrackerGnss::trackFeatures(const FeatureBasePtrList& _feat
...
@@ -118,7 +120,7 @@ unsigned int ProcessorTrackerGnss::trackFeatures(const FeatureBasePtrList& _feat
if
(
_features_in
.
empty
())
if
(
_features_in
.
empty
())
return
0
;
return
0
;
//WOLF_
INFO
("tracking " , _features_in.size() , " features...");
//WOLF_
DEBUG
("tracking " , _features_in.size() , " features...");
assert
(
_capture
==
incoming_ptr_
);
assert
(
_capture
==
incoming_ptr_
);
...
@@ -141,14 +143,14 @@ unsigned int ProcessorTrackerGnss::trackFeatures(const FeatureBasePtrList& _feat
...
@@ -141,14 +143,14 @@ unsigned int ProcessorTrackerGnss::trackFeatures(const FeatureBasePtrList& _feat
}
}
}
}
WOLF_
INFO
(
"ProcessorTrackerGnss::trackFeatures: tracked "
,
_features_out
.
size
(),
" (of "
,
_features_in
.
size
(),
")"
);
WOLF_
DEBUG
(
"ProcessorTrackerGnss::trackFeatures: tracked "
,
_features_out
.
size
(),
" (of "
,
_features_in
.
size
(),
")"
);
return
_features_out
.
size
();
return
_features_out
.
size
();
}
}
bool
ProcessorTrackerGnss
::
voteForKeyFrame
()
const
bool
ProcessorTrackerGnss
::
voteForKeyFrame
()
const
{
{
//WOLF_
INFO
("ProcessorTrackerGnss::voteForKeyFrame");
//WOLF_
DEBUG
("ProcessorTrackerGnss::voteForKeyFrame");
// too old origin
// too old origin
if
(
origin_ptr_
==
nullptr
or
(
last_ptr_
->
getTimeStamp
()
-
origin_ptr_
->
getTimeStamp
())
>
params_tracker_gnss_
->
max_time_span
)
if
(
origin_ptr_
==
nullptr
or
(
last_ptr_
->
getTimeStamp
()
-
origin_ptr_
->
getTimeStamp
())
>
params_tracker_gnss_
->
max_time_span
)
...
@@ -165,7 +167,7 @@ bool ProcessorTrackerGnss::voteForKeyFrame() const
...
@@ -165,7 +167,7 @@ bool ProcessorTrackerGnss::voteForKeyFrame() const
if
(
known_features_incoming_
.
size
()
<
params_tracker_feature_
->
min_features_for_keyframe
if
(
known_features_incoming_
.
size
()
<
params_tracker_feature_
->
min_features_for_keyframe
and
not
untracked_last_features_
.
empty
()
)
and
not
untracked_last_features_
.
empty
()
)
{
{
WOLF_
INFO
(
"Vote for KF because of too less known_features_incoming and not empty untracked in last"
);
WOLF_
DEBUG
(
"Vote for KF because of too less known_features_incoming and not empty untracked in last"
);
return
true
;
return
true
;
}
}
...
@@ -195,7 +197,7 @@ unsigned int ProcessorTrackerGnss::detectNewFeatures(const int& _max_new_feature
...
@@ -195,7 +197,7 @@ unsigned int ProcessorTrackerGnss::detectNewFeatures(const int& _max_new_feature
_features_out
.
push_back
(
feat_pair
.
second
);
_features_out
.
push_back
(
feat_pair
.
second
);
WOLF_DEBUG
(
"feature "
,
feat_pair
.
second
->
id
()
,
" detected!"
);
WOLF_DEBUG
(
"feature "
,
feat_pair
.
second
->
id
()
,
" detected!"
);
}
}
WOLF_
INFO
(
_features_out
.
size
()
,
" new features detected!"
);
WOLF_
DEBUG
(
_features_out
.
size
()
,
" new features detected!"
);
return
_features_out
.
size
();
return
_features_out
.
size
();
}
}
...
@@ -253,7 +255,7 @@ void ProcessorTrackerGnss::establishFactors()
...
@@ -253,7 +255,7 @@ void ProcessorTrackerGnss::establishFactors()
// FACTOR per pair of KF (FactorGnssTdcp3d)
// FACTOR per pair of KF (FactorGnssTdcp3d)
if
(
params_tracker_gnss_
->
gnss_opt
.
tdcp
.
batch
)
if
(
params_tracker_gnss_
->
gnss_opt
.
tdcp
.
batch
)
{
{
WOLF_
INFO
(
"TDCP BATCH frame "
,
last_ptr_
->
getFrame
()
->
id
());
WOLF_
DEBUG
(
"TDCP BATCH frame "
,
last_ptr_
->
getFrame
()
->
id
());
for
(
auto
KF_rit
=
getProblem
()
->
getTrajectory
()
->
getFrameList
().
rbegin
();
for
(
auto
KF_rit
=
getProblem
()
->
getTrajectory
()
->
getFrameList
().
rbegin
();
KF_rit
!=
getProblem
()
->
getTrajectory
()
->
getFrameList
().
rend
();
KF_rit
!=
getProblem
()
->
getTrajectory
()
->
getFrameList
().
rend
();
...
@@ -261,7 +263,7 @@ void ProcessorTrackerGnss::establishFactors()
...
@@ -261,7 +263,7 @@ void ProcessorTrackerGnss::establishFactors()
{
{
FrameBasePtr
KF
=
(
*
KF_rit
);
FrameBasePtr
KF
=
(
*
KF_rit
);
WOLF_
INFO
(
"TDCP BATCH ref frame "
,
KF
->
id
());
WOLF_
DEBUG
(
"TDCP BATCH ref frame "
,
KF
->
id
());
// discard non-key frames, last-last pair and frames without CaptureGnss
// discard non-key frames, last-last pair and frames without CaptureGnss
if
(
not
KF
->
isKey
()
or
if
(
not
KF
->
isKey
()
or
...
@@ -275,7 +277,7 @@ void ProcessorTrackerGnss::establishFactors()
...
@@ -275,7 +277,7 @@ void ProcessorTrackerGnss::establishFactors()
// dt
// dt
double
dt
=
last_ptr_
->
getTimeStamp
()
-
ref_cap_gnss
->
getTimeStamp
();
double
dt
=
last_ptr_
->
getTimeStamp
()
-
ref_cap_gnss
->
getTimeStamp
();
WOLF_
INFO
(
"TDCP BATCH dt = "
,
dt
);
WOLF_
DEBUG
(
"TDCP BATCH dt = "
,
dt
);
// discard strange cases
// discard strange cases
if
(
dt
<=
0
)
if
(
dt
<=
0
)
...
@@ -291,7 +293,7 @@ void ProcessorTrackerGnss::establishFactors()
...
@@ -291,7 +293,7 @@ void ProcessorTrackerGnss::establishFactors()
// get common sats from tracking
// get common sats from tracking
auto
matches
=
track_matrix_
.
matches
(
ref_cap_gnss
,
last_cap_gnss
);
auto
matches
=
track_matrix_
.
matches
(
ref_cap_gnss
,
last_cap_gnss
);
WOLF_
INFO
(
"TDCP BATCH matches "
,
matches
.
size
());
WOLF_
DEBUG
(
"TDCP BATCH matches "
,
matches
.
size
());
std
::
set
<
int
>
common_sats
;
std
::
set
<
int
>
common_sats
;
for
(
auto
match
:
matches
)
for
(
auto
match
:
matches
)
{
{
...
@@ -301,7 +303,7 @@ void ProcessorTrackerGnss::establishFactors()
...
@@ -301,7 +303,7 @@ void ProcessorTrackerGnss::establishFactors()
std
::
static_pointer_cast
<
FeatureGnssSatellite
>
(
match
.
second
.
second
)
->
satNumber
());
std
::
static_pointer_cast
<
FeatureGnssSatellite
>
(
match
.
second
.
second
)
->
satNumber
());
common_sats
.
insert
(
std
::
static_pointer_cast
<
FeatureGnssSatellite
>
(
match
.
second
.
first
)
->
satNumber
());
common_sats
.
insert
(
std
::
static_pointer_cast
<
FeatureGnssSatellite
>
(
match
.
second
.
first
)
->
satNumber
());
}
}
WOLF_
INFO
(
"TDCP BATCH common_sats: "
,
common_sats
.
size
());
WOLF_
DEBUG
(
"TDCP BATCH common_sats: "
,
common_sats
.
size
());
for
(
auto
sat
:
common_sats
)
for
(
auto
sat
:
common_sats
)
std
::
cout
<<
sat
<<
" "
;
std
::
cout
<<
sat
<<
" "
;
std
::
cout
<<
std
::
endl
;
std
::
cout
<<
std
::
endl
;
...
@@ -309,7 +311,7 @@ void ProcessorTrackerGnss::establishFactors()
...
@@ -309,7 +311,7 @@ void ProcessorTrackerGnss::establishFactors()
// DEBUG: FIND COMMON SATELLITES OBSERVATIONS
// DEBUG: FIND COMMON SATELLITES OBSERVATIONS
std
::
set
<
int
>
common_sats_debug
=
GnssUtils
::
Observations
::
findCommonObservations
(
*
ref_cap_gnss
->
getSnapshot
()
->
getObservations
(),
std
::
set
<
int
>
common_sats_debug
=
GnssUtils
::
Observations
::
findCommonObservations
(
*
ref_cap_gnss
->
getSnapshot
()
->
getObservations
(),
*
last_cap_gnss
->
getSnapshot
()
->
getObservations
());
*
last_cap_gnss
->
getSnapshot
()
->
getObservations
());
WOLF_
INFO
(
"TDCP BATCH common_sats_debug: "
,
common_sats_debug
.
size
());
WOLF_
DEBUG
(
"TDCP BATCH common_sats_debug: "
,
common_sats_debug
.
size
());
for
(
auto
sat
:
common_sats_debug
)
for
(
auto
sat
:
common_sats_debug
)
std
::
cout
<<
sat
<<
" "
;
std
::
cout
<<
sat
<<
" "
;
std
::
cout
<<
std
::
endl
;
std
::
cout
<<
std
::
endl
;
...
@@ -329,8 +331,8 @@ void ProcessorTrackerGnss::establishFactors()
...
@@ -329,8 +331,8 @@ void ProcessorTrackerGnss::establishFactors()
std
::
set
<
int
>
(),
std
::
set
<
int
>
(),
params_tracker_gnss_
->
tdcp_batch_params
))
params_tracker_gnss_
->
tdcp_batch_params
))
{
{
WOLF_
INFO
(
"TDCP BATCH d = "
,
d
.
transpose
());
WOLF_
DEBUG
(
"TDCP BATCH d = "
,
d
.
transpose
());
WOLF_
INFO
(
"TDCP BATCH cov =
\n
"
,
cov_d
);
WOLF_
DEBUG
(
"TDCP BATCH cov =
\n
"
,
cov_d
);
// EMPLACE FEATURE
// EMPLACE FEATURE
auto
ftr
=
FeatureBase
::
emplace
<
FeatureGnssTdcp
>
(
last_cap_gnss
,
Eigen
::
Vector3d
(
d
.
head
<
3
>
()),
Eigen
::
Matrix3d
(
cov_d
.
topLeftCorner
<
3
,
3
>
()));
auto
ftr
=
FeatureBase
::
emplace
<
FeatureGnssTdcp
>
(
last_cap_gnss
,
Eigen
::
Vector3d
(
d
.
head
<
3
>
()),
Eigen
::
Matrix3d
(
cov_d
.
topLeftCorner
<
3
,
3
>
()));
...
@@ -339,7 +341,9 @@ void ProcessorTrackerGnss::establishFactors()
...
@@ -339,7 +341,9 @@ void ProcessorTrackerGnss::establishFactors()
FactorBase
::
emplace
<
FactorGnssTdcp3d
>
(
ftr
,
ftr
,
KF
,
sensor_gnss_
,
shared_from_this
());
FactorBase
::
emplace
<
FactorGnssTdcp3d
>
(
ftr
,
ftr
,
KF
,
sensor_gnss_
,
shared_from_this
());
}
}
else
else
WOLF_INFO
(
"TDCP BATCH failed"
);
{
WOLF_DEBUG
(
"TDCP BATCH failed"
);
}
}
}
}
}
// FACTOR per SATELLITE (FactorGnssTdcp)
// FACTOR per SATELLITE (FactorGnssTdcp)
...
@@ -399,7 +403,7 @@ void ProcessorTrackerGnss::establishFactors()
...
@@ -399,7 +403,7 @@ void ProcessorTrackerGnss::establishFactors()
params_tracker_gnss_
->
gnss_opt
.
tdcp
.
loss_function
);
params_tracker_gnss_
->
gnss_opt
.
tdcp
.
loss_function
);
new_factors
.
push_back
(
new_fac
);
new_factors
.
push_back
(
new_fac
);
// WOLF_
INFO
( "Factor: track: " , feature_in_last->trackId(),
// WOLF_
DEBUG
( "Factor: track: " , feature_in_last->trackId(),
// " origin: " , feature_in_origin->id() ,
// " origin: " , feature_in_origin->id() ,
// " from last: " , feature_in_last->id() );
// " from last: " , feature_in_last->id() );
}
}
...
@@ -444,7 +448,7 @@ void ProcessorTrackerGnss::removeOutliers(FactorBasePtrList fac_list, CaptureBas
...
@@ -444,7 +448,7 @@ void ProcessorTrackerGnss::removeOutliers(FactorBasePtrList fac_list, CaptureBas
FactorBasePtrList
remove_fac
;
FactorBasePtrList
remove_fac
;
//WOLF_
INFO
( "PR ", getName()," rejectOutlier...");
//WOLF_
DEBUG
( "PR ", getName()," rejectOutlier...");
// PseudoRange states
// PseudoRange states
Eigen
::
Vector3d
x
;
Eigen
::
Vector3d
x
;
...
@@ -586,8 +590,8 @@ void ProcessorTrackerGnss::removeOutliers(FactorBasePtrList fac_list, CaptureBas
...
@@ -586,8 +590,8 @@ void ProcessorTrackerGnss::removeOutliers(FactorBasePtrList fac_list, CaptureBas
// RTKLIB FIX error
// RTKLIB FIX error
//int sat = std::static_pointer_cast<FeatureGnssSatellite>(fac->getFeature())->getSatellite().sat;
//int sat = std::static_pointer_cast<FeatureGnssSatellite>(fac->getFeature())->getSatellite().sat;
//assert(fix_last_.prange_residuals.count(sat) && "sat not used when computing fix!");
//assert(fix_last_.prange_residuals.count(sat) && "sat not used when computing fix!");
//WOLF_
INFO
("FactorGnssPseudoRange error = ", fac->getMeasurementSquareRootInformationUpper().inverse()*residual);
//WOLF_
DEBUG
("FactorGnssPseudoRange error = ", fac->getMeasurementSquareRootInformationUpper().inverse()*residual);
//WOLF_
INFO
("RTKLIB pntpos error = ", fix_last_.prange_residuals.at(sat));
//WOLF_
DEBUG
("RTKLIB pntpos error = ", fix_last_.prange_residuals.at(sat));
// discard if residual too high evaluated at the current estimation
// discard if residual too high evaluated at the current estimation
if
(
std
::
abs
(
residual
)
>
params_tracker_gnss_
->
outlier_residual_th
)
if
(
std
::
abs
(
residual
)
>
params_tracker_gnss_
->
outlier_residual_th
)
...
@@ -621,7 +625,7 @@ void ProcessorTrackerGnss::removeOutliers(FactorBasePtrList fac_list, CaptureBas
...
@@ -621,7 +625,7 @@ void ProcessorTrackerGnss::removeOutliers(FactorBasePtrList fac_list, CaptureBas
// evaluate
// evaluate
fac_tdcp
->
evaluate
(
parameters_tdcp
,
&
residual
,
nullptr
);
fac_tdcp
->
evaluate
(
parameters_tdcp
,
&
residual
,
nullptr
);
//WOLF_
INFO
("FactorGnssTdcp with residual = ", residual);
//WOLF_
DEBUG
("FactorGnssTdcp with residual = ", residual);
// discard if residual too high evaluated at the current estimation
// discard if residual too high evaluated at the current estimation
if
(
std
::
abs
(
residual
)
>
params_tracker_gnss_
->
outlier_residual_th
)
if
(
std
::
abs
(
residual
)
>
params_tracker_gnss_
->
outlier_residual_th
)
...
@@ -647,7 +651,7 @@ void ProcessorTrackerGnss::removeOutliers(FactorBasePtrList fac_list, CaptureBas
...
@@ -647,7 +651,7 @@ void ProcessorTrackerGnss::removeOutliers(FactorBasePtrList fac_list, CaptureBas
//assert(false);
//assert(false);
fac
->
remove
();
fac
->
remove
();
}
}
WOLF_
INFO
(
"ProcessorTrackerGnss::removeOutliers:"
,
WOLF_
DEBUG
(
"ProcessorTrackerGnss::removeOutliers:"
,
"
\n\t
Pseudorange: "
,
outliers_pseudorange_
,
"
\t
( "
,
(
100.0
*
outliers_pseudorange_
)
/
(
outliers_pseudorange_
+
inliers_pseudorange_
),
" %)"
);
"
\n\t
Pseudorange: "
,
outliers_pseudorange_
,
"
\t
( "
,
(
100.0
*
outliers_pseudorange_
)
/
(
outliers_pseudorange_
+
inliers_pseudorange_
),
" %)"
);
if
(
params_tracker_gnss_
->
gnss_opt
.
tdcp
.
enabled
and
params_tracker_gnss_
->
remove_outliers_tdcp
)
if
(
params_tracker_gnss_
->
gnss_opt
.
tdcp
.
enabled
and
params_tracker_gnss_
->
remove_outliers_tdcp
)
std
::
cout
<<
"
\t
TDCP: "
std
::
cout
<<
"
\t
TDCP: "
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment