Commit 520cb0d7 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

Adding more control and multi-pass refineMotionVectors()

parent 4adfcfa1
Loading
Loading
Loading
Loading
+93 −15
Original line number Diff line number Diff line
@@ -725,7 +725,7 @@ public class CuasMotion {
		return total;
	}
	
	
	/*
	public static int addNewResults(
			final double [][][] target_sequence, // will only process non-nulls here
			final double [][][] new_sequence,
@@ -762,6 +762,7 @@ public class CuasMotion {
		ImageDtt.startAndJoin(threads);
		return anew.get();
	}
	*/
	public static double [][][] applyFilter(
			double [][][] target_sequence,
			int    [][]   filter5){
@@ -2058,9 +2059,19 @@ public class CuasMotion {
			int                 half_accum_range,   // corr_pairs/2
			boolean             smooth,
			int                 corr_offset,        // inter-frame distance for correlation pairs
			int                 corr_offset_scale,
			double              mv_diff_max,        // if > 0, fail for high MV correction 
			String              dbg_suffix,
			int                 dbg_iter_index,     // to generate different image names for different iteration to simplify "save as" images
			int                 debugLevel) {
		// TODO: limit corr_offset_scale so corr_offset_eff will not exceed scan range (but keep >=1)
		
		final int max_index_dbg = 5; // show images for the first iterations only
		// By Claude on 05/13/2026: scale corr_offset for residual measurement.
		// S>1 uses larger frame separation (better SNR for small residuals); result is divided by S to normalize.
		// offset_scale for mask positioning and corr_offset_mv in correlatePairs stay on original corr_offset.
//		final int corr_offset_scale = (int) Math.round(recalc_mv_boost); // TODO: promote to config or derive from other params
		final int corr_offset_eff   = corr_offset * corr_offset_scale;
		final int tileSize = GPUTileProcessor.DTT_SIZE;   // 8 pixels
		final int tilesX   = cuasMotion.tilesX;
		final int width    = cuasMotion.gpu_max_width;
@@ -2078,7 +2089,11 @@ public class CuasMotion {
		// Hard-coded debug selectors: set >= 0 to enable per-scan/per-tile visualisation
		final int dbg_nseq = 97; // 40; // 41; // 157; // -(116); // 57; // 20; // -1;
		final int dbg_tile = 54+38*80; //52+38*80;  // 50+38*80; // 55+38*80; // -(17 + 33*80); // 48+32*80; // 50+38*80; // -1;

		if (debugLevel >= 0) {
			System.out.println("refineMotionVectors(): corr_offset="+corr_offset+", corr_offset_scale="+corr_offset_scale+
					", corr_offset_eff="+corr_offset_eff+
					", dbg_nseq="+dbg_nseq+", dbg_tile="+dbg_tile);
		}
		// Pre-compute integer-pixel raised-cosine mask kernel once (shared across all nseq)
		final int r1i = (int) Math.ceil(recalc_mv_r1);
		final int mside = 2 * r1i + 1;
@@ -2095,7 +2110,7 @@ public class CuasMotion {
		}
		if ((dbg_nseq >= 0 || dbg_tile >= 0) && (debugLevel >= 0) && (dbg_iter_index<= max_index_dbg)) {
			ShowDoubleFloatArrays.showArrays(mask_kernel.clone(), mside, mside,
					"refineMotionVectors-mask-boost"+recalc_mv_boost+"-r0_" + recalc_mv_r0 + "-r1_" + recalc_mv_r1+"-niter"+dbg_iter_index);
					"refineMotionVectors-mask-boost"+recalc_mv_boost+"-r0_" + recalc_mv_r0 + "-r1_" + recalc_mv_r1+"-niter"+dbg_iter_index+dbg_suffix);
		}

		// Allocate staging array once; each nseq clears only the frames it needs
@@ -2122,7 +2137,7 @@ public class CuasMotion {
			int frame_center = frame0 + nseq * corr_inc;
			// Center the boosted correlation window on frame_center
			int frame0_ref  = frame_center - corr_pairs_ref / 2;
			int frame1_ref  = frame0_ref + corr_offset;
			int frame1_ref  = frame0_ref + corr_offset_eff;

			// Determine the frame range actually accessed by correlatePairs
			// (pairs where frame0+dframe>=0 AND frame1+dframe<nframes)
@@ -2199,7 +2214,7 @@ public class CuasMotion {
							? scene_titles_all[f] : "f" + f;
				}
				ShowDoubleFloatArrays.showArrays(stack_slices, width, height, true,
						"refineMotionVectors-boost"+recalc_mv_boost+"-masked-nseq" + nseq+"-niter"+dbg_iter_index, stack_titles);
						"refineMotionVectors-boost"+recalc_mv_boost+"-masked-nseq" + nseq+"-niter"+dbg_iter_index+dbg_suffix, stack_titles);
			}
			if ((nseq == dbg_nseq) && (debugLevel >= 0) && (dbg_iter_index<= max_index_dbg)) {
				int fcount = fmax_alloc - fmin_alloc + 1;
@@ -2212,7 +2227,7 @@ public class CuasMotion {
							? scene_titles_all[f] : "f" + f;
				}
				ShowDoubleFloatArrays.showArrays(stack_slices, width, height, true,
						"refineMotionVectors-boost"+recalc_mv_boost+"-nseq" + nseq+"-niter"+dbg_iter_index, stack_titles);
						"refineMotionVectors-boost"+recalc_mv_boost+"-nseq" + nseq+"-niter"+dbg_iter_index+dbg_suffix, stack_titles);
			}

			TDCorrTile[] tdCorrTiles = cuasMotion.correlatePairs( // By Claude on 05/06/2026
@@ -2255,18 +2270,25 @@ public class CuasMotion {
				double[] target = targets_nonoverlap[nseq][ntile];
				if (target == null || Double.isNaN(target[CuasMotionLMA.RSLT_X])) continue;
				if (vector_field[ntile] == null) continue;
				double scaled_dvx = vector_field[ntile][INDX_VX] / corr_offset_scale; // By Claude on 05/13/2026
				double scaled_dvy = vector_field[ntile][INDX_VY] / corr_offset_scale;
				if (ntile == dbg_tile && debugLevel >= 0) {
					System.out.printf("refineMotionVectors(): nseq=%3d ntile=%4d  before: VX=%9.4f VY=%9.4f  delta: dVX=%8.4f dVY=%8.4f  after: VX1=%9.4f VY1=%9.4f VSTR=%9.4f\n",
							nseq, ntile,
							target[CuasMotionLMA.RSLT_VX], target[CuasMotionLMA.RSLT_VY],
							vector_field[ntile][INDX_VX],   vector_field[ntile][INDX_VY],
							target[CuasMotionLMA.RSLT_VX] + vector_field[ntile][INDX_VX],
							target[CuasMotionLMA.RSLT_VY] + vector_field[ntile][INDX_VY],
							scaled_dvx, scaled_dvy,
							target[CuasMotionLMA.RSLT_VX] + scaled_dvx,
							target[CuasMotionLMA.RSLT_VY] + scaled_dvy,
							vector_field[ntile][INDX_STR]);
				}
				target[CuasMotionLMA.RSLT_VX] +=  vector_field[ntile][INDX_VX]; // disable for testing
				target[CuasMotionLMA.RSLT_VY] +=  vector_field[ntile][INDX_VY];
				target[CuasMotionLMA.RSLT_VX] += scaled_dvx;
				target[CuasMotionLMA.RSLT_VY] += scaled_dvy;
				target[CuasMotionLMA.RSLT_VSTR] = vector_field[ntile][INDX_STR];
				target[CuasMotionLMA.RSLT_VCORR] = Math.sqrt(scaled_dvx*scaled_dvx + scaled_dvy*scaled_dvy);
				if ((mv_diff_max > 0) && (target[CuasMotionLMA.RSLT_VCORR] > mv_diff_max) && !(target[CuasMotionLMA.RSLT_FAIL] > 0 )) {
					target[CuasMotionLMA.RSLT_FAIL] = CuasMotionLMA.FAIL_VCORR; // set when?
					// set RSLT_WHEN - will be set in public static int addNewResults()
				}
			}
		}
		// Debug: CORR2D overview — one slice per keyframe, same layout as *CORR2D.tiff
