Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
imagej-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
3
Issues
3
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Elphel
imagej-elphel
Commits
f2cc84fd
Commit
f2cc84fd
authored
Mar 06, 2022
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More debugging of individual scenes and pairs
parent
ee1f0069
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
71 additions
and
164 deletions
+71
-164
Corr2dLMA.java
src/main/java/com/elphel/imagej/tileprocessor/Corr2dLMA.java
+26
-21
Correlation2d.java
...n/java/com/elphel/imagej/tileprocessor/Correlation2d.java
+2
-1
ImageDtt.java
src/main/java/com/elphel/imagej/tileprocessor/ImageDtt.java
+29
-13
ImageDttParameters.java
...a/com/elphel/imagej/tileprocessor/ImageDttParameters.java
+1
-1
OpticalFlow.java
...ain/java/com/elphel/imagej/tileprocessor/OpticalFlow.java
+12
-127
QuadCLTCPU.java
...main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java
+1
-1
No files found.
src/main/java/com/elphel/imagej/tileprocessor/Corr2dLMA.java
View file @
f2cc84fd
...
...
@@ -2614,7 +2614,8 @@ public class Corr2dLMA {
lma_min_min_ac
,
// minimal of A and C coefficients minimum (measures sharpest point)
lma_max_area
,
// maximal half-area (if > 0.0)
lma_str_scale
,
// convert lma-generated strength to match previous ones - scale
lma_str_offset
// convert lma-generated strength to match previous ones - add to result
lma_str_offset
,
// convert lma-generated strength to match previous ones - add to result
false
// boolean dbg_mode
)[
0
];
}
...
...
@@ -2626,11 +2627,12 @@ public class Corr2dLMA {
double
lma_min_strength
,
// minimal composite strength (sqrt(average amp squared over absolute RMS)
double
lma_min_max_ac
,
// minimal of A and C coefficients maximum (measures sharpest point/line)
double
lma_min_min_ac
,
// minimal of A and C coefficients minimum (measures sharpest point)
double
lma_max_area
,
// maximal half-area (if > 0.0)
double
lma_max_area
,
// maximal half-area (if > 0.0)
// 20
double
lma_str_scale
,
// convert lma-generated strength to match previous ones - scale
double
lma_str_offset
// convert lma-generated strength to match previous ones - add to result
double
lma_str_offset
,
// convert lma-generated strength to match previous ones - add to result
boolean
dbg_mode
){
double
[][][]
ds
=
new
double
[
numMax
][
numTiles
][
3
];
double
[][][]
ds
=
new
double
[
numMax
][
numTiles
][
dbg_mode
?
6
:
3
];
double
[]
rms
=
getRmsTile
();
for
(
int
nmax
=
0
;
nmax
<
numMax
;
nmax
++)
{
double
[][]
maxmin_amp
=
getMaxMinAmpTile
(
nmax
);
// nmax
...
...
@@ -2654,8 +2656,6 @@ public class Corr2dLMA {
lmas_min_amp
=
lmas_min_amp_bg
;
break
;
}
}
}
if
((
maxmin_amp
[
tile
][
1
]/
maxmin_amp
[
tile
][
0
])
<
lmas_min_amp
)
{
...
...
@@ -2663,24 +2663,24 @@ public class Corr2dLMA {
}
double
avg
=
0.50
*(
maxmin_amp
[
tile
][
0
]+
maxmin_amp
[
tile
][
1
]);
// max_min[1] can be negative - filter it out?
double
rrms
=
rms
[
tile
]/
avg
;
if
(((
lma_max_rel_rms
>
0.0
)
&&
(
rrms
>
lma_max_rel_rms
))
||
(
Math
.
max
(
abc
[
tile
][
0
],
abc
[
tile
][
2
])
<
lma_min_max_ac
)
// || (Math.min(abc[tile][0], abc[tile][2]) < lma_min_min_ac)
)
{
if
((
lma_max_rel_rms
>
0.00
)
&&
(
rrms
>
lma_max_rel_rms
))
{
continue
;
}
if
(
lma_max_area
>
0
)
{
if
((
abc
[
tile
][
0
]
>
0.0
)
&&
(
abc
[
tile
][
2
]
>
0.0
))
{
// double area_old = 1.0/abc[tile][0] + 1.0/abc[tile][2]; // area of a maximum
double
area
=
1.0
/
Math
.
sqrt
(
abc
[
tile
][
0
]
*
abc
[
tile
][
2
]);
if
(
area
>
lma_max_area
)
{
continue
;
// too wide maximum
}
}
else
{
continue
;
// not a maximum
if
(
Math
.
max
(
abc
[
tile
][
0
],
abc
[
tile
][
2
])
<
lma_min_max_ac
)
{
continue
;
}
if
((
lma_min_min_ac
>
0.0
)
&&
((
abc
[
tile
][
0
]
<
lma_min_min_ac
)
||
(
abc
[
tile
][
2
]
<
lma_min_min_ac
))){
continue
;
// too large a or c (not sharp along at least one direction)
}
double
area
=
0.0
;
if
((
abc
[
tile
][
0
]
>
0.0
)
&&
(
abc
[
tile
][
2
]
>
0.0
))
{
// double area_old = 1.0/abc[tile][0] + 1.0/abc[tile][2]; // area of a maximum
area
=
1.0
/
Math
.
sqrt
(
abc
[
tile
][
0
]
*
abc
[
tile
][
2
]);
if
((
lma_max_area
>
0
)
&&
(
area
>
lma_max_area
))
{
continue
;
// too wide maximum
}
}
else
{
continue
;
// not a maximum
}
double
strength
=
Math
.
sqrt
(
avg
/
rrms
);
// double disparity = -all_pars[DISP_INDEX + offs];
...
...
@@ -2695,6 +2695,11 @@ public class Corr2dLMA {
ds
[
nmax
][
tile
][
0
]
=
disparity
;
ds
[
nmax
][
tile
][
1
]
=
(
strength
*
lma_str_scale
)
+
lma_str_offset
;
ds
[
nmax
][
tile
][
2
]
=
strength
;
// as is
if
(
ds
[
nmax
][
tile
].
length
>
3
)
{
ds
[
nmax
][
tile
][
3
]
=
area
;
ds
[
nmax
][
tile
][
4
]
=
ac
;
ds
[
nmax
][
tile
][
5
]
=
Math
.
min
(
abc
[
tile
][
0
],
abc
[
tile
][
2
]);
}
}
}
return
ds
;
...
...
src/main/java/com/elphel/imagej/tileprocessor/Correlation2d.java
View file @
f2cc84fd
...
...
@@ -4842,7 +4842,8 @@ public class Correlation2d {
imgdtt_params
.
lmas_min_min_ac
,
// minimal of A and C coefficients minimum (measures sharpest point)
imgdtt_params
.
lmas_max_area
,
//double lma_max_area, // maximal half-area (if > 0.0)
imgdtt_params
.
lma_str_scale
,
// convert lma-generated strength to match previous ones - scale
imgdtt_params
.
lma_str_offset
// convert lma-generated strength to match previous ones - add to result
imgdtt_params
.
lma_str_offset
,
// convert lma-generated strength to match previous ones - add to result
false
// boolean dbg_mode
);
for
(
int
nmax
=
00
;
nmax
<
dispStrs
.
length
;
nmax
++)
if
(
dispStrs
[
nmax
][
0
][
1
]
<=
0
)
{
lmaSuccess
=
false
;
...
...
src/main/java/com/elphel/imagej/tileprocessor/ImageDtt.java
View file @
f2cc84fd
...
...
@@ -2681,11 +2681,12 @@ public class ImageDtt extends ImageDttCPU {
(
debugTile0
?
1
:
-
2
),
// int debug_level,
tileX
,
// int tileX, // just for debug output
tileY
);
if
(
debugTile1
)
{
if
(
debugTile1
&&
(
lma_dual
!=
null
))
{
// addad (lma_dual != null)
System
.
out
.
println
(
"clt_process_tl_correlations() corrLMA2DualMax() done, lma_dual="
+
((
lma_dual
==
null
)?
"null"
:
" not null"
));
}
if
(
lma_dual
!=
null
)
{
boolean
dbg_dispStrs
=
(
debug_lma
!=
null
);
double
[][][]
dispStrs
=
lma_dual
.
lmaDisparityStrengths
(
//TODO: add parameter to filter out negative minimums ?
imgdtt_params
.
lmas_min_amp
,
// minimal ratio of minimal pair correlation amplitude to maximal pair correlation amplitude
imgdtt_params
.
lmas_min_amp_bg
,
// minimal ratio of minimal pair correlation amplitude to maximal pair correlation amplitude
...
...
@@ -2695,13 +2696,18 @@ public class ImageDtt extends ImageDttCPU {
imgdtt_params
.
lmas_min_min_ac
,
// minimal of A and C coefficients minimum (measures sharpest point)
imgdtt_params
.
lmas_max_area
,
//double lma_max_area, // maximal half-area (if > 0.0)
imgdtt_params
.
lma_str_scale
,
// convert lma-generated strength to match previous ones - scale
imgdtt_params
.
lma_str_offset
// convert lma-generated strength to match previous ones - add to result
imgdtt_params
.
lma_str_offset
,
// convert lma-generated strength to match previous ones - add to result
dbg_dispStrs
// false // boolean dbg_mode
);
disp_str_lma
=
new
double
[
dispStrs
.
length
][];
// order matching input ones
for
(
int
nmax
=
0
;
nmax
<
dispStrs
.
length
;
nmax
++)
{
if
((
dispStrs
[
nmax
]
!=
null
)
&&
(
dispStrs
[
nmax
].
length
>
0
))
{
disp_str_lma
[
nmax
]
=
dispStrs
[
nmax
][
0
];
if
(
dbg_dispStrs
)
{
for
(
int
i
=
0
;
i
<
dispStrs
[
nmax
][
0
].
length
;
i
++)
{
debug_lma
[
i
][
nTile
]
=
dispStrs
[
nmax
][
0
][
i
];
}
}
}
}
if
(
imgdtt_params
.
bimax_post_LMA
&&
(
sel_max
>=
0
))
{
...
...
@@ -2866,18 +2872,28 @@ public class ImageDtt extends ImageDttCPU {
}
startAndJoin
(
threads
);
if
(
debug_lma
!=
null
)
{
(
new
ShowDoubleFloatArrays
()).
showArrays
(
debug_lma
,
tilesX
,
tilesY
,
true
,
"lma_debug"
,
new
String
[]
{
"disp_samples"
,
"num_cnvx_samples"
,
"num_comb_samples"
,
"num_lmas"
,
"num_iters"
,
"rms"
}
);
if
(
imgdtt_params
.
bimax_dual_LMA
)
{
(
new
ShowDoubleFloatArrays
()).
showArrays
(
debug_lma
,
tilesX
,
tilesY
,
true
,
"lma_debug_dual_LMA"
,
new
String
[]
{
"disparity"
,
"strength_mod"
,
"strength"
,
"area"
,
"ac"
,
"min(a,c)"
}
);
}
else
{
(
new
ShowDoubleFloatArrays
()).
showArrays
(
debug_lma
,
tilesX
,
tilesY
,
true
,
"lma_debug"
,
new
String
[]
{
"disp_samples"
,
"num_cnvx_samples"
,
"num_comb_samples"
,
"num_lmas"
,
"num_iters"
,
"rms"
}
);
}
}
}
return
;
}
...
...
src/main/java/com/elphel/imagej/tileprocessor/ImageDttParameters.java
View file @
f2cc84fd
...
...
@@ -220,7 +220,7 @@ public class ImageDttParameters {
public
double
lmas_min_strength
=
0.7
;
// LWIR16: 0.4 minimal composite strength (sqrt(average amp squared over absolute RMS)
public
double
lmas_min_ac
=
0.02
;
// LWIR16: 0.01 minimal of a and C coefficients maximum (measures sharpest point/line)
public
double
lmas_min_min_ac
=
0.007
;
// LWIR16: 0.007 minimal of a and C coefficients minimum (measures sharpest point)
public
double
lmas_max_area
=
0.0
;
// LWIR16: 0.0 maximal half-area (if > 0.0)
public
double
lmas_max_area
=
2
0.0
;
// LWIR16: 0.0 maximal half-area (if > 0.0)
// public boolean lma_gaussian = false; // model correlation maximum as a Gaussian (false - as a parabola)
public
int
lma_gaussian
=
0
;
// 0 - parabola, 1 - Gaussian, 2 - limited parabola, 3 - limited squared parabola
...
...
src/main/java/com/elphel/imagej/tileprocessor/OpticalFlow.java
View file @
f2cc84fd
...
...
@@ -3236,7 +3236,7 @@ public class OpticalFlow {
reference_QuadClt
.
getImageName
()
+
"/"
+
scene_QuadClt
.
getImageName
()+
" Done."
);
}
}
for
(
int
i
=
0
;
i
<
scenes
.
length
;
i
++)
{
for
(
int
i
=
0
0
;
i
<
scenes
.
length
;
i
++)
{
int
i_prev
=
i
-
((
i
>
0
)
?
1
:
0
);
int
i_next
=
i
+
((
i
<
(
scenes
.
length
-
1
))
?
1
:
0
);
double
dt
=
scenes
[
i_next
].
getTimeStamp
()
-
scenes
[
i_prev
].
getTimeStamp
();
...
...
@@ -3287,6 +3287,14 @@ public class OpticalFlow {
double
[]
dbg_img
=
new
double
[
dbg_w
*
dbg_h
];
for
(
int
dh
=
0
;
dh
<
dbg_h
;
dh
++)
{
for
(
int
dw
=
0
;
dw
<
dbg_w
;
dw
++)
{
if
(
ers_xyzatr
[
dw
]
==
null
)
{
System
.
out
.
println
(
"adjustPairsDualPass(): ers_xyzatr["
+
dw
+
"] == null"
);
continue
;
}
if
(
ers_xyzatr
[
dw
][
dh
/
3
]
==
null
)
{
System
.
out
.
println
(
"adjustPairsDualPass(): ers_xyzatr["
+
dw
+
"]["
+(
dh
/
3
)+
"] == null"
);
continue
;
}
dbg_img
[
dh
*
dbg_w
+
dw
]
=
ers_xyzatr
[
dw
][
dh
/
3
][
dh
%
3
];
}
}
...
...
@@ -3373,135 +3381,12 @@ public class OpticalFlow {
for
(
int
i
=
1
;
i
<
scenes
.
length
;
i
++)
{
QuadCLT
reference_QuadClt
=
scenes
[
i
];
/*
QuadCLT scene_QuadClt = scenes[i - 1];
ErsCorrection ers_scene = scene_QuadClt.getErsCorrection();
reference_QuadClt.getErsCorrection().addScene(scene_QuadClt.getImageName(),
scenes_xyzatr1[i][0],
scenes_xyzatr1[i][1],
ers_scene.getErsXYZ_dt(),
ers_scene.getErsATR_dt()
);
*/
reference_QuadClt
.
saveInterProperties
(
// save properties for interscene processing (extrinsics, ers, ...)
null
,
// String path, // full name with extension or w/o path to use x3d directory
debug_level
+
1
);
}
}
/*
public void adjustSeries(
CLTParameters clt_parameters,
double k_prev,
QuadCLT [] scenes, // ordered by increasing timestamps
int debug_level
)
{
double [][][] scenes_xyzatr = new double [scenes.length][][]; // previous scene relative to the next one
// double [][][] ers_xyzatr = new double [scenes.length][][]; // previous scene relative to the next one
QuadCLT reference_QuadClt = scenes[scenes.length-1]; // last acquired
ErsCorrection ers_reference = reference_QuadClt.getErsCorrection();
// modify LMA parameters to freeze reference ERS, remove pull on scene ERS
boolean[] param_select2 = clt_parameters.ilp.ilma_lma_select.clone(); // final boolean[] param_select,
double [] param_regweights2 = clt_parameters.ilp.ilma_regularization_weights; // final double [] param_regweights,
boolean delete_scene_asap = (debug_level < 10); // to save memory
// freeze reference ERS, free scene ERS
for (int j = 0; j <3; j++) {
param_select2[ErsCorrection.DP_DVX + j] = false;
param_select2[ErsCorrection.DP_DVAZ + j] = false;
param_regweights2[ErsCorrection.DP_DSVX + j] = 0.0+0;
param_regweights2[ErsCorrection.DP_DSVAZ + j] = 0.0;
}
for (int i = scenes.length - 3; i >=0 ; i--) {
QuadCLT scene_QuadClt = scenes[i];
String last_known_ts = scenes[i+1].getImageName(); // it should be present in the reference scene scenes
String scene_ts = scenes[i].getImageName(); // it should be present in the scenes[i+1] scenes
ErsCorrection ers_scene_last_known = scenes[i+1].getErsCorrection();
ErsCorrection ers_scene = scene_QuadClt.getErsCorrection();
double [] last_known_xyz = ers_reference.getSceneXYZ(last_known_ts);
double [] last_known_atr = ers_reference.getSceneATR(last_known_ts);
double [] new_from_last_xyz = ers_scene_last_known.getSceneXYZ(scene_ts);
double [] new_from_last_atr = ers_scene_last_known.getSceneATR(scene_ts);
// combine two rotations and two translations
System.out.println("Processing scene "+i+": "+scene_QuadClt.getImageName());
double [][] combo_XYZATR = ErsCorrection.combineXYZATR(
last_known_xyz, // double [] reference_xyz,
last_known_atr, // double [] reference_atr, // null?
new_from_last_xyz, // double [] scene_xyz,
new_from_last_atr); // double [] scene_atr)
// before adjusting - save original ERS, restart afterwards
double [] ers_scene_original_xyz_dt = ers_scene.getErsXYZ_dt();
double [] ers_scene_original_atr_dt = ers_scene.getErsATR_dt();
// ers should be correct for both
scenes_xyzatr[i] = adjustPairsLMA(
clt_parameters, // CLTParameters clt_parameters,
reference_QuadClt, // QuadCLT reference_QuadCLT,
scene_QuadClt, // QuadCLT scene_QuadCLT,
combo_XYZATR[0], // xyz
combo_XYZATR[1], // atr
param_select2, // final boolean[] param_select,
param_regweights2, // final double [] param_regweights,
debug_level); // int debug_level)
ers_reference.addScene(scene_QuadClt.getImageName(),
scenes_xyzatr[i][0],
scenes_xyzatr[i][1],
ers_scene.getErsXYZ_dt(),
ers_scene.getErsATR_dt()
);
// restore original ers data
ers_scene.setErsDt(
ers_scene_original_xyz_dt, // double [] ers_xyz_dt,
ers_scene_original_atr_dt); // double [] ers_atr_dt)(ers_scene_original_xyz_dt);
ers_scene.setupERS();
if (debug_level > -1) {
System.out.println("Pass multi scene "+i+" (of "+ scenes.length+") "+
reference_QuadClt.getImageName() + "/" + scene_QuadClt.getImageName()+" Done.");
}
if (delete_scene_asap) {
scenes[i+1] = null;
}
// Runtime.getRuntime().gc();
// System.out.println("Scene "+i+", --- Free memory="+Runtime.getRuntime().freeMemory()+" (of "+Runtime.getRuntime().totalMemory()+")");
}
reference_QuadClt.saveInterProperties( // save properties for interscene processing (extrinsics, ers, ...)
null, // String path, // full name with extension or w/o path to use x3d directory
debug_level+1);
if (!delete_scene_asap && (debug_level > -1)) {
System.out.println("adjustSeries(): preparing image set...");
int nscenes = scenes.length;
int indx_ref = nscenes - 1;
double [][][] all_scenes_xyzatr = new double [scenes.length][][]; // includes reference (last)
double [][][] all_scenes_ers_dt = new double [scenes.length][][]; // includes reference (last)
all_scenes_xyzatr[indx_ref] = new double [][] {ZERO3,ZERO3};
all_scenes_ers_dt[indx_ref] = new double [][] {
ers_reference.getErsXYZ_dt(),
ers_reference.getErsATR_dt()};
for (int i = 0; i < nscenes; i++) if (i != indx_ref) {
String ts = scenes[i].getImageName();
all_scenes_xyzatr[i] = new double[][] {ers_reference.getSceneXYZ(ts), ers_reference.getSceneATR(ts)};
all_scenes_ers_dt[i] = new double[][] {ers_reference.getSceneErsXYZ_dt(ts), ers_reference.getSceneErsATR_dt(ts)};
}
compareRefSceneTiles(
"" , // String suffix,
false, // boolean blur_reference,
all_scenes_xyzatr, // double [][][] scene_xyzatr, // does not include reference
all_scenes_ers_dt, // double [][][] scene_ers_dt, // does not include reference
scenes, // QuadCLT [] scenes,
8); // int iscale) // 8
}
if (debug_level > -1) {
System.out.println("adjustSeries() Done.");
}
}
*/
public
void
adjustSeries
(
CLTParameters
clt_parameters
,
double
k_prev
,
...
...
@@ -3910,7 +3795,7 @@ Maybe later - add same weight. Or use CM instead, even for LMA?
double
[]
weights
=
new
double
[(
int
)
Math
.
floor
(
half_run_range
)+
1
];
weights
[
0
]
=
1
;
for
(
int
i
=
1
;
i
<
weights
.
length
;
i
++)
{
weights
[
i
]
=
0.5
*
(
Math
.
cos
(
i
*
Math
.
PI
/
half_run_range
));
weights
[
i
]
=
0.5
*
(
Math
.
cos
(
i
*
Math
.
PI
/
half_run_range
)
+
1.0
);
}
double
[][][]
ers_xyzatr
=
new
double
[
ers_xyzatr_in
.
length
][][];
for
(
int
nscene
=
0
;
nscene
<
ers_xyzatr_in
.
length
;
nscene
++)
{
...
...
@@ -3918,12 +3803,12 @@ Maybe later - add same weight. Or use CM instead, even for LMA?
double
[][]
swd
=
new
double
[
2
][
3
];
for
(
int
ds
=
-
weights
.
length
+
1
;
ds
<
weights
.
length
;
ds
++)
{
int
ns
=
nscene
+
ds
;
if
((
ns
>=
0
)
&&
(
ns
<
ers_xyzatr
.
length
)
&&
(
ers_xyzatr
[
ns
]
!=
null
))
{
if
((
ns
>=
0
)
&&
(
ns
<
ers_xyzatr
_in
.
length
)
&&
(
ers_xyzatr_in
[
ns
]
!=
null
))
{
double
w
=
(
ds
>=
0
)
?
weights
[
ds
]
:
weights
[-
ds
];
sw
+=
w
;
for
(
int
m
=
0
;
m
<
swd
.
length
;
m
++)
{
for
(
int
d
=
0
;
d
<
swd
[
m
].
length
;
d
++)
{
swd
[
m
][
d
]
+=
w
*
ers_xyzatr
[
ns
][
m
][
d
];
swd
[
m
][
d
]
+=
w
*
ers_xyzatr
_in
[
ns
][
m
][
d
];
}
}
}
...
...
src/main/java/com/elphel/imagej/tileprocessor/QuadCLTCPU.java
View file @
f2cc84fd
...
...
@@ -12805,7 +12805,7 @@ public class QuadCLTCPU {
if
(
clt_parameters
.
z_corr_map
.
containsKey
(
image_name
)){
// not used in lwir
z_correction
+=
clt_parameters
.
z_corr_map
.
get
(
image_name
);
}
final
double
disparity_corr
=
(
z_correction
==
0
)
?
0.0
:
geometryCorrection
.
getDisparityFromZ
(
1.0
/
z_correction
);
final
double
disparity_corr
=
(
z_correction
==
0
)
?
0.0
0
:
geometryCorrection
.
getDisparityFromZ
(
1.0
/
z_correction
);
int
mcorr_sel
=
save_corr
?
Correlation2d
.
corrSelEncode
(
clt_parameters
.
img_dtt
,
getNumSensors
())
:
0
;
TpTask
[]
tp_tasks
=
GpuQuad
.
setTasks
(
// null on geometryCorrection
num_sensors
,
// final int num_cams,
...
...
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