| Line 139... |
Line 139... |
| 139 |
double firstCircleX = circles[0];
|
139 |
double firstCircleX = circles[0];
|
| 140 |
double secondCircleX = circles[1];
|
140 |
double secondCircleX = circles[1];
|
| 141 |
double distance = Math.abs(firstCircleX - secondCircleX);
|
141 |
double distance = Math.abs(firstCircleX - secondCircleX);
|
| 142 |
LOGGER.info("Distance is " + distance);
|
142 |
LOGGER.info("Distance is " + distance);
|
| 143 |
|
143 |
|
| 144 |
LOGGER.info("Starting Checkdistance method");
|
144 |
double[] cal = calibrate(driver, actionProvider, distance);
|
| 145 |
int moveByOffset = checkDistance(driver, wait10Sec, actionProvider, distance, slideButton);
|
145 |
int moveByOffset = cal == null ? 0 : (int) cal[0];
|
| 146 |
if (moveByOffset > 0) {
|
146 |
if (moveByOffset > 0) {
|
| 147 |
LOGGER.info("Margin Offset - " + slideButton.getCssValue("margin-left"));
|
147 |
// Move, then measure again and close the remainder BEFORE
|
| 148 |
LOGGER.info("Ending Checkdistance method " + moveByOffset);
|
148 |
// releasing. Releasing on the first computed offset committed
|
| - |
|
149 |
// the whole calibration error to the final position.
|
| 149 |
actionProvider.moveByOffset(moveByOffset, 0).release().perform();
|
150 |
actionProvider.moveByOffset(moveByOffset, 0).perform();
|
| - |
|
151 |
refine(driver, actionProvider, cal[1]);
|
| - |
|
152 |
actionProvider.release().perform();
|
| 150 |
LOGGER.info("Move click performed");
|
153 |
LOGGER.info("Move click performed (main {}px)", moveByOffset);
|
| 151 |
try {
|
154 |
try {
|
| 152 |
try {
|
155 |
try {
|
| 153 |
wait5Sec.until(ExpectedConditions.visibilityOfElementLocated(By.className("dx_captcha_basic_bar-inform")));
|
156 |
wait5Sec.until(ExpectedConditions.visibilityOfElementLocated(By.className("dx_captcha_basic_bar-inform")));
|
| 154 |
LOGGER.warn("Failed = " + counter);
|
157 |
LOGGER.warn("Failed = " + counter);
|
| 155 |
} catch (Exception notFailedException) {
|
158 |
} catch (Exception notFailedException) {
|
| Line 269... |
Line 272... |
| 269 |
LOGGER.warn("Could not read regDate from the Oppo response: " + e.getMessage());
|
272 |
LOGGER.warn("Could not read regDate from the Oppo response: " + e.getMessage());
|
| 270 |
return null;
|
273 |
return null;
|
| 271 |
}
|
274 |
}
|
| 272 |
}
|
275 |
}
|
| 273 |
|
276 |
|
| - |
|
277 |
/**
|
| - |
|
278 |
* Slider pixels to nudge when working out how far the puzzle piece travels per
|
| - |
|
279 |
* slider pixel.
|
| - |
|
280 |
*
|
| - |
|
281 |
* This was 15, which was the reason the captcha only solved about 9% of the time.
|
| - |
|
282 |
* The piece moves roughly 1.7 px per slider px, so a 15 px nudge closed the gap by
|
| - |
|
283 |
* only ~25 px -- and Hough circle detection is worth about +/-2-3 px per circle, so
|
| - |
|
284 |
* the ratio was being derived from a measurement with ~20% noise in it. That error
|
| - |
|
285 |
* then multiplied across the whole remaining travel: on a 150 px gap it landed ~30 px
|
| - |
|
286 |
* out, and the target hole is only ~30 px across, so it missed entirely.
|
| - |
|
287 |
*
|
| - |
|
288 |
* A 60 px nudge closes ~100 px, so the same detection noise is ~5% instead of ~20%.
|
| - |
|
289 |
*/
|
| - |
|
290 |
private static final int CALIBRATION_NUDGE = 60;
|
| - |
|
291 |
|
| - |
|
292 |
/** Stop correcting once the piece is within this many px of the hole. */
|
| - |
|
293 |
private static final double ALIGNED_PX = 2.0;
|
| - |
|
294 |
|
| - |
|
295 |
/**
|
| - |
|
296 |
* @return {sliderPxToMove, sliderPxPerCirclePx}, or null when the circles could not
|
| - |
|
297 |
* be read. Returned rather than stored on a field: this is a singleton and
|
| - |
|
298 |
* the Oppo secondary and tertiary jobs run it concurrently.
|
| - |
|
299 |
*/
|
| 274 |
private int checkDistance(WebDriver driver, WebDriverWait wait3Sec, Actions actionProvider, double distance, WebElement slideButton) throws Exception {
|
300 |
private double[] calibrate(WebDriver driver, Actions actionProvider, double distance) throws Exception {
|
| - |
|
301 |
actionProvider.moveByOffset(CALIBRATION_NUDGE, 0).perform();
|
| 275 |
|
302 |
|
| 276 |
//actionProvider.moveToElement(slideButton).clickAndHold().moveByOffset(1, 0).perform();
|
- |
|
| 277 |
actionProvider.moveByOffset(15, 0).perform();
|
- |
|
| 278 |
String fileName2 = "/tmp/" + Thread.currentThread().getName() + "-moved.png";
|
303 |
String fileName2 = "/tmp/" + Thread.currentThread().getName() + "-moved.png";
|
| 279 |
double[] movedCircles = getMatCircles2(driver, fileName2);
|
304 |
double[] movedCircles = getMatCircles2(driver, fileName2);
|
| 280 |
if (movedCircles == null) return 0;
|
305 |
if (movedCircles == null) return null;
|
| - |
|
306 |
|
| 281 |
double movedFirst = movedCircles[0];
|
307 |
double movedDistance = Math.abs(movedCircles[0] - movedCircles[1]);
|
| 282 |
double movedSecond = movedCircles[1];
|
308 |
double closed = distance - movedDistance;
|
| - |
|
309 |
LOGGER.info("Calibration: gap {} -> {} after {}px, closed {}",
|
| 283 |
//System.out.println("Test Offset Move " + testMove);
|
310 |
distance, movedDistance, CALIBRATION_NUDGE, closed);
|
| - |
|
311 |
|
| 284 |
LOGGER.info("Found Moved " + movedFirst + " ," + movedSecond);
|
312 |
// A non-positive value means the piece did not move, or moved away from the
|
| - |
|
313 |
// hole -- either way the ratio is meaningless and guessing would waste the try.
|
| - |
|
314 |
if (closed <= 0) return null;
|
| - |
|
315 |
|
| - |
|
316 |
double sliderPerCircle = CALIBRATION_NUDGE / closed;
|
| 285 |
double movedDistance = Math.abs(movedFirst - movedSecond);
|
317 |
int moveBy = (int) Math.round(movedDistance * sliderPerCircle);
|
| 286 |
double moved = distance - movedDistance;
|
318 |
return new double[]{moveBy, sliderPerCircle};
|
| - |
|
319 |
}
|
| - |
|
320 |
|
| - |
|
321 |
/**
|
| - |
|
322 |
* Measure again after the main move and close whatever is left. The old code
|
| - |
|
323 |
* committed its single computed offset blind, so any calibration error went
|
| 287 |
/*LOGGER.info("Original distance " + distance);
|
324 |
* straight into the final position with nothing to catch it.
|
| - |
|
325 |
*/
|
| - |
|
326 |
private int refine(WebDriver driver, Actions actionProvider, double sliderPerCircle) throws Exception {
|
| - |
|
327 |
String fileName = "/tmp/" + Thread.currentThread().getName() + "-refine.png";
|
| 288 |
LOGGER.info("Moved Distance " + movedDistance);
|
328 |
double[] circles = getMatCircles2(driver, fileName);
|
| 289 |
LOGGER.info("Moved " + moved);*/
|
329 |
if (circles == null) return 0;
|
| - |
|
330 |
|
| - |
|
331 |
double remaining = Math.abs(circles[0] - circles[1]);
|
| 290 |
if (moved == 0) return 0;
|
332 |
if (remaining <= ALIGNED_PX) return 0;
|
| - |
|
333 |
|
| 291 |
int moveBy = (int) ((movedDistance) * (15 / moved));
|
334 |
int correction = (int) Math.round(remaining * sliderPerCircle);
|
| 292 |
//int moveBy = (int) distance - 21;
|
335 |
if (correction == 0) return 0;
|
| - |
|
336 |
LOGGER.info("Refine: {}px of gap left -> nudging {}px", remaining, correction);
|
| - |
|
337 |
actionProvider.moveByOffset(correction, 0).perform();
|
| 293 |
return moveBy;
|
338 |
return correction;
|
| 294 |
}
|
339 |
}
|
| 295 |
|
340 |
|
| 296 |
private Mat getMatCircles(WebDriver driver, String fileName) throws Exception {
|
341 |
private Mat getMatCircles(WebDriver driver, String fileName) throws Exception {
|
| 297 |
|
342 |
|
| 298 |
File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
|
343 |
File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
|