@@ -2293,7 +2315,7 @@ public class CuasMotion {
					dbg_2d_corrs,
					cuasMotion.tilesX * (corr_size + 1),
					cuasMotion.tilesY * (corr_size + 1),
					"refineMotionVectors-CORR2D-boost"+recalc_mv_boost+"-n"+dbg_iter_index,
					"refineMotionVectors-CORR2D-boost"+recalc_mv_boost+"-n"+dbg_iter_index+dbg_suffix,
					slice_titles_ref).show();
		}
	}
@@ -8084,10 +8106,16 @@ public class CuasMotion {
			System.out.println("\n========================== Starting centered iterations =============================.\n");
		}
		// By Claude on 05/05/2026 — optional MV refinement parameters for centered loop
		boolean recalc_mv       = clt_parameters.imp.cuas_recalc_mv && !slow_mode;
//		boolean recalc_mv       = clt_parameters.imp.cuas_recalc_mv && !slow_mode;
		int     recalc_mv_num =   slow_mode ? 0 : clt_parameters.imp.cuas_recalc_mv_num;
		double  recalc_mv_boost = clt_parameters.imp.cuas_recalc_mv_boost;
		double  recalc_mv_corr  =  clt_parameters.imp.cuas_recalc_mv_corr;
		double  recalc_mv_r0    = clt_parameters.imp.cuas_recalc_mv_r0;
		double  recalc_mv_r1    = clt_parameters.imp.cuas_recalc_mv_r1;
		double  recalc_mv_r0f   = clt_parameters.imp.cuas_recalc_mv_r0f;
		double  recalc_mv_r1f   = clt_parameters.imp.cuas_recalc_mv_r1f;
		double  recalc_mv_max2  = clt_parameters.imp.cuas_recalc_mv_max2;
		int     recalc_mv_icorr = (int) Math.round(recalc_mv_corr);
		
	    double lma_rrms2 =       clt_parameters.imp.cuas_lma_rrms2; // =      0.15; // Maximal relative to A rms. OK is when (RMS < cuas_lma_arms) || (RMS < cuas_lma_rrms * A)
	    double lma_mina2 =       clt_parameters.imp.cuas_lma_mina2; // =      1.0;  // Minimal A (amplitude)
