From 8839f97456701f4d01641e8f0356be30bea8798c Mon Sep 17 00:00:00 2001 From: davpapp Date: Thu, 15 Mar 2018 23:14:51 -0400 Subject: [PATCH] refactored some code --- src/Cursor.java | 4 --- src/CursorTask.java | 1 - src/DetectedObject.java | 1 - src/ImageCapturer.java | 17 ++++++++++++ src/ImageCollector.java | 5 ++-- src/Inventory.java | 20 ++++++++++++-- src/IronMiner.java | 33 ++++++++++++++---------- src/ObjectDetector.java | 5 ---- src/PathTransformer.java | 2 +- src/RandomDetector.java | 30 +++++++-------------- src/TrackerThread.java | 2 +- target/classes/CameraCalibrator.class | Bin 1923 -> 1327 bytes target/classes/Cursor.class | Bin 9399 -> 9320 bytes target/classes/CursorTask.class | Bin 2899 -> 2899 bytes target/classes/DetectedObject.class | Bin 2237 -> 2237 bytes target/classes/ImageCapturer.class | Bin 0 -> 763 bytes target/classes/ImageCollector.class | Bin 4335 -> 4053 bytes target/classes/Inventory.class | Bin 4674 -> 5057 bytes target/classes/IronMiner.class | Bin 6898 -> 6821 bytes target/classes/ObjectDetector.class | Bin 7447 -> 7112 bytes target/classes/PathTransformer.class | Bin 2568 -> 2121 bytes target/classes/RandomDetector.class | Bin 4145 -> 3767 bytes target/classes/RandomDetectorTest.class | Bin 2328 -> 2320 bytes target/classes/TrackerThread.class | Bin 3147 -> 3162 bytes 24 files changed, 69 insertions(+), 51 deletions(-) create mode 100644 src/ImageCapturer.java create mode 100644 target/classes/ImageCapturer.class diff --git a/src/Cursor.java b/src/Cursor.java index ee4b30b..f1ff2d6 100644 --- a/src/Cursor.java +++ b/src/Cursor.java @@ -68,7 +68,6 @@ public class Cursor { this.cursorPathsByDistance.get(cursorPath.getCursorPathDistance()).add(cursorPath); } - // TODO: make sure these are reasonable private int getRandomClickLength() { return Randomizer.nextGaussianWithinRange(MINIMUM_CLICK_LENGTH, MAXIMUM_CLICK_LENGTH); } @@ -76,7 +75,6 @@ public class Cursor { private int getRandomClickReleaseLength() { return Randomizer.nextGaussianWithinRange(MINIMUM_CLICK_LENGTH + 5, MAXIMUM_CLICK_LENGTH + 10); } - // END public void leftClickCursor() throws InterruptedException { Thread.sleep(30, 55); @@ -240,12 +238,10 @@ public class Cursor { } private Point randomizePoint(Point goalPoint, int xTolerance, int yTolerance) { - Randomizer randomizer = new Randomizer(); return new Point(goalPoint.x + Randomizer.nextGaussianWithinRange(-xTolerance, xTolerance), goalPoint.y + Randomizer.nextGaussianWithinRange(-yTolerance, yTolerance)); } private Point randomizePoint(Point goalPoint, int xToleranceLeft, int xToleranceRight, int yTolerance) { - Randomizer randomizer = new Randomizer(); return new Point(goalPoint.x + Randomizer.nextGaussianWithinRange(-xToleranceLeft, xToleranceRight), goalPoint.y + Randomizer.nextGaussianWithinRange(-yTolerance, yTolerance)); } diff --git a/src/CursorTask.java b/src/CursorTask.java index f5e1b99..6bc68f9 100644 --- a/src/CursorTask.java +++ b/src/CursorTask.java @@ -38,7 +38,6 @@ public class CursorTask { } } - public Point dropItem(Cursor cursor, Inventory inventory, int row, int column) throws Exception { Point coordinatesToRightClick = inventory.getClickCoordinatesForInventorySlot(row, column); Point clickedCoordinates = rightClickItemSlotWithRandomness(cursor, coordinatesToRightClick); diff --git a/src/DetectedObject.java b/src/DetectedObject.java index 6797d0f..c22b822 100644 --- a/src/DetectedObject.java +++ b/src/DetectedObject.java @@ -17,7 +17,6 @@ public class DetectedObject { this.detectionClass = initializeLabel(detectionClass); } - // TODO: migrate this all to a Rect2d data type private Rect2d initializeBoundingBox(float[] detectionBox) { int offset_x = (int) (detectionBox[1] * Constants.GAME_WINDOW_WIDTH); int offset_y = (int) (detectionBox[0] * Constants.GAME_WINDOW_HEIGHT); diff --git a/src/ImageCapturer.java b/src/ImageCapturer.java new file mode 100644 index 0000000..b6206dd --- /dev/null +++ b/src/ImageCapturer.java @@ -0,0 +1,17 @@ +import java.awt.AWTException; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; + +public class ImageCapturer { + + public static BufferedImage captureScreenshotGameWindow() throws AWTException { + Rectangle rectangle = new Rectangle(Constants.GAME_WINDOW_OFFSET_X, Constants.GAME_WINDOW_OFFSET_Y, Constants.GAME_WINDOW_WIDTH, Constants.GAME_WINDOW_HEIGHT); + return new Robot().createScreenCapture(rectangle); + } + + public static BufferedImage captureScreenRectangle(Rectangle rectangle) throws AWTException { + return new Robot().createScreenCapture(rectangle); + } + +} diff --git a/src/ImageCollector.java b/src/ImageCollector.java index 36dc467..921da01 100644 --- a/src/ImageCollector.java +++ b/src/ImageCollector.java @@ -99,11 +99,12 @@ public class ImageCollector { inventory.updateAndWriteAllInventoryImages(); } - public static void main(String[] args) throws Exception + /*public static void main(String[] args) throws Exception { ImageCollector imageCollector = new ImageCollector("/home/dpapp/Desktop/RunescapeAI/Images/"); imageCollector.collectImages("chatDialogue"); //imageCollector.generateInventoryImages(); //imageCollector.captureAndSaveFullWindow(); - } + }*/ + } diff --git a/src/Inventory.java b/src/Inventory.java index e29596e..cc6a05f 100644 --- a/src/Inventory.java +++ b/src/Inventory.java @@ -39,16 +39,17 @@ public class Inventory { items = new InventoryItems(Paths.INVENTORY_ITEMS_DIRECTORY_PATH); } - public void update() throws IOException { + /*public void update() throws IOException { BufferedImage image = robot.createScreenCapture(this.inventoryRectangleToCapture); updateAllInventorySlots(image); - } + }*/ public int getNumberOfItemsOfTypeInInventory(String itemType) throws IOException { int numberOfItemsOfType = 0; BufferedImage image = robot.createScreenCapture(this.inventoryRectangleToCapture); for (int row = 0; row < Constants.INVENTORY_NUM_ROWS; row++) { for (int column = 0; column < Constants.INVENTORY_NUM_COLUMNS; column++) { + inventorySlots[row][column].updateInventorySlot(image); if (inventorySlots[row][column].getItemNameInInventorySlot(items).equals(itemType)) { numberOfItemsOfType++; @@ -58,6 +59,19 @@ public class Inventory { return numberOfItemsOfType++; } + public void dropAllItemsOfType(String itemType, CursorTask cursorTask, Cursor cursor) throws Exception { + BufferedImage image = robot.createScreenCapture(this.inventoryRectangleToCapture); + for (int row = 0; row < Constants.INVENTORY_NUM_ROWS; row++) { + for (int column = 0; column < Constants.INVENTORY_NUM_COLUMNS; column++) { + + inventorySlots[row][column].updateInventorySlot(image); + if (inventorySlots[row][column].getItemNameInInventorySlot(items).equals(itemType)) { + cursorTask.dropItem(cursor, this, row, column); + } + } + } + } + public int getFirstIronOreInInventory() throws IOException { BufferedImage image = robot.createScreenCapture(this.inventoryRectangleToCapture); for (int row = 0; row < Constants.INVENTORY_NUM_ROWS; row++) { @@ -126,6 +140,8 @@ public class Inventory { return true; } + + public Point getClickCoordinatesForInventorySlot(int row, int column) { Point centerOfInventorySlot = inventorySlots[row][column].getClickablePointWithinItemSlot(); int x = Constants.INVENTORY_WINDOW_OFFSET_X + row * Constants.INVENTORY_SLOT_WIDTH + centerOfInventorySlot.x; diff --git a/src/IronMiner.java b/src/IronMiner.java index 863a0ff..0356772 100644 --- a/src/IronMiner.java +++ b/src/IronMiner.java @@ -33,7 +33,6 @@ public class IronMiner { Robot robot; HumanBehavior humanBehavior; CameraCalibrator cameraCalibrator; - RandomDetector randomDetector; MiningSuccessHistory miningSuccessHistory; ObjectDetectionHistory objectDetectionHistory; @@ -46,7 +45,6 @@ public class IronMiner { objectDetector = new ObjectDetector(); robot = new Robot(); humanBehavior = new HumanBehavior(); - randomDetector = new RandomDetector(); cameraCalibrator = new CameraCalibrator(targetNumberOfDetectedOres); miningSuccessHistory = new MiningSuccessHistory(); objectDetectionHistory = new ObjectDetectionHistory(targetNumberOfDetectedOres); @@ -54,16 +52,18 @@ public class IronMiner { public void run() throws Exception { long startTime = System.currentTimeMillis(); - int worldHopCounter = 0; int count = 0; while (((System.currentTimeMillis() - startTime) / 1000.0 / 60) < 93) { - BufferedImage screenCapture = objectDetector.captureScreenshotGameWindow(); + BufferedImage screenCapture = ImageCapturer.captureScreenshotGameWindow(); ArrayList detectedObjects = objectDetector.getObjectsInImage(screenCapture, 0.30); ArrayList ironOres = objectDetector.getIronOres(detectedObjects); readjustCameraIfObjectsAreNotBeingDetected(detectedObjects.size()); - + humanBehavior.randomlyCheckMiningXP(cursor); + RandomDetector.dealWithRandoms(screenCapture, cursor); + dropInventoryIfCloseToFull(); + DetectedObject closestIronOre = getClosestObjectToCharacter(ironOres); if (closestIronOre != null) { @@ -109,15 +109,10 @@ public class IronMiner { count++; System.out.println("Ores in inventory: " + numberOfOresInInventoryBefore + ". Mining success? " + miningSuccess); - boolean worldHopped = hopWorldsIfMiningSuccessRateIsLow(miningSuccess); - if (worldHopped) { - worldHopCounter++; - } - System.out.println(count + ", time: " + ((System.currentTimeMillis() - startTime) / 1000 / 60) + ". Hops: " + worldHopCounter); + printMiningStats(count, startTime); + + hopWorldsIfMiningSuccessRateIsLow(miningSuccess); } - humanBehavior.randomlyCheckMiningXP(cursor); - randomDetector.dealWithRandoms(screenCapture, cursor); - dropInventoryIfFull(); } } @@ -140,14 +135,24 @@ public class IronMiner { } } - private void dropInventoryIfFull() throws Exception { + /*private void dropInventoryIfFull() throws Exception { inventory.updateLastSlot(); if (inventory.isLastSlotInInventoryFull()) { cursorTask.optimizedDropAllItemsInInventory(cursor, inventory); Thread.sleep(Randomizer.nextGaussianWithinRange(1104, 1651)); } + }*/ + + private void dropInventoryIfCloseToFull() throws Exception { + if (inventory.getNumberOfItemsOfTypeInInventory("ironOre") > 15) { + inventory.dropAllItemsOfType("ironOre", cursorTask, cursor); + Thread.sleep(Randomizer.nextGaussianWithinRange(1104, 1651)); + } } + private void printMiningStats(int numberOfIronOresMined, long startTime) { + System.out.println(numberOfIronOresMined + " ores mined in " + ((System.currentTimeMillis() - startTime) / 1000 / 60) + " minutes"); + } private DetectedObject getClosestObjectToCharacter(ArrayList detectedObjects) { int closestDistanceToCharacter = Integer.MAX_VALUE; diff --git a/src/ObjectDetector.java b/src/ObjectDetector.java index 1ac0531..d22cd90 100644 --- a/src/ObjectDetector.java +++ b/src/ObjectDetector.java @@ -146,9 +146,4 @@ public class ObjectDetector { data[i + 2] = tmp; } } - - public BufferedImage captureScreenshotGameWindow() throws IOException, AWTException { - Rectangle area = new Rectangle(Constants.GAME_WINDOW_OFFSET_X, Constants.GAME_WINDOW_OFFSET_Y, Constants.GAME_WINDOW_WIDTH, Constants.GAME_WINDOW_HEIGHT); - return robot.createScreenCapture(area); - } } \ No newline at end of file diff --git a/src/PathTransformer.java b/src/PathTransformer.java index a61a18e..9150b7f 100644 --- a/src/PathTransformer.java +++ b/src/PathTransformer.java @@ -29,7 +29,7 @@ public class PathTransformer { Matrix lhs = new Matrix(lhsArray); Matrix rhs = new Matrix(rhsArray, 3); - System.out.println("(" + p1.getX() + "," + p1.getY() + "), (" + p2.getX() + "," + p2.getY() + "), (" + p3.getX() + "," + p3.getY() + ")"); + //System.out.println("(" + p1.getX() + "," + p1.getY() + "), (" + p2.getX() + "," + p2.getY() + "), (" + p3.getX() + "," + p3.getY() + ")"); Matrix ans = lhs.solve(rhs); /*System.out.println("x = " + ans.get(0, 0)); diff --git a/src/RandomDetector.java b/src/RandomDetector.java index 3dbe999..76887ca 100644 --- a/src/RandomDetector.java +++ b/src/RandomDetector.java @@ -11,13 +11,8 @@ import java.util.ArrayList; import javax.imageio.ImageIO; public class RandomDetector { - Robot robot; - public RandomDetector() throws AWTException { - robot = new Robot(); - } - - public void dealWithRandoms(BufferedImage screenCapture, Cursor cursor) throws Exception { + public static void dealWithRandoms(BufferedImage screenCapture, Cursor cursor) throws Exception { Point chatDialogueCornerPoint = findChatDialogueCornerPoint(screenCapture); Point speakerPoint = findSpeakerPointFromCornerPoint(screenCapture, chatDialogueCornerPoint); @@ -35,9 +30,9 @@ public class RandomDetector { } } - private boolean dialogueHasDismissOption(Point speakerPoint) throws IOException, AWTException { + private static boolean dialogueHasDismissOption(Point speakerPoint) throws IOException, AWTException { Rectangle dialogueRectangle = new Rectangle(Constants.GAME_WINDOW_OFFSET_X + speakerPoint.x - 25, Constants.GAME_WINDOW_OFFSET_Y + speakerPoint.y, 95, 55); - BufferedImage dialogueCapture = robot.createScreenCapture(dialogueRectangle); + BufferedImage dialogueCapture = ImageCapturer.captureScreenRectangle(dialogueRectangle); for (int x = 0; x < 95; x++) { for (int y = 0; y < 55; y++) { int pixelColor = dialogueCapture.getRGB(x, y); @@ -49,7 +44,7 @@ public class RandomDetector { return false; } - public Point findChatDialogueCornerPoint(BufferedImage screenCapture) throws AWTException, InterruptedException { + public static Point findChatDialogueCornerPoint(BufferedImage screenCapture) throws AWTException, InterruptedException { for (int x = 30; x < Constants.GAME_WINDOW_WIDTH - 30; x++) { for (int y = 20; y < Constants.GAME_WINDOW_HEIGHT - 20; y++) { int pixelColor = screenCapture.getRGB(x, y); @@ -61,14 +56,14 @@ public class RandomDetector { return null; } - private boolean isPixelChatColor(int color) { + private static boolean isPixelChatColor(int color) { int[] colorChannels = getRGBChannelsFromPixel(color); return (isColorWithinTolerance(colorChannels[0], 0, 3) && isColorWithinTolerance(colorChannels[1], 255, 3) && isColorWithinTolerance(colorChannels[2], 255, 3)); } - public Point findSpeakerPointFromCornerPoint(BufferedImage screenCapture, Point chatDialogueStart) { + public static Point findSpeakerPointFromCornerPoint(BufferedImage screenCapture, Point chatDialogueStart) { if (chatDialogueStart == null) { return null; } @@ -93,25 +88,20 @@ public class RandomDetector { return null; } - private boolean isSpeakerPointCloseToCharacter(Point speakerPoint) { + private static boolean isSpeakerPointCloseToCharacter(Point speakerPoint) { return (Math.abs(speakerPoint.x + Constants.GAME_WINDOW_OFFSET_X - Constants.CHARACTER_CENTER_X) < 90 && Math.abs(speakerPoint.y + Constants.GAME_WINDOW_OFFSET_Y - Constants.CHARACTER_CENTER_Y) < 80); } - private Point getDismissOptionClickLocation(Point speakerLocation) { + private static Point getDismissOptionClickLocation(Point speakerLocation) { return new Point(speakerLocation.x, speakerLocation.y + 46); } - private boolean isColorWithinTolerance(int color1, int color2, int tolerance) { + private static boolean isColorWithinTolerance(int color1, int color2, int tolerance) { return (Math.abs(color1 - color2) < tolerance); } - private int[] getRGBChannelsFromPixel(int pixel) { + private static int[] getRGBChannelsFromPixel(int pixel) { int[] colors = {(pixel)&0xFF, (pixel>>8)&0xFF, (pixel>>16)&0xFF, (pixel>>24)&0xFF}; return colors; } - - public BufferedImage captureScreenshotGameWindow() throws IOException, AWTException { - Rectangle area = new Rectangle(Constants.GAME_WINDOW_OFFSET_X, Constants.GAME_WINDOW_OFFSET_Y, Constants.GAME_WINDOW_WIDTH, Constants.GAME_WINDOW_HEIGHT); - return robot.createScreenCapture(area); - } } diff --git a/src/TrackerThread.java b/src/TrackerThread.java index bf4c399..a60ab87 100644 --- a/src/TrackerThread.java +++ b/src/TrackerThread.java @@ -32,7 +32,7 @@ public class TrackerThread implements Runnable { int oreLostCount = 0; while (!objectTrackingFailure && oreLostCount < 3 && !isTimeElapsedOverLimit(miningStartTime, maxTimeToMine)) { long frameStartTime = System.currentTimeMillis(); - screenCapture = objectDetector.captureScreenshotGameWindow(); + screenCapture = ImageCapturer.captureScreenshotGameWindow(); ArrayList detectedObjects = objectDetector.getObjectsInImage(screenCapture, 0.15); ArrayList ironOres = objectDetector.getObjectsOfClassInList(detectedObjects, "ironOre"); objectTrackingFailure = ironOreTracker.update(screenCapture, boundingBox); diff --git a/target/classes/CameraCalibrator.class b/target/classes/CameraCalibrator.class index 606721907a05428daffdaca81602b448d41a6128..4477ff95013d2c2dc0d015f4096b869f14f2cee9 100644 GIT binary patch delta 492 zcmb7AO-~b16g{sU9r~Qu0%HWr;#Db3A*2cgOD!LMRKbmepb5)?d8Jcl=1ty=5ZJf? z)-2|S5E7$A2y6*|h?U0YB*uj+bCdJVefOMubMJosn9}Q?-!A~vuyjHX$g+-y1o^JL zZC5=z*s8Xq6tV}y1Xu3^$s^%ybBApTKXg4ic16HKDK{HDUtr$_v;+c*HLE-Nq z);f~gj)5lT2yR6l=OKY+y{&wpFtK1@G5Mk0e6As@0-$Fot@l0phVrG#G8j~N8$@A0 z9w;?95L31bo literal 1923 zcmaJ>TUQ%Z6#fn*nKBNSLK2{9xwK%DK#7-LlpvQTrKU!x5Q0^!o+O7bCCp@ZEqYP0l2lwF1^E|*o|ZZr-{LT>J5g-c>l@zo9k%P|C{ zU9!n`DDV06BR93BBx#1wl4+UlGD9GqOB5OOdr!-v?wYpcXy|8%v^~~#3vC^lXY7j5 z(TgDieYnWb8&4Gbz%XJUh>(T|!$8~D%cdiYA!RaVK*I%w!Mte+A9#V6YJy=nZr@}e0NI-epK2ncg2q7nl-=Vb-Q6z7-r*n|L!-$mTA9suXo$7G_7hn zQPeO+h&xSf7pUVZW;9%*BF=^}FpIYtVr5=;8&YhSr4W|0Z@c%2uU*rs*hdUg@kFQ7 z<{__&)ZND3o{*xFQ@3^Rvp6G%$yGhKodFleV1Y*)iOXzd2C0nW#bar`Dw8 z$9dCn(<-R&?CL9SyfzO+FjJzz6t{M#(Y1C+=y0XjBJmZ?0RcshK@X0Fgf8+iXzB z3wGYN57up|=A*-7lVFB^$0I1?v&As+=62FdR=OWh$RM z&?mH7@eevS@tKB)^zOGj0*MJ}U<=zcHD<N)Qi zC_-nra3GE!O5r# zil|t;*2bEhgkXznyvI^kYVlO;QfyQLRqOtn2ty6-AlDQfgf zDN|h6*M_b~5VD{{Ho~z1GI9`)T#*!3AG(Pvd0fed8FoaY0CP|%ZilUww!$9{NGK8- zL$2gxRm!T2RitP$q)C;mst}B7@yyU5xe$PQOodylGZsk=tah;4$tqfm8gr!G2tgBO zV~}C%Ar6sh^%v zGV2Ua)Bz37Vmdluz&RLk5f)rR3@&3Xu3!PWgw=e7u8N1|V!9?0BF=|)BMd!A!c8p1 zEu^CxtI#VxMzs6)F}+`SBHN4uJpCQs$z7iJ9^!BxiFknd80rbNBvQsO{P399HiBt* z!Vf-06rQnlgl*4Z!wW3OOJv{`GFflL8#wV6F1+KFyhkHGU>`=&j8CF{rl7CFV$F{E zhQ<89Xh0kTk%Ck{r|`proC)W9CBNs#r&V0G#;plZd_R<)*onNahaKoczf!mI&;d*t z&kgZSr4T>)hz(5i=b9{%qZ0N`5PvE}+eChnC{Ge)eD)D#d{Kzpudw|c}PR@;rh#CWi&rD_bCPbJrB| F{0A{H%P9Z= delta 1028 zcmX|9Yfy|~6n>7~rEjgvx3$}4TT#(y6_X`&nT#1k84@O4*xF^I>+Tksp)#c*4Bi-p(&Taj30jRgCEK1YxUzh@B6&xInQ~{neW@u&Q$G_zc+3J zu+p|m+H85g7L5ocXkE4vduefDmBU5QrDcqu1cKgP=q@X=?O0Uda+kVR+B{D87}_9q z%AsZ(S7tgLF2`gWe_F~zE(fyf$U&QgSB@s9_#g-P<$Z@j$=@)qY^3=@%l(A zzmlW>p`uigW?V?=;-Im_kO4oeh8~#+!5TzjEoNYykORvN>p7FnnH-prizwt_CN_ws zz~xdtG$?=syZ9csM%v8C$*7P~m~aLqOGS)|F##pwLQtjT!f3cL79J5BoG)!>w1ZI< zqbSiGoGI;sKdLbeHNqU?mg+cH4;g#JdD9ZnACfHXW3@(B+s|rA!fr~D4l(C2bB-{l zUOLM8CeAl2`R$?hsmIyT3FvSV0cb%GS`my>n2ghyjyB9fJK}LxkhzV{iFR`VT@<=W zErt#R;ws|c#XNK(1szz1>*CI&{hFJseoJJ8?G5f`_jhLDtr)0$aKmz|kIuOS(NJJ8!qu4+ZT?OSP6s zz)#-IFGavQO!5gZ9XHUWh+6P~ry62g@Q`mRt_i1X%Hdh!RPI>3!aGb`qQBTX0j zvMe1mG1SvwZn%bh8yUz3wWq3 ziEmyi@?vTokxBMD);jo<3;n5#pDyuaDlFh=R5mrh@h@g$07<<0#YCbvVus2^ZlQ~u a6Qx$>F)CX#j?7~ukFryu3f37#mHz2BXPuITKk;8MqkCCI@p(k+fo9X0QgT ZvSAQquw{^7uxC(UaAeS6aGJy&3;+X=45I)5 diff --git a/target/classes/DetectedObject.class b/target/classes/DetectedObject.class index 27f2259ab6fed9ffd2b4e9287570601651e827f4..fdeb79aa72f9a7b71117b03d64c7471102c1b2b6 100644 GIT binary patch delta 67 zcmdlhxL0sPCYzur0|$c`g8+j#gEWH#gBpY6;a6*lY`i!8PzAR XW6x*Qo-D^v$EwfZ#$YgcA%_eArt=LR delta 67 zcmdlhxL0sPCYzub0|$dRg8+jBgEWIAgBpX>y28GFt>;a4_lY`i!88s%a XW6x*QnJmXq$7;af#$Y&kA%_eAsD%wG diff --git a/target/classes/ImageCapturer.class b/target/classes/ImageCapturer.class new file mode 100644 index 0000000000000000000000000000000000000000..871a4d99fed5442b914f77ab8cdd20298ee47638 GIT binary patch literal 763 zcmah`$xh=y5PcN_CMJX|z%VRfJtQ3P1#tl(%^*NP1QJUS$Bxs4Mv0A_4)9rUnMi}g z2k=p7s_kGD4HA8*>aMDO^sYanAdDWgL__X~JKYInU?EA!-imwSG=Q7$}vigyfE2mo^5FN@Ea1gt3b9kpS6C? z*EXh*GG;c7ITQ&6<}0*}X!nLlSTB9jjeBfn^TO<`p^7M;L1G} z&c1KFYeoYW!OP>lgDsh*v9&;QsjDugSN~wV)4XY#*!%?6F6T>lv<3O5=fsr8x HNCN=?2J#KS delta 338 zcmZus%Syvg5Ir|W+JqXkg)S|{g^G*2DY$SY)t~XU@zFD_>Q+|9yT5poWj0-Lj6%NCYuMd11HN5(k2Z zBKG)JmISf4vbdeYEko(Av3}@Eodqh+qt7tUeHBT*uZ7mUF4K0VG~evRGIfQPs}0_W zgeOyOgQ1s2lBt0=!Uoy8L7j2N@elC9cYV+&d2m$Fbxzu(noP3Sp1sdn-|t&{ zpRXOaordr4efbrDhw42M$Tw%9~C zmWn5*_C(_;J}fv42CPS?f?e3nSBuT%UFgxHo56G-G!gPfL$ML>o>Vdt8&S}UC-@Pu zm(L1rS&sn*8;=OKH4K*FWIWLrjkcx22gf@0bxkG03~qi~S2P`H8c&YJlU<>)(T1hC z!A%v0NKvlBj>(~LA{B|p3O{o?q72*Dc^3J>F(8{uf5UMbtB}$yHdudkQXTvnc}> zcu`(EwUHsMU=qP={drCuYv#Wis_R;Uf?rHytKgT?@OrMJ&MNw>lCO3V?YS96O^fKL zS;QXRl)t&@5xC&TV|WxzbU1dxhaNPbnhx3)$n@U_C+$!_eb|d9sj`m7KGf4_r2S9f zY5q;VW4fRH4T-sQe_|Ew8AOQI3+XA5X3yY0ita*!p2h)^P({B77tyj&)YP^LemRW| zno7xMm3<}RvS@9(LiBkU*VTHgl2u;BaPJA3S!I*{(m&JRosgJSqUh#Tsv+P3`mZJ} zz*ZCxUlAHnLX0kKr`Zm))4ZFae!4#@ZEHqbmUdu?mh|EPMu|p^qBuyo3$R<|CN>j- z*g#%LE)-LtjTFjcA7FuW7e#txY^htaC5AZvBj4d{2?(3hs28@RQKLfJeE0jPBU+o( zIK!LZP0BiZ0P3waQ=wvXpc0+*2G~V4f&{V?0d(`T%4$Jv!xg2fP^~922i40X<5T=6 zrFvUSz*BPrf-jC1cO#?A6YrVA2P09l_|zB z#XF7FJuQJ6%d@v|bg$*u4IICT=X+IxQ@O`2TCD>_FbW%W#ZG<6QB-CrinA2zJ^aB~ z$6n_5jCOB=C=L-t5^HF*BLO$YS5SDe6dsKtSXe9U!W=(VSZ?X~B5R~f1_6`&^Fp_9 z24}V9#Ap9oKB_IhhI#HcRg@;qLocKuit4t^G0kK-&f})F0;g^BCKpTaTPA1849Pr6 zGEWiYEXpZ%Vg_EE=6{*C2?7A8c2l7wbYV}`UcL$%lzCoK|MmJ*7kEulb~iV203O{m(< z?!_KA+-CFzAM9wyS{#{iruEI4j<5Qre}KOD=4kcg1`BrX%x}5p{Lc5C@0@clc;9FK z;o-O60oaC*Z<~J-?aHa~;Y@MF3=j6G*o!s_Nc&9!+Et{`L2;!{@Y0geEr!!HFNf(D zu_d$>Jt_{MLqJvebz6RFBws8{%=U~Gie_v@T16iY(mg3z{~`vAI3&P!A~ThVk7e@N zcu#R6m(Qv=j3eZi`y?Zd(Py%kJ~j9i{(T%ddSKY?8B_6c3B*+fNo6LB{{x~n#qS;$ zAdTm)+%)1%0h%5>GhK{#7IOKb3PQ60VWt9$cw5Cg z`fb*XMf%y){?$_zL6HVDzbBcBL|5>_ZI)bwpH~eMuTiMj0y|>#iRQBG!+vlqbfSyW zmVl6?1xrnJcjOKlopQoyNbsrkE_$PP(NDK5JDl4P!qeD^CbY8J9Y`RJ?eveu3-!FZwu3Yj%n{iHFlu^ySa~A@eJRe=l?0z+p4*w5?)x_Y%Sr*f{*b`jCX<# zX@NC8UV2=Qb`G54z#SX(5cLlHUW*Ie^oQn+cfx=!n9bTSon6jpJv-!Zv@Q{P~! zuT;PJ_2&*9Yk>J4Mjej8i=#S+YCUYj8V8j*mII4=f3@2hg;#08=8X?=7RNY?VLZXR z7efdmyCI9nqbwqN77uJOsSjuAZ(F^i_e*A8ZX<;i1#23!hoy5kubW3df6ScM%@^Sw8v~_$K=- diff --git a/target/classes/IronMiner.class b/target/classes/IronMiner.class index 9832e161edf11d8f97ded6dff3369592088ac578..81a6e419cd913180f7b4724b02783c2dd9588ec9 100644 GIT binary patch literal 6821 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 OmZd6ga!$>Z^ZyUqq0mwQ literal 6898 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 diff --git a/target/classes/RandomDetector.class b/target/classes/RandomDetector.class index 5fdd8515dfa36e9e08528ade9ea215e56824be31..4bc579227129d2184937b7b79d6244e0df14c674 100644 GIT binary patch literal 3767 zcmai0TW}Ov8U9Y@mW&!3J0|Gb95G8<3DJFaa{z3Bg;sk-Ou3fjlUDhnKKW#ozWC&WZ&qy~@jItyCc~0-sW5%I z&)@&$`@a7_{l_Q2{w;uG_-Oz&0^3H7T*h7;FdZ}P*!cjw0{RW(mJ!byx%v3W>5NPYcoTNU48nst4Lee zSLPEuw~{uO9LvrX0@xwYuvtN6CkTN?4PopQXqmHenZ$zO3|L0io?kW-c0On3FWFX( z#UB2Y$dS#&)Em9h^)3y&(JZh>x*l6HjhiKZ=kxaBQ|?cHiu;dy-!fdQhBmYdv|EMh zV2P|=Zq6)_;Qh}yPbQzK)qnc^ zKU1!N|MbtiY7s;?4hIk?>#kO;+h$(F5xgMKlrvYH3&wJxU>P|X&&tteo^tec4h%$+ zLF&FIfESt+2tFUMl3L{E! z(x^{EzXY(206w*ukSNGbklK_`oz`#$XE&irnRAXZ`oB;e*aE6&vGOT=;Qx~>^SmtR zf-HO}8JP?qNqQ^&r05M|5HHLAO-U`Qtt~~CoYKN`B48q121E5@6 zE7@;hry&pao1fwwy+G|Lve^p)%NlOs6?TJFxMZ!ESve9DcGl+H@OCC6mjyy)*;kU{ z6y4;c@>GrR@-QuHA-JTRN{0cwMs27p)xna?aXRIfmmD)w;X!8fhK4us78T(p%YA6dSe+P6d@x2CZp(Ip>U7jFB>)-EORQcGg~*vNFy>5Z}gk0(h_7 zg$jgW!&%VqU3`z{sxeE7Bt@8i4*UVYI=sQm>OH3;%oZUgoB41YD(fY*B7 z)nOa9(@N*s%bk#N^DnxTml~|{SR?qsu7V! z#ER&8yNILQ|Li?l2SKq&Mn~4>3F? zbM>fPyH%DtGYE0jfSqVW2haUDn$Uw?Nb;Z_MKdPQ3JZIbb=1ukm+(3IVcxVDV>LdQ z7^h_ot*&E|D-Wi)uc79@m zGx`Kqvord2{rDr8Db~I)?CD=e#M9$l$L>RIVedoadVFDD5zamMydSK3McAt!U)%WS zsziK|<-GZa4><)eq>|>$(c@`f)7oKOa2YD=Y;xzAv_g}i2(XBW3t)o5K(#ksf+fsghhyx5M|C-?FlpCRI#O4oBi5`{GSvQNwF@a}lqnVxDe~zlg8g!=9M8JA@7Q zW=G7oc|+Q&INC|vfK&YKW2^KN^_PfkpGs5$M$h;flVax~g0JHa<4U2`f(ac8;2oyT z?@KouF-9K#_w9CvrLbdvOD#2>$(n4_W4ZN!;tjBBk23H=Ed0r9hWm`uS!4k=OMX;Y15qy)sUWMvz z)cT)byATAoR_r9(p^s4i7~LG5^1Hf3`ZW?G=U!BHu0B5#5}8a9-_kGN$1d5z`ov5K z|51-F-Isk@MYuaLuc|WKi5V?5oTSwQ(aBK!Xe@>5Bcn1@gG5+{Q~tXZxO`kag=eaK zHsE~%0=nW!SaKz&l^pHcnpg2VBWSw&90d)hM`_t;P^M zm`fq%nXS}pJn);~w5OR3@cPKKw^^^f?Jj-Ix?WoPoAq7pG8L0O>{b#~uP<;+St<{= W1>*RT%Api^l8 literal 4145 zcmai1-BT3V9X*$so`%^LdW2CC@N0F$3?nFUaaYt;z>jf36cD1Wk!GfW)?u2R?orny zyPGVV&t0=gHXr6=6UM`|3j*_jO5(g!!Rlv3z)gx zefxLMIluG!-OHaJ{^s`p_TfVvRRXm`RzB;_^x3|h@!f)suz-2Rx@L9cto&5R;KUW) z7tjjsgv)QUUp=#~`yE5_PPahhpp$p}!vdk!#Hc{@*o}-m>pO1V)A5Wzy!^t^v61pK zfpD*zwWA23)_{&`9VWq)=c?dQ)Sk<%CBha1Td-B2Y0}AOd#5eG&#`juRMGBr3wgV6#&z;kZ_iT}ORQp1 zZ*|~Nyx`6}68^|j!ap8;&E<9(cn+Tt*y4DVi}mJQ&mM6} ztzcz*yFe)_RtwN3E<}+)n~o%15$I+hh22c-l#_BMz2YUtD zX54G`(R_BunVR-r14gIE0sUunH=Q zXJooyTUi4~aFp}BoNdq2_pPTAqcX3(2KuDXo3bUVoV2_?$D46HZ&1~boOIm42`OL; z1$^XTuT(*rUsjrwDsA8tUS5@|-=6f#Vb;K_ko86SbocP1 zD(tIB*wD&S-4*U$OPeTsT+>k$XfESiW1fNQAkYZCHguw=lsj5m;HH5u;EOc3Y%0u8GfE8kU3c%?V4q&7OMg35q8zQR( zMWp~eL&WLB)}>Q z2Au*m{whyR>Adogahftg3IdaP(=L15j6KGU#=S1Et@SCsA`puvWy2hHi-nAR+>v{7 zeb7Bujuh=Onb^*ph1f;}|G1a)^BIo0@uLbgybALw3WK8_&XcpuV%>LBO{!PXLJGodE18C@K` zgcgkOC~*l}F;3BZ>{Rsj1;9)6NCD?@K~XN^B3>cY2wcAPd9G2*o^zR_Fe6A|s{V^{ z9cTGl&w1Q)O2S0=Z3UtW`M%ECm+m7&ar3gde+jvPPpTc}H0K-2DcIIbxv}fktMu#8(R3IIZebhbN~GEzvsdt9yTw}FaJIC5f=y~ zNOD;aNDEqd+DPz_kVGfiaFC;8*v&mJ$zGWtwY`e|$pBoL{v}0_+akB3FX43(d5)X+ z8o9hCH)Q_oY-tB-9bwJCPxt^NgUckq;zC-_~HRH(NOgXO~}4O)dM?9ZKC+H zGUOi^O4{a-x#iFT_L>cc7qGppxkYjgC*$-DIj@r`Z*F12@6LrpOH6dlFaL9{N;JpB zzvh?!BJP&C@1W;_=ZU3@;rG)LFObKJRHKV*pGP<%i0g50z3L;(WvC#lbnUmOY25eFyIn_Bdx%gYfp~ zL?h(sHozvP7*~pOEA=O0znh{957TP$TUzY^2ToUH0bASRTAWqqb?M2tuJo^oYjWyb zM8qR6?Y?{-j zq2J+^)aez~_HLDRx>c^|TlhAsw~EoT0oxPKbSi+6QRoekRZOf#?iZ#UCIki{6|XkBMyd9=>N@ zxPwiy`pt9WG5kl}I&(+Xc7+ili~%+gNoYe5rA#PUs?l*iV@Gf0V;*Hoi=H4xxoEvq zT`sIvYFC2ucF^a8=ypZ)`f~Jo+@?s93AgrA(966E^X=NEW(l`tZM2Sxmkef>@2dOp;|x_N!@e7MQ1z8MU)Cethp zBTeR}U^tMHeIQ^LRcp*plDt9`6i!DOQ3rme5bfr?4^-g@{2agFmE12Ynm5fRuOKZf to40w6c8`fu?AZOXV{@}}A78e>y7elAZ7MChp26qYPB5{{z~tk>CIT diff --git a/target/classes/RandomDetectorTest.class b/target/classes/RandomDetectorTest.class index de44f653eb136af10a7517d98fa084dea0871883..4a78244fd7c6bf6d04c14dada931e41a10ec19f3 100644 GIT binary patch delta 165 zcmWlSy$XV0002)?`<4paK1ec&2*rjF2c@=#{-D*Np{=HVX{;BB2wd_B8fy}#-k~?j zrW+3K9>(2x-^!6hMF1Bk!*UEeqZNnhXHe=tSxL3to4OgDl-SMbhMLrJ{7{#g)br$9 zo+xQz3VY^Z63`&RVn~xQHYX%!+Ej|VkM@61rB+a~V8a%ruyc0o3+plBz!9Awxe8lZ ICNHu60epxZ&j0`b delta 173 zcmXAitqQ_W07lPnn=2{|L@p?9LqsMBifQ1=qOO=U8VpO$pKKCsqO9l>tQzEEvinwE zF?}B#4(DRu?8mtnx#(EH$(K03?MYhmK!1mYQBErK`e4$PbnYy=FM5IDKdA{rG7QZB z6{gHS#j$qHs+Je`X%NyR!Xd_GipL(okv1h&8Djiel&Po{ELoAFDLP}#M$x|Vw(Kwo MvxDVnNtRp57u)b482|tP diff --git a/target/classes/TrackerThread.class b/target/classes/TrackerThread.class index 3a6e9c65d35827b787fadd9d890c8a3e5b04532d..d1b75f2b839c12b3014d035d81e7591a7221747f 100644 GIT binary patch delta 853 zcmX|6i$>Db(X_0|luZrmb%Q&Ux4}TgQprRp z70slYI-5;w)^FVVJzH$HQm_4HjaAJyo9*n-aWm=JWz)!R{oS0qqKSQqy#~|T!kyt@ zEE%i~t?i0LJJPXa!e&3Y29r8cu|&Ed9gf7erNR+u5_U)j_3Dh7o@NI|U+&9zZWyO@ zj+$kh)&W)JJ#VA16c=>6@>v61wwc5geN8R)3~Mg9?IXM1s z7~keaqwE=GvSSYnV>veR0yh?Sc|g;I9g;&h`zJK(kKVGrl@w9OJh_)*nwd|E1srD~ z-2^yEDW@rv?4=A+#*j?w5f#F%WQ65BWfguAeVrUfIt9!YYw?&vv|x}&Kdr=Ykxwse z#6?RHM>tG78PY33qK_mVX%(kKkYbS#j!4*I85>1R9IwbL=O}5iMC5#q39?0wNv8;P ziy#Me2^yI|Cj@nijOo($AG7B_vqzY{5?h5DXNfbWDnoHnQEVFWz!-I=qEFu6xW<`* zOW|ZVOH+*^EMK!Jm7U+HBx~JzBlRNhr zU*J6hje)5b-*D+Q=N#uKSM~d>B|%4=(EXBrUFa@uh{KfK&51%4f}BFuKhAAE(+;S+ I;&5^AFMZyw=>Px# delta 826 zcmX|<%TE(g6vltkPJ3ry1QpSu#YjMrf`UOI5HT)Pe1m`w5Jad|0i{qYs3;Gu@3&VM z8ckeaNQ}ndqZ&=zn&85XD_8nA7!y|D8BCna-1FUY&iCE#=FE@4*Feg|)W^@jY95TI z{PLuw)wFj;!to7}xU5k<>8Z2UvcX{^oAhCCP3C3;)e(z!*TfxW& zLk+dM*sK;tokKkhdeDse_c-ijpZ;y;`kQE0?AJkGAiITm2I)Pqj_!DUye-_-5NivI zVyoM6Q19|B^tZb({HE9U$}rCA9JR!SM^i1 z(x2eE!-)Q_mKeA7AC)VKyAJpCV(X_}fypen?`y5>VrTCM3d`+K=q*`Ez0MA1S0~w0 z=@dyKvoOhyGQV5Oath~4VVCZ=bINx=oPIP$VCRY?jbqGq#+Inup~CzLWOBY8%daLai~1>;l^ z6yvu@bM2GOVu=>dIYb15OfGYnBY4PSSkybjOCBfbqzj*%730_t$MMTiQMv^wR&Y#k zmx!#9(e(($7JIAdmF842na>G9j@U7Yi