Commit f6e85676 authored by Andrey Filippov's avatar Andrey Filippov

bug fixes

parent 15b80649
This diff is collapsed.
...@@ -2140,6 +2140,7 @@ public class EyesisCorrectionParameters { ...@@ -2140,6 +2140,7 @@ public class EyesisCorrectionParameters {
public boolean avg_cluster_disp = false; // Weight-average disparity for the whole cluster public boolean avg_cluster_disp = false; // Weight-average disparity for the whole cluster
public double maxDispTriangle = 0.2; // Maximal relative disparity difference in a triangle face public double maxDispTriangle = 0.2; // Maximal relative disparity difference in a triangle face
public double infinityDistance = 10000; // Distance to generate backdrop (0 - use regular backdrop) public double infinityDistance = 10000; // Distance to generate backdrop (0 - use regular backdrop)
public int min_bgnd_tiles = 10; // Minimal number of background tiles to generate background
public boolean shUseFlaps = true; // Split into shells with flaps public boolean shUseFlaps = true; // Split into shells with flaps
public boolean shAggrFade = true; // Aggressive fade alpha (whole boundary) public boolean shAggrFade = true; // Aggressive fade alpha (whole boundary)
public int shMinArea = 1; // Minimal shell area (not counting flaps public int shMinArea = 1; // Minimal shell area (not counting flaps
...@@ -2758,6 +2759,7 @@ public class EyesisCorrectionParameters { ...@@ -2758,6 +2759,7 @@ public class EyesisCorrectionParameters {
properties.setProperty(prefix+"avg_cluster_disp", this.avg_cluster_disp+""); properties.setProperty(prefix+"avg_cluster_disp", this.avg_cluster_disp+"");
properties.setProperty(prefix+"maxDispTriangle", this.maxDispTriangle +""); properties.setProperty(prefix+"maxDispTriangle", this.maxDispTriangle +"");
properties.setProperty(prefix+"infinityDistance", this.infinityDistance +""); properties.setProperty(prefix+"infinityDistance", this.infinityDistance +"");
properties.setProperty(prefix+"min_bgnd_tiles", this.min_bgnd_tiles+"");
properties.setProperty(prefix+"shUseFlaps", this.shUseFlaps+""); properties.setProperty(prefix+"shUseFlaps", this.shUseFlaps+"");
properties.setProperty(prefix+"shAggrFade", this.shAggrFade+""); properties.setProperty(prefix+"shAggrFade", this.shAggrFade+"");
properties.setProperty(prefix+"shMinArea", this.shMinArea+""); properties.setProperty(prefix+"shMinArea", this.shMinArea+"");
...@@ -3335,6 +3337,7 @@ public class EyesisCorrectionParameters { ...@@ -3335,6 +3337,7 @@ public class EyesisCorrectionParameters {
if (properties.getProperty(prefix+"avg_cluster_disp")!=null) this.avg_cluster_disp=Boolean.parseBoolean(properties.getProperty(prefix+"avg_cluster_disp")); if (properties.getProperty(prefix+"avg_cluster_disp")!=null) this.avg_cluster_disp=Boolean.parseBoolean(properties.getProperty(prefix+"avg_cluster_disp"));
if (properties.getProperty(prefix+"maxDispTriangle")!=null) this.maxDispTriangle=Double.parseDouble(properties.getProperty(prefix+"maxDispTriangle")); if (properties.getProperty(prefix+"maxDispTriangle")!=null) this.maxDispTriangle=Double.parseDouble(properties.getProperty(prefix+"maxDispTriangle"));
if (properties.getProperty(prefix+"infinityDistance")!=null) this.infinityDistance=Double.parseDouble(properties.getProperty(prefix+"infinityDistance")); if (properties.getProperty(prefix+"infinityDistance")!=null) this.infinityDistance=Double.parseDouble(properties.getProperty(prefix+"infinityDistance"));
if (properties.getProperty(prefix+"min_bgnd_tiles")!=null) this.min_bgnd_tiles=Integer.parseInt(properties.getProperty(prefix+"min_bgnd_tiles"));
if (properties.getProperty(prefix+"shUseFlaps")!=null) this.shUseFlaps=Boolean.parseBoolean(properties.getProperty(prefix+"shUseFlaps")); if (properties.getProperty(prefix+"shUseFlaps")!=null) this.shUseFlaps=Boolean.parseBoolean(properties.getProperty(prefix+"shUseFlaps"));
if (properties.getProperty(prefix+"shAggrFade")!=null) this.shAggrFade=Boolean.parseBoolean(properties.getProperty(prefix+"shAggrFade")); if (properties.getProperty(prefix+"shAggrFade")!=null) this.shAggrFade=Boolean.parseBoolean(properties.getProperty(prefix+"shAggrFade"));
if (properties.getProperty(prefix+"shMinArea")!=null) this.shMinArea=Integer.parseInt(properties.getProperty(prefix+"shMinArea")); if (properties.getProperty(prefix+"shMinArea")!=null) this.shMinArea=Integer.parseInt(properties.getProperty(prefix+"shMinArea"));
...@@ -3809,7 +3812,7 @@ public class EyesisCorrectionParameters { ...@@ -3809,7 +3812,7 @@ public class EyesisCorrectionParameters {
gd.addNumericField("X 3", this.fine_corr_x_3, 3); gd.addNumericField("X 3", this.fine_corr_x_3, 3);
gd.addNumericField("Y 4", this.fine_corr_y_3, 3); gd.addNumericField("Y 4", this.fine_corr_y_3, 3);
gd.addNumericField("Y 4", this.fcorr_radius, 3); gd.addNumericField("fcorr_radius", this.fcorr_radius, 3);
gd.addNumericField("Do not try to correct outside this fraction of width/hight", this.fcorr_min_strength,3); gd.addNumericField("Do not try to correct outside this fraction of width/hight", this.fcorr_min_strength,3);
gd.addNumericField("Consider only tiles with absolute residual disparity lower than", this.fcorr_disp_diff, 3); gd.addNumericField("Consider only tiles with absolute residual disparity lower than", this.fcorr_disp_diff, 3);
gd.addCheckbox ("Use quadratic polynomial for fine correction (false - only linear)", this.fcorr_quadratic); gd.addCheckbox ("Use quadratic polynomial for fine correction (false - only linear)", this.fcorr_quadratic);
...@@ -3940,6 +3943,7 @@ public class EyesisCorrectionParameters { ...@@ -3940,6 +3943,7 @@ public class EyesisCorrectionParameters {
gd.addCheckbox ("Weight-average disparity for the whole cluster ", this.avg_cluster_disp); gd.addCheckbox ("Weight-average disparity for the whole cluster ", this.avg_cluster_disp);
gd.addNumericField("Maximal disparity difference in a triangle face to show", this.maxDispTriangle, 6); gd.addNumericField("Maximal disparity difference in a triangle face to show", this.maxDispTriangle, 6);
gd.addNumericField("Distance to generate backdrop (0 - use regular backdrop)", this.infinityDistance, 8); gd.addNumericField("Distance to generate backdrop (0 - use regular backdrop)", this.infinityDistance, 8);
gd.addNumericField(" Minimal number of background tiles to generate background", this.min_bgnd_tiles, 0);
gd.addCheckbox ("Split into shells with flaps", this.shUseFlaps); gd.addCheckbox ("Split into shells with flaps", this.shUseFlaps);
gd.addCheckbox ("Aggressive fade alpha (whole boundary)", this.shAggrFade); gd.addCheckbox ("Aggressive fade alpha (whole boundary)", this.shAggrFade);
...@@ -4549,6 +4553,7 @@ public class EyesisCorrectionParameters { ...@@ -4549,6 +4553,7 @@ public class EyesisCorrectionParameters {
this.avg_cluster_disp= gd.getNextBoolean(); this.avg_cluster_disp= gd.getNextBoolean();
this.maxDispTriangle= gd.getNextNumber(); this.maxDispTriangle= gd.getNextNumber();
this.infinityDistance= gd.getNextNumber(); this.infinityDistance= gd.getNextNumber();
this.min_bgnd_tiles= (int) gd.getNextNumber();
this.shUseFlaps= gd.getNextBoolean(); this.shUseFlaps= gd.getNextBoolean();
this.shAggrFade= gd.getNextBoolean(); this.shAggrFade= gd.getNextBoolean();
this.shMinArea= (int) gd.getNextNumber(); this.shMinArea= (int) gd.getNextNumber();
......
...@@ -501,7 +501,7 @@ private Panel panel1, ...@@ -501,7 +501,7 @@ private Panel panel1,
addButton("CLT process files", panelClt1, color_process); addButton("CLT process files", panelClt1, color_process);
addButton("CLT process sets", panelClt1, color_process); addButton("CLT process sets", panelClt1, color_process);
addButton("CLT process quads", panelClt1, color_process); addButton("CLT process quads", panelClt1, color_process);
// addButton("CLT process corr", panelClt1, color_conf_process); // addButton("CLT 4 images", panelClt1, color_conf_process);
// addButton("CLT disparity scan", panelClt1, color_conf_process); // addButton("CLT disparity scan", panelClt1, color_conf_process);
// addButton("CLT reset fine corr", panelClt1, color_stop); // addButton("CLT reset fine corr", panelClt1, color_stop);
// addButton("CLT show fine corr", panelClt1, color_configure); // addButton("CLT show fine corr", panelClt1, color_configure);
...@@ -528,7 +528,7 @@ private Panel panel1, ...@@ -528,7 +528,7 @@ private Panel panel1,
// addButton("CLT process files", panelClt2, color_process); // addButton("CLT process files", panelClt2, color_process);
// addButton("CLT process sets", panelClt2, color_process); // addButton("CLT process sets", panelClt2, color_process);
// addButton("CLT process quads", panelClt2, color_process); // addButton("CLT process quads", panelClt2, color_process);
addButton("CLT process corr", panelClt2, color_conf_process); addButton("CLT 4 images", panelClt2, color_conf_process);
addButton("CLT disparity scan", panelClt2, color_conf_process); addButton("CLT disparity scan", panelClt2, color_conf_process);
addButton("CLT reset fine corr", panelClt2, color_stop); addButton("CLT reset fine corr", panelClt2, color_stop);
addButton("CLT reset extrinsic corr", panelClt2, color_stop); addButton("CLT reset extrinsic corr", panelClt2, color_stop);
...@@ -4475,7 +4475,7 @@ private Panel panel1, ...@@ -4475,7 +4475,7 @@ private Panel panel1,
return; return;
} else if (label.equals("CLT process corr") || label.equals("CLT apply fine corr") || label.equals("CLT infinity corr")) { } else if (label.equals("CLT 4 images") || label.equals("CLT apply fine corr") || label.equals("CLT infinity corr")) {
boolean apply_corr = label.equals("CLT apply fine corr"); boolean apply_corr = label.equals("CLT apply fine corr");
boolean infinity_corr = label.equals("CLT infinity corr"); boolean infinity_corr = label.equals("CLT infinity corr");
DEBUG_LEVEL=MASTER_DEBUG_LEVEL; DEBUG_LEVEL=MASTER_DEBUG_LEVEL;
......
...@@ -5166,7 +5166,7 @@ public class QuadCLT { ...@@ -5166,7 +5166,7 @@ public class QuadCLT {
// } // }
bgnd_data.texture = imp_bgnd.getTitle()+ (clt_parameters.black_back? ".jpeg" : ".png"); bgnd_data.texture = (imp_bgnd == null)? null: ( imp_bgnd.getTitle()+ (clt_parameters.black_back? ".jpeg" : ".png"));
// create x3d file // create x3d file
X3dOutput x3dOutput = new X3dOutput( X3dOutput x3dOutput = new X3dOutput(
...@@ -5176,10 +5176,11 @@ public class QuadCLT { ...@@ -5176,10 +5176,11 @@ public class QuadCLT {
tp.clt_3d_passes); tp.clt_3d_passes);
x3dOutput.generateBackground(clt_parameters.infinityDistance <= 0.0); // needs just first (background) scan x3dOutput.generateBackground(clt_parameters.infinityDistance <= 0.0); // needs just first (background) scan
/*
String x3d_path= correctionsParameters.selectX3dDirectory( String x3d_path= correctionsParameters.selectX3dDirectory(
true, // smart, true, // smart,
true); //newAllowed, // save true); //newAllowed, // save
*/
// refine first measurement // refine first measurement
int bg_pass = tp.clt_3d_passes.size() - 1; // 0 int bg_pass = tp.clt_3d_passes.size() - 1; // 0
int refine_pass = tp.clt_3d_passes.size(); // 1 int refine_pass = tp.clt_3d_passes.size(); // 1
...@@ -6182,14 +6183,6 @@ public class QuadCLT { ...@@ -6182,14 +6183,6 @@ public class QuadCLT {
tp.clt_3d_passes.add(latest_scan); // put it back tp.clt_3d_passes.add(latest_scan); // put it back
} }
int next_pass = tp.clt_3d_passes.size(); // int next_pass = tp.clt_3d_passes.size(); //
// tp.showScan(
// tp.clt_3d_passes.get(0), // CLTPass3d scan,
// "bg_scan"); //String title)
// tp.showScan(
// tp.clt_3d_passes.get(next_pass-1), // CLTPass3d scan,
// "after_pass2-"+(next_pass-1)); //String title)
// tp.thirdPassSetup( // prepare tile tasks for the second pass based on the previous one(s)
tp.thirdPassSetupSurf( // prepare tile tasks for the second pass based on the previous one(s) // needs last scan tp.thirdPassSetupSurf( // prepare tile tasks for the second pass based on the previous one(s) // needs last scan
clt_parameters, clt_parameters,
clt_parameters.bgnd_range, // double disparity_far, clt_parameters.bgnd_range, // double disparity_far,
...@@ -6233,31 +6226,30 @@ public class QuadCLT { ...@@ -6233,31 +6226,30 @@ public class QuadCLT {
x3dOutput.generateBackground(clt_parameters.infinityDistance <= 0.0); // needs just first (background) scan x3dOutput.generateBackground(clt_parameters.infinityDistance <= 0.0); // needs just first (background) scan
} }
int bgndIndex = 0; // it already exists?
CLTPass3d bgndScan = tp.clt_3d_passes.get(bgndIndex);
// boolean [] bgnd_sel = bgndScan.getSelected().clone();
// int num_bgnd = 0;
// for (int i = 0; i < bgnd_sel.length; i++) if (bgnd_sel[i]) num_bgnd++;
// if (num_bgnd >= clt_parameters.min_bgnd_tiles) { // TODO: same for the backdrop too
if (bgndScan.texture != null) { // TODO: same for the backdrop too
if (clt_parameters.infinityDistance > 0.0){ // generate background as a billboard if (clt_parameters.infinityDistance > 0.0){ // generate background as a billboard
// tp.showScan(
// tp.clt_3d_passes.get(0), // CLTPass3d scan,
// "bg_scan_inf"); //String title)
double infinity_disparity = geometryCorrection.getDisparityFromZ(clt_parameters.infinityDistance); double infinity_disparity = geometryCorrection.getDisparityFromZ(clt_parameters.infinityDistance);
int scanIndex = 0; // it already exists?
CLTPass3d scan = tp.clt_3d_passes.get(scanIndex);
// grow selection, then grow once more and create border_tiles // grow selection, then grow once more and create border_tiles
// create/rstore, probably not needed // create/rstore, probably not needed
boolean [] bg_sel_backup = scan.getSelected().clone(); boolean [] bg_sel_backup = bgndScan.getSelected().clone();
boolean [] bg_border_backup = (scan.getBorderTiles() == null) ? null: scan.getBorderTiles().clone(); boolean [] bg_border_backup = (bgndScan.getBorderTiles() == null) ? null: bgndScan.getBorderTiles().clone();
boolean [] bg_selected = scan.getSelected(); boolean [] bg_selected = bgndScan.getSelected();
// tp.growTiles( // tp.growTiles(
// 2, // grow tile selection by 1 over non-background tiles 1: 4 directions, 2 - 8 directions, 3 - 8 by 1, 4 by 1 more // 2, // grow tile selection by 1 over non-background tiles 1: 4 directions, 2 - 8 directions, 3 - 8 by 1, 4 by 1 more
// bg_selected, // bg_selected,
// null); // prohibit // null); // prohibit
boolean [] border_tiles = bg_selected.clone(); boolean [] border_tiles = bg_selected.clone();
tp.growTiles( tp.growTiles(
2, // grow tile selection by 1 over non-background tiles 1: 4 directions, 2 - 8 directions, 3 - 8 by 1, 4 by 1 more 2, // grow tile selection by 1 over non-background tiles 1: 4 directions, 2 - 8 directions, 3 - 8 by 1, 4 by 1 more
bg_selected, bg_selected,
null); // prohibit null); // prohibit
// for (int) // for (int)
for (int i = 0; i < border_tiles.length; i++){ for (int i = 0; i < border_tiles.length; i++){
border_tiles[i] = !border_tiles[i] && bg_selected[i]; border_tiles[i] = !border_tiles[i] && bg_selected[i];
...@@ -6266,19 +6258,19 @@ public class QuadCLT { ...@@ -6266,19 +6258,19 @@ public class QuadCLT {
for (int ty = 0; ty < tilesY; ty++){ for (int ty = 0; ty < tilesY; ty++){
for (int tx = 0; tx < tilesX; tx++){ for (int tx = 0; tx < tilesX; tx++){
if (!bg_selected[tx + tilesX*ty]){ if (!bg_selected[tx + tilesX*ty]){
scan.texture_tiles[ty][tx] = null; bgndScan.texture_tiles[ty][tx] = null;
} }
} }
} }
scan.setBorderTiles(border_tiles); bgndScan.setBorderTiles(border_tiles);
// updates selection from non-null texture tiles // updates selection from non-null texture tiles
String texturePath = getPassImage( // get image from a single pass String texturePath = getPassImage( // get image from a single pass
clt_parameters, clt_parameters,
colorProcParameters, colorProcParameters,
rgbParameters, rgbParameters,
this.image_name+"-img_infinity", // +scanIndex, this.image_name+"-img_infinity", // +scanIndex,
scanIndex, bgndIndex,
threadsMax, // maximal number of threads to launch threadsMax, // maximal number of threads to launch
updateStatus, updateStatus,
debugLevel); debugLevel);
...@@ -6288,9 +6280,9 @@ public class QuadCLT { ...@@ -6288,9 +6280,9 @@ public class QuadCLT {
for (int ty = 0; ty < tilesY; ty ++) for (int tx = 0; tx < tilesX; tx ++){ for (int ty = 0; ty < tilesY; ty ++) for (int tx = 0; tx < tilesX; tx ++){
scan_disparity[indx++] = infinity_disparity; scan_disparity[indx++] = infinity_disparity;
} }
// tp.showScan( // tp.showScan(
// scan, // CLTPass3d scan, // scan, // CLTPass3d scan,
// "infinityDistance"); // "infinityDistance");
boolean showTri = false; // ((scanIndex < next_pass + 1) && clt_parameters.show_triangles) ||((scanIndex - next_pass) == 73); boolean showTri = false; // ((scanIndex < next_pass + 1) && clt_parameters.show_triangles) ||((scanIndex - next_pass) == 73);
try { try {
...@@ -6300,8 +6292,8 @@ public class QuadCLT { ...@@ -6300,8 +6292,8 @@ public class QuadCLT {
texturePath, texturePath,
"INFINITY", // id (scanIndex - next_pass), // id "INFINITY", // id (scanIndex - next_pass), // id
"INFINITY", // class "INFINITY", // class
scan.getTextureBounds(), bgndScan.getTextureBounds(),
scan.selected, bgndScan.selected,
scan_disparity, // scan.disparity_map[ImageDtt.DISPARITY_INDEX_CM], scan_disparity, // scan.disparity_map[ImageDtt.DISPARITY_INDEX_CM],
clt_parameters.transform_size, clt_parameters.transform_size,
clt_parameters.correct_distortions, // requires backdrop image to be corrected also clt_parameters.correct_distortions, // requires backdrop image to be corrected also
...@@ -6315,10 +6307,10 @@ public class QuadCLT { ...@@ -6315,10 +6307,10 @@ public class QuadCLT {
return false; return false;
} }
// maybe not needed // maybe not needed
scan.setBorderTiles(bg_border_backup); bgndScan.setBorderTiles(bg_border_backup);
scan.setSelected(bg_sel_backup); bgndScan.setSelected(bg_sel_backup);
}
} }
...@@ -6620,6 +6612,7 @@ public class QuadCLT { ...@@ -6620,6 +6612,7 @@ public class QuadCLT {
sdfa_instance.showArrays(dbg_img, tilesX, tilesY, true, "strict_grown",titles); sdfa_instance.showArrays(dbg_img, tilesX, tilesY, true, "strict_grown",titles);
} }
int num_bgnd = 0;
double [][][][] texture_tiles_bgnd = new double[tilesY][tilesX][][]; double [][][][] texture_tiles_bgnd = new double[tilesY][tilesX][][];
double [] alpha_zero = new double [4*clt_parameters.transform_size*clt_parameters.transform_size]; double [] alpha_zero = new double [4*clt_parameters.transform_size*clt_parameters.transform_size];
int alpha_index = 3; int alpha_index = 3;
...@@ -6632,6 +6625,7 @@ public class QuadCLT { ...@@ -6632,6 +6625,7 @@ public class QuadCLT {
bgnd_tiles_grown2[tileY * tilesX + tileX]) { bgnd_tiles_grown2[tileY * tilesX + tileX]) {
if (bgnd_tiles[tileY * tilesX + tileX]) { if (bgnd_tiles[tileY * tilesX + tileX]) {
texture_tiles_bgnd[tileY][tileX]= texture_tiles[tileY][tileX]; texture_tiles_bgnd[tileY][tileX]= texture_tiles[tileY][tileX];
num_bgnd++;
}else{ }else{
texture_tiles_bgnd[tileY][tileX]= texture_tiles[tileY][tileX].clone(); texture_tiles_bgnd[tileY][tileX]= texture_tiles[tileY][tileX].clone();
texture_tiles_bgnd[tileY][tileX][alpha_index] = alpha_zero; texture_tiles_bgnd[tileY][tileX][alpha_index] = alpha_zero;
...@@ -6647,6 +6641,7 @@ public class QuadCLT { ...@@ -6647,6 +6641,7 @@ public class QuadCLT {
bgnd_tiles[tileY * tilesX + tileX]) { bgnd_tiles[tileY * tilesX + tileX]) {
if (bgnd_tiles_grown2[tileY * tilesX + tileX]) { if (bgnd_tiles_grown2[tileY * tilesX + tileX]) {
texture_tiles_bgnd[tileY][tileX]= texture_tiles[tileY][tileX]; texture_tiles_bgnd[tileY][tileX]= texture_tiles[tileY][tileX];
num_bgnd++;
}else{ }else{
texture_tiles_bgnd[tileY][tileX]= texture_tiles[tileY][tileX].clone(); texture_tiles_bgnd[tileY][tileX]= texture_tiles[tileY][tileX].clone();
texture_tiles_bgnd[tileY][tileX][alpha_index] = alpha_zero; texture_tiles_bgnd[tileY][tileX][alpha_index] = alpha_zero;
...@@ -6656,6 +6651,11 @@ public class QuadCLT { ...@@ -6656,6 +6651,11 @@ public class QuadCLT {
} }
} }
if (num_bgnd < clt_parameters.min_bgnd_tiles){
return null; // no background to generate
}
ImageDtt image_dtt = new ImageDtt(); ImageDtt image_dtt = new ImageDtt();
double [][] texture_overlap = image_dtt.combineRGBATiles( double [][] texture_overlap = image_dtt.combineRGBATiles(
texture_tiles_bgnd, // texture_tiles, // array [tp.tilesY][tp.tilesX][4][4*transform_size] or [tp.tilesY][tp.tilesX]{null} texture_tiles_bgnd, // texture_tiles, // array [tp.tilesY][tp.tilesX][4][4*transform_size] or [tp.tilesY][tp.tilesX]{null}
......
...@@ -97,7 +97,7 @@ public class X3dOutput { ...@@ -97,7 +97,7 @@ public class X3dOutput {
Element el_Bgnd = x3dDoc.createElement("Background"); Element el_Bgnd = x3dDoc.createElement("Background");
el_Bgnd.setAttribute("class","Background"); el_Bgnd.setAttribute("class","Background");
el_Bgnd.setAttribute("id", "Background"); el_Bgnd.setAttribute("id", "Background");
if (use_backdrop) { if (use_backdrop && (bgnd_pass.texture != null)) {
el_Bgnd.setAttribute("frontUrl", bgnd_pass.texture); el_Bgnd.setAttribute("frontUrl", bgnd_pass.texture);
// temporarily - add same picture to all other sides. Actually - any square will work, make some // temporarily - add same picture to all other sides. Actually - any square will work, make some
// perspective grids/ colors to simplify orientation when looking wrong way // perspective grids/ colors to simplify orientation when looking wrong way
......
Markdown is supported
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