@@ -8231,7 +8259,8 @@ public class CuasMotion {
			if (accum_boosted) {
				// Andrey 05/05/2026 moved here (earlier) so shiftAndRenderAccumulate() will use updated motion vector
				// By Claude on 05/05/2026 — re-correlate with spatial mask around known target
				if (recalc_mv) {
				if (recalc_mv_num > 0) {
					int corr_offset_scale = (int) Math.round(recalc_mv_boost); // TODO: promote to config or derive from other params	
					refineMotionVectors(
							clt_parameters,      // CLTParameters   clt_parameters,
							batch_mode,          // boolean         batch_mode,
@@ -8246,9 +8275,33 @@ public class CuasMotion {
							half_accum_range,    // int             half_accum_range,
							smooth,              // boolean         smooth,
							corr_offset,         // int             corr_offset,
							recalc_mv_icorr,     // int           corr_offset_scale,
							0,                   // double              mv_diff_max,        // if > 0, fail for high MV correction 
							"-first",            // String              dbg_suffix,
							niter - niter0,      // int                 dbg_iter_index,
							debugLevel); // -1); // debugLevel);         // int             debugLevel)
					if (recalc_mv_num > 1) {
					refineMotionVectors( // just testing conversion
							clt_parameters,      // CLTParameters   clt_parameters,
							batch_mode,          // boolean         batch_mode,
							cuasMotion,          // CuasMotion      cuasMotion,
							recalc_mv_boost,     // double          recalc_mv_boost,
							recalc_mv_r0f,       // double          recalc_mv_r0,
							recalc_mv_r1f,       // double          recalc_mv_r1,
							fpixels_refine,      // By Claude on 05/07/2026: LPF'd with precorr_ra (was fpixels_tum)
							targets_nonoverlap,  // double [][][]   targets_nonoverlap,
							frame0,              // int             frame0,
							corr_inc,            // int             corr_inc,
							half_accum_range,    // int             half_accum_range,
							smooth,              // boolean         smooth,
							corr_offset,         // int             corr_offset,
							recalc_mv_icorr,     // final int           corr_offset_scale,
							recalc_mv_max2,      // double              mv_diff_max,        // if > 0, fail for high MV correction 
							"-second",           // String              dbg_suffix,
							niter - niter0,      // int                 dbg_iter_index,
							debugLevel); // -1); // debugLevel);         // int             debugLevel)
					}
				}
				double [][][] extended_scan = extendMotionScan(
						targets_nonoverlap, // final double [][][] motion_scan,
						null, // filter5,      // final boolean [][]  filtered, // centers, should be non-overlapped
@@ -8356,9 +8409,10 @@ public class CuasMotion {
				}
			}
			if (accum_base) {
//				int corr_offset_scale = 4; // (int) Math.round(recalc_mv_boost); // TODO: promote to config or derive from other params	
				// Andrey 05/05/2026 moved here (earlier) so shiftAndRenderAccumulate() will use updated motion vector
				// By Claude on 05/05/2026 — re-correlate with spatial mask around known target
				if (recalc_mv) {
				if (recalc_mv_num > 0) {
					refineMotionVectors(
							clt_parameters,      // CLTParameters   clt_parameters,
							batch_mode,          // boolean         batch_mode,
@@ -8373,8 +8427,32 @@ public class CuasMotion {
							half_accum_range,    // int             half_accum_range,
							smooth,              // boolean         smooth,
							corr_offset,         // int             corr_offset,
							recalc_mv_icorr,     // final int           corr_offset_scale,
							0,                   // double              mv_diff_max,        // if > 0, fail for high MV correction 
							"-first",            // String              dbg_suffix,
							niter - niter0,      // int                 dbg_iter_index,
							debugLevel); // -1); // debugLevel);         // int             debugLevel)
					if (recalc_mv_num > 1) {					
					refineMotionVectors(
							clt_parameters,      // CLTParameters   clt_parameters,
							batch_mode,          // boolean         batch_mode,
							cuasMotion,          // CuasMotion      cuasMotion,
							1.0, // recalc_mv_boost,     // double          recalc_mv_boost,
							recalc_mv_r0f,        // double          recalc_mv_r0,
							recalc_mv_r1f,        // double          recalc_mv_r1,
							fpixels_refine,      // By Claude on 05/07/2026: LPF'd with precorr_ra (was fpixels_tum)
							targets_nonoverlap,  // double [][][]   targets_nonoverlap,
							frame0,              // int             frame0,
							corr_inc,            // int             corr_inc,
							half_accum_range,    // int             half_accum_range,
							smooth,              // boolean         smooth,
							corr_offset,         // int             corr_offset,
							recalc_mv_icorr,     // final int           corr_offset_scale,
							recalc_mv_max2,      // double              mv_diff_max,        // if > 0, fail for high MV correction 
							"-second",           // String              dbg_suffix,
							niter - niter0,      // int                 dbg_iter_index,
							debugLevel); // -1); // debugLevel);         // int             debugLevel)
					}
				}
				double [][][] extended_scan = extendMotionScan(
						targets_nonoverlap, // final double [][][] motion_scan,
+54 −53
Original line number Diff line number Diff line
@@ -83,58 +83,58 @@ public class CuasMotionLMA {
	public static final int RSLT_VSTR =   19;
	public static final int RSLT_VFRAC =  20;
	public static final int RSLT_VBOOST = 21; // motion vector was calculated with boosted number of accumulated scene pairs (based scaled this)
	
	public static final int RSLT_BX =     22;
	public static final int RSLT_BY =     23; // RSLT_BX+1;
	public static final int RSLT_AX =     24; // RSLT_BX+2;
	public static final int RSLT_AY =     25; // RSLT_BX+3;
	public static final int RSLT_MISMATCH_BEFORE = 26;
	public static final int RSLT_MISMATCH_AFTER =  27; // RSLT_MISMATCH_BEFORE+1;
	public static final int RSLT_MISMATCH_DIRS=    28;
	public static final int RSLT_MATCH_LENGTH=     29; // is one less than the total length (0 - isolated)
	public static final int RSLT_BEFORE_LENGTH=    30; // just for debug
	public static final int RSLT_AFTER_LENGTH=     31; // just for debug
	public static final int RSLT_SEQ_TRAVEL=       32; 
	public static final int RSLT_MSCORE =          33;
	public static final int RSLT_QA =              34;
	public static final int RSLT_QRMS =            35;
	public static final int RSLT_QRMS_A =          36;
	public static final int RSLT_QCENTER =         37;
	public static final int RSLT_QMATCH =          38;
	public static final int RSLT_QMATCH_LEN=       39;
	public static final int RSLT_QTRAVEL=          40;
	public static final int RSLT_QSCORE =          41;
	public static final int RSLT_STRONGER =        42; // index of stronger neighbor (may be more)
	public static final int RSLT_SLOW =            43; // 1 - slow, 0 - fast 
	public static final int RSLT_WHEN =            44;
	public static final int RSLT_FAIL =            45;
	public static final int RSLT_DISPARITY=        46; // disparity from single keyframe sequences
	public static final int RSLT_DISP_DIFF=        47; // disparity difference between what?
	public static final int RSLT_DISP_STR =        48; // disparity strength
	public static final int RSLT_RANGE =           49; // range (meters) found from RSLT_DISPARITY, modified by RSLT_INFINITY
	public static final int RSLT_GLOBAL =          50; // local target ID (1-based)
	public static final int RSLT_GLENGTH =         51; // length (symmetrical around this one) for which disparity and range are provided
	public static final int RSLT_GDISPARITY=       52; // disparity from accumulation of the range (RSLT_GLENGTH)
	public static final int RSLT_GDISP_DIFF=       53; // disparity difference for a range
	public static final int RSLT_GDISP_STR =       54; // disparity strength for a range
	public static final int RSLT_GRANGE =          55; // global range - calculated for long sequences (and its fractions)
	public static final int RSLT_FL_PX =           56; // flight log px
	public static final int RSLT_FL_PY =           57; // flight log py
	public static final int RSLT_FL_DISP =         58; // flight log true disparity
	public static final int RSLT_FL_RANGE =        59; // flight log range (meters)
	public static final int RSLT_INFINITY =        60; // disparity at infinity used for range calculation
	public static final int RSLT_TARGET_ID =       61; // unique target id for the whole sequence of segments. 1 is reserved for the UAS
	public static final int RSLT_VEL_AWAY =        62; // axial velocity (positive - away), range derivative (m/s), calculated from the difference to the previous/next series range 
	public static final int RSLT_VEL_RIGHT =       63; // lateral velocity, right ( calculated from angular and RSLT_GRANGE
	public static final int RSLT_VEL_UP =          64; // lateral velocity, up ( calculated from angular and RSLT_GRANGE
	public static final int RSLT_RANGE_LIN =       65; // range linear interpolated using previous/next series if the same target is present there 
	public static final int RSLT_VCORR =  22; // Last correction of VX, VY during refine (large correction means failed correction)
	public static final int RSLT_BX =     23;
	public static final int RSLT_BY =     24; // RSLT_BX+1;
	public static final int RSLT_AX =     25; // RSLT_BX+2;
	public static final int RSLT_AY =     26; // RSLT_BX+3;
	public static final int RSLT_MISMATCH_BEFORE = 27;
	public static final int RSLT_MISMATCH_AFTER =  28; // RSLT_MISMATCH_BEFORE+1;
	public static final int RSLT_MISMATCH_DIRS=    29;
	public static final int RSLT_MATCH_LENGTH=     30; // is one less than the total length (0 - isolated)
	public static final int RSLT_BEFORE_LENGTH=    31; // just for debug
	public static final int RSLT_AFTER_LENGTH=     32; // just for debug
	public static final int RSLT_SEQ_TRAVEL=       33; 
	public static final int RSLT_MSCORE =          34;
	public static final int RSLT_QA =              35;
	public static final int RSLT_QRMS =            36;
	public static final int RSLT_QRMS_A =          37;
	public static final int RSLT_QCENTER =         38;
	public static final int RSLT_QMATCH =          39;
	public static final int RSLT_QMATCH_LEN=       40;
	public static final int RSLT_QTRAVEL=          41;
	public static final int RSLT_QSCORE =          42;
	public static final int RSLT_STRONGER =        43; // index of stronger neighbor (may be more)
	public static final int RSLT_SLOW =            44; // 1 - slow, 0 - fast 
	public static final int RSLT_WHEN =            45;
	public static final int RSLT_FAIL =            46;
	public static final int RSLT_DISPARITY=        47; // disparity from single keyframe sequences
	public static final int RSLT_DISP_DIFF=        48; // disparity difference between what?
	public static final int RSLT_DISP_STR =        49; // disparity strength
	public static final int RSLT_RANGE =           50; // range (meters) found from RSLT_DISPARITY, modified by RSLT_INFINITY
	public static final int RSLT_GLOBAL =          51; // local target ID (1-based)
	public static final int RSLT_GLENGTH =         52; // length (symmetrical around this one) for which disparity and range are provided
	public static final int RSLT_GDISPARITY=       53; // disparity from accumulation of the range (RSLT_GLENGTH)
	public static final int RSLT_GDISP_DIFF=       54; // disparity difference for a range
	public static final int RSLT_GDISP_STR =       55; // disparity strength for a range
	public static final int RSLT_GRANGE =          56; // global range - calculated for long sequences (and its fractions)
	public static final int RSLT_FL_PX =           57; // flight log px
	public static final int RSLT_FL_PY =           58; // flight log py
	public static final int RSLT_FL_DISP =         59; // flight log true disparity
	public static final int RSLT_FL_RANGE =        60; // flight log range (meters)
	public static final int RSLT_INFINITY =        61; // disparity at infinity used for range calculation
	public static final int RSLT_TARGET_ID =       62; // unique target id for the whole sequence of segments. 1 is reserved for the UAS
	public static final int RSLT_VEL_AWAY =        63; // axial velocity (positive - away), range derivative (m/s), calculated from the difference to the previous/next series range 
	public static final int RSLT_VEL_RIGHT =       64; // lateral velocity, right ( calculated from angular and RSLT_GRANGE
	public static final int RSLT_VEL_UP =          65; // lateral velocity, up ( calculated from angular and RSLT_GRANGE
	public static final int RSLT_RANGE_LIN =       66; // range linear interpolated using previous/next series if the same target is present there 
	public static final int RSLT_LEN = RSLT_RANGE_LIN + 1;
	
	public static final String [] LMA_TITLES = 
		{"X-OFFS","Y-OFFS", "AMPLITUDE", "RADIUS","RAD_POS", "OVERSHOOT","OFFSET","RMSE","RMSE/A","MAX2A","ITERATIONS",
				"CENTERED", "EXP-BOOST",
				"Centr-X","Centr-Y","Centr-max","Centr-frac",
				"Vx", "Vy", "V-conf","V-frac", "V-boost",// from motion vectors
				"Vx", "Vy", "V-conf","V-frac", "V-boost","V-corr",// from motion vectors
				"X-before", "Y-before","X-after","Y-after",  // from getHalfBeforeAfterPixXY()
				"ERR-BEFORE", "ERR-AFTER", "BA-DIRS", // before dir + 16*after dir
				"Match-length",
@@ -166,12 +166,13 @@ public class CuasMotionLMA {
	public static final int FAIL_K_LOW =    13;  // Overshoot is too low (not used, it can be down to 0)
	public static final int FAIL_K_HIGH =   14;  // Overshoot is too high
	public static final int FAIL_FAR =      15;  // Peak is too far from the center
	public static final int FAIL_HORIZON =  16;  // Peak is below horizon 
	public static final int FAIL_MISMATCH = 17;  // Mismatch on both ends is too high 
	public static final int FAIL_NEIGHBOR = 18;  // failed because some neighbor is stronger   
	public static final int FAIL_DUPLICATE= 19;  // coordinate are (almost) the same as those of a stronger tile   
	public static final int FAIL_USED=      20;  // non-centered used to generate centered, remove this   
	public static final int FAIL_FL_ONLY=   21;  // Flight log data only, no target detected here   
	public static final int FAIL_VCORR =    16;  // MV refinement (fine pass) resulted in a too high correction (not yet checked)
	public static final int FAIL_HORIZON =  17;  // Peak is below horizon 
	public static final int FAIL_MISMATCH = 18;  // Mismatch on both ends is too high 
	public static final int FAIL_NEIGHBOR = 19;  // failed because some neighbor is stronger   
	public static final int FAIL_DUPLICATE= 20;  // coordinate are (almost) the same as those of a stronger tile   
	public static final int FAIL_USED=      21;  // non-centered used to generate centered, remove this   
	public static final int FAIL_FL_ONLY=   22;  // Flight log data only, no target detected here   
	
	public static final int CENTERED_NO =    0; 
	public static final int CENTERED_YES =   1; 
+47 −12

File changed.

Preview size limit exceeded, changes collapsed.