PageRenderTime 142ms CodeModel.GetById 16ms app.highlight 109ms RepoModel.GetById 2ms app.codeStats 0ms

/src/jd/captcha/JAntiCaptcha.java

https://bitbucket.org/jorgenio/jdownloader
Java | 2022 lines | 1479 code | 249 blank | 294 comment | 391 complexity | c7b1cfed3d209b39158660b898c3aa15 MD5 | raw file
   1//    jDownloader - Downloadmanager
   2//    Copyright (C) 2008  JD-Team support@jdownloader.org
   3//
   4//    This program is free software: you can redistribute it and/or modify
   5//    it under the terms of the GNU General Public License as published by
   6//    the Free Software Foundation, either version 3 of the License, or
   7//    (at your option) any later version.
   8//
   9//    This program is distributed in the hope that it will be useful,
  10//    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12//    GNU General Public License for more details.
  13//
  14//    You should have received a copy of the GNU General Public License
  15//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16
  17package jd.captcha;
  18
  19import java.awt.Color;
  20import java.awt.Graphics;
  21import java.awt.GridBagLayout;
  22import java.awt.GridLayout;
  23import java.awt.Image;
  24import java.awt.event.ActionEvent;
  25import java.awt.event.ActionListener;
  26import java.awt.image.BufferedImage;
  27import java.io.File;
  28import java.io.FileFilter;
  29import java.io.IOException;
  30import java.lang.reflect.Method;
  31import java.util.ArrayList;
  32import java.util.Collections;
  33import java.util.Comparator;
  34import java.util.ListIterator;
  35import java.util.Vector;
  36import java.util.logging.Logger;
  37
  38import javax.imageio.ImageIO;
  39import javax.swing.ImageIcon;
  40import javax.swing.JButton;
  41import javax.swing.JCheckBox;
  42import javax.swing.JDialog;
  43import javax.swing.JFrame;
  44import javax.swing.JLabel;
  45import javax.swing.JOptionPane;
  46import javax.swing.JPanel;
  47import javax.swing.JScrollPane;
  48import javax.swing.JTextArea;
  49
  50import jd.captcha.configuration.JACScript;
  51import jd.captcha.gui.BasicWindow;
  52import jd.captcha.gui.ImageComponent;
  53import jd.captcha.gui.ScrollPaneWindow;
  54import jd.captcha.pixelgrid.Captcha;
  55import jd.captcha.pixelgrid.Letter;
  56import jd.captcha.utils.Utilities;
  57import jd.controlling.JDLogger;
  58import jd.gui.userio.DummyFrame;
  59import jd.http.Browser;
  60import jd.nutils.Executer;
  61import jd.nutils.JDHash;
  62import jd.nutils.io.JDIO;
  63import jd.utils.JDUtilities;
  64
  65import org.appwork.utils.Regex;
  66import org.appwork.utils.os.CrossSystem;
  67import org.w3c.dom.Document;
  68import org.w3c.dom.Element;
  69import org.w3c.dom.NamedNodeMap;
  70import org.w3c.dom.Node;
  71import org.w3c.dom.NodeList;
  72
  73/**
  74 * Diese Klasse stellt alle public Methoden zur captcha Erkennung zur Verfügung.
  75 * Sie verküpft Letter und captcha Klassen. Gleichzeitig dient sie als
  76 * Parameter-Dump.
  77 * 
  78 * @author JD-Team
  79 */
  80public class JAntiCaptcha {
  81
  82    /**
  83     * Logger
  84     */
  85    private static Logger logger = Utilities.getLogger();
  86
  87    /**
  88     * Testet die Angegebene Methode. Dabei werden analysebilder erstellt.
  89     * 
  90     * @param file
  91     */
  92    public static void testMethod(File file) {
  93        int checkCaptchas = 20;
  94        String code;
  95        String inputCode;
  96        int totalLetters = 0;
  97        int correctLetters = 0;
  98        File captchaFile;
  99        Image img;
 100        String methodName = file.getName();
 101        File captchaDir = new File(file.getAbsolutePath() + "/captchas");
 102        if (Utilities.isLoggerActive()) {
 103            logger.info("Test Method: " + methodName);
 104        }
 105        new JAntiCaptcha(methodName);
 106        File[] entries = captchaDir.listFiles(new FileFilter() {
 107            public boolean accept(File pathname) {
 108                // if(Utilities.isLoggerActive())logger.info(pathname.getName(
 109                // ));
 110                if (pathname.getName().endsWith(".jpg") || pathname.getName().endsWith(".png") || pathname.getName().endsWith(".gif")) {
 111
 112                    return true;
 113                } else {
 114                    return false;
 115                }
 116            }
 117
 118        });
 119        ScrollPaneWindow w = new ScrollPaneWindow();
 120        w.setTitle(" Test Captchas: " + file.getAbsolutePath());
 121
 122        w.resizeWindow(100);
 123        if (Utilities.isLoggerActive()) {
 124            logger.info("Found Testcaptchas: " + entries.length);
 125        }
 126        int testNum = Math.min(checkCaptchas, entries.length);
 127        if (Utilities.isLoggerActive()) {
 128            logger.info("Test " + testNum + " Captchas");
 129        }
 130        int i = 0;
 131        for (i = 0; i < testNum; i++) {
 132            captchaFile = entries[(int) (Math.random() * entries.length)];
 133
 134            logger.info("JJJJJJJJ" + captchaFile);
 135            img = Utilities.loadImage(captchaFile);
 136            w.setText(0, i, captchaFile.getName());
 137            w.setImage(1, i, img);
 138
 139            w.repack();
 140
 141            JAntiCaptcha jac = new JAntiCaptcha(methodName);
 142            // BasicWindow.showImage(img);
 143            Captcha cap = jac.createCaptcha(img);
 144            if (cap == null) {
 145                if (Utilities.isLoggerActive()) {
 146                    logger.severe("Captcha Bild konnte nicht eingelesen werden");
 147                }
 148                continue;
 149            }
 150
 151            w.setImage(2, i, cap.getImage());
 152            // BasicWindow.showImage(cap.getImageWithGaps(2));
 153            code = jac.checkCaptcha(captchaFile, cap);
 154            w.setImage(3, i, cap.getImage());
 155
 156            w.setText(4, i, "JAC:" + code);
 157
 158            w.repack();
 159
 160            inputCode = JOptionPane.showInputDialog("Bitte Captcha Code eingeben", code);
 161
 162            w.setText(5, i, "User:" + inputCode);
 163            w.repack();
 164            if (code == null) {
 165                code = "";
 166            }
 167            if (inputCode == null) {
 168                inputCode = "";
 169            }
 170            code = code.toLowerCase();
 171            inputCode = inputCode.toLowerCase();
 172            for (int x = 0; x < inputCode.length(); x++) {
 173                totalLetters++;
 174
 175                if (inputCode.length() == code.length() && inputCode.charAt(x) == code.charAt(x)) {
 176                    correctLetters++;
 177                }
 178            }
 179            if (Utilities.isLoggerActive()) {
 180                logger.info("Erkennung: " + correctLetters + "/" + totalLetters + " = " + Utilities.getPercent(correctLetters, totalLetters) + "%");
 181            }
 182        }
 183        w.setText(0, i + 1, "Erkennung: " + Utilities.getPercent(correctLetters, totalLetters) + "%");
 184        w.setText(4, i + 1, "Richtig: " + correctLetters);
 185        w.setText(5, i + 1, "Falsch: " + (totalLetters - correctLetters));
 186        JOptionPane.showMessageDialog(new JFrame(), "Erkennung: " + correctLetters + "/" + totalLetters + " = " + Utilities.getPercent(correctLetters, totalLetters) + "%");
 187    }
 188
 189    /**
 190     * Führt einen Testlauf mit den übergebenen Methoden durch
 191     * 
 192     * @param methods
 193     */
 194    public static void testMethods(File[] methods) {
 195        for (File element : methods) {
 196            JAntiCaptcha.testMethod(element);
 197        }
 198
 199    }
 200
 201    /**
 202     * Fenster die eigentlich nur zur Entwicklung sind um Basic GUI Elemente zu
 203     * haben
 204     */
 205    private BasicWindow              bw2;
 206
 207    private BasicWindow              bw3;
 208
 209    private JDialog                  f;
 210
 211    /**
 212     * Bildtyp. Falls dieser von jpg unterschiedlich ist, muss zuerst
 213     * konvertiert werden.
 214     */
 215    private String                   imageType;
 216
 217    /**
 218     * jas Script Instanz. Sie verarbneitet das JACScript und speichert die
 219     * Parameter
 220     */
 221    public JACScript                 jas;
 222    /**
 223     * Vector mit den Buchstaben aus der MTHO File
 224     */
 225    public ArrayList<Letter>         letterDB;
 226
 227    private int[][]                  letterMap    = null;
 228
 229    /**
 230     * Anzahl der Buchstaben im Captcha. Wird aus der jacinfo.xml gelesen
 231     */
 232    private int                      letterNum;
 233
 234    /**
 235     * ordnername der methode
 236     */
 237    private String                   methodDirName;
 238
 239    private boolean                  showDebugGui = false;
 240
 241    private Vector<ScrollPaneWindow> spw          = new Vector<ScrollPaneWindow>();
 242
 243    private Captcha                  workingCaptcha;
 244
 245    private boolean                  extern;
 246
 247    public boolean isExtern() {
 248        return extern;
 249    }
 250
 251    private String command;
 252
 253    private String dstFile;
 254
 255    private String srcFile;
 256
 257    private Image  sourceImage;
 258
 259    public JAntiCaptcha(String methodName) {
 260        JACMethod method = JACMethod.forServiceName(methodName);
 261        if (method == null) {
 262            logger.severe("no such method found! " + methodName);
 263            return;
 264        }
 265        methodDirName = method.getFileName();
 266
 267        getJACInfo();
 268
 269        jas = new JACScript(this, methodDirName);
 270        long time = System.currentTimeMillis();
 271        loadMTHFile();
 272
 273        time = System.currentTimeMillis() - time;
 274        System.out.println(time);
 275        if (Utilities.isLoggerActive()) {
 276            logger.fine("letter DB loaded: Buchstaben: " + letterDB.size());
 277        }
 278    }
 279
 280    /**
 281     * prüft den übergebenen Captcha und gibt den Code als String zurück. Das
 282     * lettersarray des Catchas wird dabei bearbeitet. Es werden decoedvalue,
 283     * avlityvalue und parent gesetzt WICHTIG: Nach dem Decoden eines Captcha
 284     * herrscht Verwirrung. Es stehen unterschiedliche Methoden zur Verfügung um
 285     * an bestimmte Informationen zu kommen: captcha.getDecodedLetters() gibt
 286     * Die letter aus der datenbank zurück. Deren werte sind nicht fest. Auf den
 287     * Wert von getvalityvalue und getValityPercent kann man sich absolut nicht
 288     * verlassen. Einzig getDecodedValue() lässt sich zuverlässig auslesen
 289     * captcha.getLetters() gibt die Wirklichen Letter des captchas zurück. Hier
 290     * lassen sich alle wichtigen Infos abfragen. z.B. ValityValue,
 291     * ValityPercent, Decodedvalue, etc. Wer immer das hier liest sollte auf
 292     * keinen fall den fehler machen und sich auf Wert aus dem getdecodedLetters
 293     * array verlassen
 294     * 
 295     * @param captcha
 296     *            Captcha instanz
 297     * @return CaptchaCode
 298     */
 299    public String checkCaptcha(File file, Captcha captcha) {
 300        if (extern) return callExtern();
 301        workingCaptcha = captcha;
 302        // Führe prepare aus
 303        jas.executePrepareCommands(file, captcha);
 304        Letter[] letters = captcha.getLetters(getLetterNum());
 305        if (letters == null) {
 306            captcha.setValityPercent(100.0);
 307            if (Utilities.isLoggerActive()) {
 308                logger.severe("Captcha konnte nicht erkannt werden!");
 309            }
 310            return null;
 311        }
 312        String ret = "";
 313        double correct = 0;
 314        LetterComperator akt;
 315
 316        // Scannen
 317        Vector<LetterComperator> newLettersVector = new Vector<LetterComperator>();
 318        for (int i = 0; i < letters.length; i++) {
 319            letters[i].setId(i);
 320            if (letters[i].detected != null) {
 321                akt = letters[i].detected;
 322            } else {
 323                akt = getLetter(letters[i]);
 324            }
 325            akt.getA().setId(i);
 326
 327            newLettersVector.add(akt);
 328
 329        }
 330        if (letters.length > getLetterNum()) {
 331            // sortieren
 332            Collections.sort(newLettersVector, new Comparator<LetterComperator>() {
 333                public int compare(LetterComperator obj1, LetterComperator obj2) {
 334
 335                    if (obj1.getValityPercent() < obj2.getValityPercent()) { return -1; }
 336                    if (obj1.getValityPercent() > obj2.getValityPercent()) { return 1; }
 337                    return 0;
 338                }
 339            });
 340
 341            // schlechte entfernen
 342            if (Utilities.isLoggerActive()) {
 343                logger.info(getLetterNum() + "");
 344            }
 345
 346            if (!jas.getBoolean("autoLetterNum")) {
 347                for (int i = newLettersVector.size() - 1; i >= getLetterNum(); i--) {
 348                    newLettersVector.remove(i);
 349                }
 350            }
 351            // Wieder in die richtige reihenfolge sortieren
 352            Collections.sort(newLettersVector, new Comparator<LetterComperator>() {
 353                public int compare(LetterComperator obj1, LetterComperator obj2) {
 354
 355                    if (obj1.getA().getId() < obj2.getA().getId()) { return -1; }
 356                    if (obj1.getA().getId() > obj2.getA().getId()) { return 1; }
 357                    return 0;
 358                }
 359            });
 360        }
 361
 362        if (getJas().getString("useLettercomparatorFilter") != null && getJas().getString("useLettercomparatorFilter").length() > 0) {
 363            String[] ref = getJas().getString("useLettercomparatorFilter").split("\\.");
 364            if (ref.length != 2) {
 365                captcha.setValityPercent(100.0);
 366                if (Utilities.isLoggerActive()) {
 367                    logger.severe("useLettercomparatorFilter should have the format Class.Method");
 368                }
 369                return null;
 370            }
 371            String cl = ref[0];
 372            String methodname = ref[1];
 373
 374            Class<?> newClass;
 375            try {
 376                newClass = Class.forName("jd.captcha.specials." + cl);
 377
 378                Class<?>[] parameterTypes = new Class[] { newLettersVector.getClass(), this.getClass() };
 379                Method method = newClass.getMethod(methodname, parameterTypes);
 380                Object[] arguments = new Object[] { newLettersVector, this };
 381                Object instance = null;
 382                method.invoke(instance, arguments);
 383
 384            } catch (Exception e) {
 385                if (Utilities.isLoggerActive()) {
 386                    logger.severe("Fehler in useLettercomparatorFilter:" + e.getLocalizedMessage() + " / " + getJas().getString("useLettercomparatorFilter"));
 387                }
 388                JDLogger.exception(e);
 389            }
 390
 391        }
 392        for (int i = 0; i < newLettersVector.size(); i++) {
 393            akt = newLettersVector.get(i);
 394
 395            if (akt == null || akt.getValityPercent() >= 100.0) {
 396                ret += "-";
 397                correct += 100.0;
 398            } else {
 399                ret += akt.getDecodedValue();
 400
 401                akt.getA().setId(i);
 402                correct += akt.getValityPercent();
 403
 404            }
 405            // if(Utilities.isLoggerActive())logger.finer("Validty: " +
 406            // correct);
 407        }
 408        if (newLettersVector.size() == 0) {
 409            captcha.setValityPercent(100.0);
 410
 411            return null;
 412        }
 413        captcha.setLetterComperators(newLettersVector.toArray(new LetterComperator[] {}));
 414
 415        if (Utilities.isLoggerActive()) {
 416            logger.finer("Vality: " + (int) (correct / newLettersVector.size()));
 417        }
 418        captcha.setValityPercent(correct / newLettersVector.size());
 419        return ret;
 420    }
 421
 422    /**
 423     * Exportiert die aktelle Datenbank als PNG einzelbilder
 424     */
 425    public void exportDB() {
 426        File path = Utilities.directoryChooser();
 427
 428        File file;
 429        BufferedImage img;
 430        int i = 0;
 431        for (Letter letter : letterDB) {
 432
 433            img = letter.getFullImage();
 434            file = new File(path + "/letterDB/" + i++ + "_" + letter.getDecodedValue() + ".png");
 435            file.mkdirs();
 436
 437            try {
 438                logger.info("Write Db: " + file);
 439                ImageIO.write(img, "png", file);
 440            } catch (IOException e) {
 441                JDLogger.exception(e);
 442            }
 443        }
 444    }
 445
 446    private BufferedImage toBufferedImage(Image i) {
 447        if (i instanceof BufferedImage) { return (BufferedImage) i; }
 448        Image img;
 449        img = new ImageIcon(i).getImage();
 450        BufferedImage b;
 451        b = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
 452        Graphics g = b.createGraphics();
 453        g.drawImage(img, 0, 0, null);
 454        g.dispose();
 455        return b;
 456    }
 457
 458    private String callExtern() {
 459        try {
 460            File file = JDUtilities.getResourceFile(this.srcFile);
 461            file.getParentFile().mkdirs();
 462            String ext = CrossSystem.getFileExtension(file.getName());
 463            ImageIO.write(toBufferedImage(this.sourceImage), ext, file);
 464        } catch (Exception e) {
 465            JDLogger.exception(e);
 466            return null;
 467        }
 468        Executer exec = new Executer(JDUtilities.getResourceFile(this.command).getAbsolutePath());
 469        exec.setRunin(JDUtilities.getResourceFile(this.command).getParent());
 470        exec.setWaitTimeout(30);
 471        exec.start();
 472        exec.waitTimeout();
 473        // String ret = exec.getOutputStream() + " \r\n " +
 474        // exec.getErrorStream();
 475
 476        String res = JDIO.readFileToString(JDUtilities.getResourceFile(this.dstFile));
 477        if (res == null) return null;
 478        return res.trim();
 479
 480    }
 481
 482    /**
 483     * Gibt den erkannten CaptchaText zurück
 484     * 
 485     * @param captchafile
 486     *            Pfad zum Bild
 487     * @return CaptchaCode
 488     */
 489    public String checkCaptcha(File captchafile) {
 490        if (Utilities.isLoggerActive()) {
 491            logger.finer("check " + captchafile);
 492        }
 493        Image captchaImage = Utilities.loadImage(captchafile);
 494        Captcha captcha = createCaptcha(captchaImage);
 495        if (captcha != null) captcha.setCaptchaFile(captchafile);
 496        // captcha.printCaptcha();
 497        return checkCaptcha(captchafile, captcha);
 498    }
 499
 500    /**
 501     * Factory Methode zur Captcha erstellung
 502     * 
 503     * @param captchaImage
 504     *            Image instanz
 505     * @return captcha
 506     */
 507    public Captcha createCaptcha(Image captchaImage) {
 508        this.sourceImage = captchaImage;
 509        if (extern) return null;
 510        if (captchaImage.getWidth(null) <= 0 || captchaImage.getHeight(null) <= 0) {
 511            if (Utilities.isLoggerActive()) {
 512                logger.severe("Image Dimensionen zu klein. Image hat keinen Inahlt. Pfad/Url prüfen!");
 513            }
 514            return null;
 515        }
 516        Captcha ret = Captcha.getCaptcha(captchaImage, this);
 517        if (ret == null) { return null; }
 518        ret.setOwner(this);
 519        return ret;
 520    }
 521
 522    /**
 523     * Aus gründen der geschwindigkeit wird die MTH XMl in einen vector
 524     * umgewandelt
 525     */
 526    private void createLetterDBFormMTH(Document mth) {
 527        letterDB = new ArrayList<Letter>();
 528        long start1 = System.currentTimeMillis();
 529        try {
 530
 531            if (mth == null || mth.getFirstChild() == null) { return; }
 532            NodeList nl = mth.getFirstChild().getChildNodes();
 533            Letter tmp;
 534            for (int i = 0; i < nl.getLength(); i++) {
 535                // Get child node
 536                Node childNode = nl.item(i);
 537                if (childNode.getNodeName().equals("letter")) {
 538                    NamedNodeMap att = childNode.getAttributes();
 539
 540                    tmp = new Letter();
 541                    tmp.setOwner(this);
 542                    String id = JDUtilities.getAttribute(childNode, "id");
 543                    if (!tmp.setTextGrid(childNode.getTextContent())) {
 544
 545                        logger.severe("Error in Letters DB line: " + i + ":" + childNode.getTextContent() + " id:" + id);
 546                        continue;
 547                    }
 548
 549                    if (id != null) {
 550                        tmp.setId(Integer.parseInt(id));
 551                    }
 552                    tmp.setSourcehash(att.getNamedItem("captchaHash").getNodeValue());
 553                    tmp.setDecodedValue(att.getNamedItem("value").getNodeValue());
 554                    tmp.setBadDetections(Integer.parseInt(JDUtilities.getAttribute(childNode, "bad")));
 555                    tmp.setGoodDetections(Integer.parseInt(JDUtilities.getAttribute(childNode, "good")));
 556                    letterDB.add(tmp);
 557                } else if (childNode.getNodeName().equals("map")) {
 558                    if (Utilities.isLoggerActive()) {
 559                        logger.fine("Parse LetterMap");
 560                    }
 561                    long start2 = System.currentTimeMillis();
 562                    String[] map = childNode.getTextContent().split("\\|");
 563                    letterMap = new int[map.length][map.length];
 564                    for (int x = 0; x < map.length; x++) {
 565                        String[] row = map[x].split("\\,");
 566                        for (int y = 0; y < map.length; y++) {
 567                            letterMap[x][y] = Integer.parseInt(row[y]);
 568                        }
 569
 570                    }
 571                    if (Utilities.isLoggerActive()) {
 572                        logger.fine("LetterMap Parsing time: " + (System.currentTimeMillis() - start2));
 573                    }
 574                }
 575            }
 576        } catch (Exception e) {
 577            JDLogger.exception(e);
 578            if (Utilities.isLoggerActive()) {
 579                logger.severe("Fehler bein lesen der MTH Datei!!. Methode kann nicht funktionieren!");
 580            }
 581
 582        }
 583        if (Utilities.isLoggerActive()) {
 584            logger.fine("Mth Parsing time: " + (System.currentTimeMillis() - start1));
 585        }
 586    }
 587
 588    /**
 589     * Diese methode trainiert einen captcha
 590     * 
 591     * @param captchafile
 592     *            File zum Bild
 593     * @param letterNum
 594     *            Anzahl der Buchstaben im captcha
 595     * @return int -1: Übersprungen Sonst: anzahl der richtig erkanten Letter
 596     */
 597
 598    private Document createXMLFromLetterDB() {
 599        Document xml = JDUtilities.parseXmlString("<jDownloader></jDownloader>", false);
 600        if (letterMap != null) {
 601            Element element = xml.createElement("map");
 602            xml.getFirstChild().appendChild(element);
 603            element.appendChild(xml.createTextNode(getLetterMapString()));
 604        }
 605
 606        int i = 0;
 607        for (Letter letter : letterDB) {
 608            Element element = xml.createElement("letter");
 609            xml.getFirstChild().appendChild(element);
 610            element.appendChild(xml.createTextNode(letter.getPixelString()));
 611            element.setAttribute("id", i++ + "");
 612            element.setAttribute("value", letter.getDecodedValue());
 613            element.setAttribute("captchaHash", letter.getSourcehash());
 614            element.setAttribute("good", letter.getGoodDetections() + "");
 615            element.setAttribute("bad", letter.getBadDetections() + "");
 616
 617        }
 618        return xml;
 619
 620    }
 621
 622    private void destroyScrollPaneWindows() {
 623        while (spw.size() > 0) {
 624            spw.remove(0).destroy();
 625        }
 626    }
 627
 628    /**
 629     * Zeigt die Momentane Library an. Buchstaben können gelöscht werden
 630     */
 631    public void displayLibrary() {
 632        if (letterDB == null || letterDB.size() == 0) { return; }
 633        // final BasicWindow w = BasicWindow.getWindow("Library: " +
 634        // letterDB.size() + " Datensätze", 400, 300);
 635        final JFrame w = new JFrame();
 636        // w.setLayout(new GridBagLayout());
 637        sortLetterDB();
 638        JPanel p = new JPanel(new GridLayout(letterDB.size() + 1, 3));
 639        w.add(new JScrollPane(p));
 640
 641        final Letter[] list = new Letter[letterDB.size()];
 642
 643        int y = 0;
 644        int i = 0;
 645        ListIterator<Letter> iter = letterDB.listIterator(letterDB.size());
 646        final ArrayList<Integer> rem = new ArrayList<Integer>();
 647        while (iter.hasPrevious()) {
 648            final Letter tmp = iter.previous();
 649            list[i] = tmp;
 650
 651            JLabel lbl = null;
 652            if ((tmp.getGoodDetections() == 0 && tmp.getBadDetections() > 3) || ((double) tmp.getBadDetections() / (double) tmp.getGoodDetections() >= 3)) {
 653                lbl = new JLabel("<html><p><font color=\"#ff0000\" " + "size=\"3\">" + tmp.getId() + ": " + tmp.getDecodedValue() + "(" + tmp.getGoodDetections() + "/" + tmp.getBadDetections() + ") Size: " + tmp.toPixelObject(0.85).getSize() + "</font> </p>" + "</html>");
 654            } else {
 655                lbl = new JLabel(tmp.getId() + ": " + tmp.getDecodedValue() + "(" + tmp.getGoodDetections() + "/" + tmp.getBadDetections() + ") Size: " + tmp.toPixelObject(0.85).getSize());
 656            }
 657
 658            ImageComponent img = new ImageComponent(tmp.getImage());
 659
 660            final JCheckBox bt = new JCheckBox("DELETE");
 661            final int ii = i;
 662            bt.addActionListener(new ActionListener() {
 663                public Integer id = ii;
 664
 665                public void actionPerformed(ActionEvent arg) {
 666                    JCheckBox src = ((JCheckBox) arg.getSource());
 667                    if (src.getText().equals("DELETE")) {
 668                        rem.add(id);
 669                    } else {
 670                        rem.remove(id);
 671                    }
 672                }
 673
 674            });
 675            p.add(lbl);
 676            p.add(img);
 677            p.add(bt);
 678            i++;
 679            y++;
 680            // if (y > 20) {
 681            // y = 0;
 682            // x += 6;
 683            // }
 684        }
 685        JButton b = new JButton("Invoke");
 686        p.add(b);
 687        b.addActionListener(new ActionListener() {
 688
 689            public void actionPerformed(ActionEvent e) {
 690                // System.out.println(rem + "");
 691                ArrayList<Letter> list = new ArrayList<Letter>();
 692                int s = letterDB.size();
 693                for (Integer i : rem) {
 694                    try {
 695                        Letter let = letterDB.get(s - 1 - i);
 696                        list.add(let);
 697
 698                    } catch (Exception ew) {
 699                        JDLogger.exception(ew);
 700                    }
 701                }
 702                for (Letter letter : list) {
 703                    removeLetterFromLibrary(letter);
 704                }
 705                saveMTHFile();
 706                displayLibrary();
 707            }
 708        });
 709        w.pack();
 710        w.setVisible(true);
 711    }
 712
 713    public String getCodeFromFileName(String name) {
 714        return new Regex(name, "captcha_(.*?)_code(.*?)\\.(.*?)").getMatch(1);
 715    }
 716
 717    /**
 718     * Liest den captchaornder aus
 719     * 
 720     * @param path
 721     * @return File Array
 722     */
 723    public File[] getImages(String path) {
 724        File dir = new File(path);
 725
 726        if (dir == null || !dir.exists()) {
 727            if (Utilities.isLoggerActive()) {
 728                logger.severe("Image dir nicht gefunden " + path);
 729            }
 730
 731        }
 732        logger.info(dir + "");
 733        File[] entries = dir.listFiles(new FileFilter() {
 734            public boolean accept(File pathname) {
 735                if (Utilities.isLoggerActive()) {
 736                    logger.info(pathname.getName());
 737                }
 738                if (pathname.getName().endsWith(".bmp") || pathname.getName().endsWith(".jpg") || pathname.getName().endsWith(".png") || pathname.getName().endsWith(".gif")) {
 739
 740                    return true;
 741                } else {
 742                    return false;
 743                }
 744            }
 745
 746        });
 747        return entries;
 748
 749    }
 750
 751    /**
 752     * @return the imageType
 753     */
 754    public String getImageType() {
 755        return imageType;
 756    }
 757
 758    /**
 759     * Die Methode parsed die jacinfo.xml
 760     */
 761    private void getJACInfo() {
 762        File f = getResourceFile("jacinfo.xml");
 763        if (!f.exists()) {
 764            if (Utilities.isLoggerActive()) {
 765                logger.severe("jacinfo.xml is missing2");
 766            }
 767            return;
 768        }
 769        Document doc = JDUtilities.parseXmlString(JDIO.readFileToString(f), false);
 770        if (doc == null) {
 771            if (Utilities.isLoggerActive()) {
 772                logger.severe("jacinfo.xml is missing2");
 773            }
 774            return;
 775        }
 776
 777        NodeList nl = doc.getFirstChild().getChildNodes();
 778        for (int i = 0; i < nl.getLength(); i++) {
 779            // Get child node
 780            Node childNode = nl.item(i);
 781
 782            if (childNode.getNodeName().equals("method")) {
 783                try {
 784                    this.extern = JDUtilities.getAttribute(childNode, "type").equalsIgnoreCase("extern");
 785                } catch (Exception e) {
 786                }
 787            } else if (childNode.getNodeName().equals("command")) {
 788
 789                this.srcFile = JDUtilities.getAttribute(childNode, "src");
 790                this.dstFile = JDUtilities.getAttribute(childNode, "dst");
 791                this.command = JDUtilities.getAttribute(childNode, "cmd");
 792
 793            } else if (childNode.getNodeName().equals("format")) {
 794                try {
 795                    setLetterNum(Integer.parseInt(JDUtilities.getAttribute(childNode, "letterNum")));
 796                } catch (Exception e) {
 797                }
 798
 799                setImageType(JDUtilities.getAttribute(childNode, "type"));
 800            }
 801        }
 802    }
 803
 804    /**
 805     * @return JACscript Instanz
 806     */
 807    public JACScript getJas() {
 808        return jas;
 809    }
 810
 811    /**
 812     * Vergleicht a und b und gibt eine Vergleichszahl zurück. a und b werden
 813     * gegeneinander verschoben und b wird über die Parameter gedreht. Praktisch
 814     * heißt das, dass derjenige Treffer als gut eingestuft wird, bei dem der
 815     * Datenbank Datensatz möglichst optimal überdeckt wird.
 816     * 
 817     * @param a
 818     *            Original Letter
 819     * @param B
 820     *            Vergleichsletter
 821     * @return int 0(super)-0xffffff (ganz übel)
 822     */
 823    public LetterComperator getLetter(Letter letter) {
 824        if (jas.getDouble("quickScanValityLimit") <= 0) {
 825            logger.info("quickscan disabled");
 826            return getLetterExtended(letter);
 827
 828        }
 829
 830        logger.info("Work on Letter:" + letter);
 831        // long startTime = Utilities.getTimer();
 832        LetterComperator res = null;
 833        double lastPercent = 100.0;
 834        int bvX, bvY;
 835        try {
 836
 837            if (letterDB == null) {
 838                if (Utilities.isLoggerActive()) {
 839                    logger.severe("letterDB nicht vorhanden");
 840                }
 841                return null;
 842            }
 843
 844            LetterComperator lc;
 845            ScrollPaneWindow w = null;
 846            if (isShowDebugGui()) {
 847                w = new ScrollPaneWindow();
 848
 849                w.setTitle(" Letter " + letter.getId());
 850            }
 851            bvX = jas.getInteger("borderVarianceX");
 852            bvY = jas.getInteger("borderVarianceY");
 853            int line = 0;
 854            lc = new LetterComperator(letter, null);
 855            lc.setScanVariance(0, 0);
 856            lc.setOwner(this);
 857            res = lc;
 858            int tt = 0;
 859            logger.info("Do quickscan");
 860            Method preValueFilterMethod = null;
 861            Class<?>[] preValueFilterParameterTypes = null;
 862            Object[] preValueFilterArguments = new Object[] { null, this };
 863            if (jas.getString("preValueFilter").length() > 0) {
 864                String[] ref = jas.getString("preValueFilter").split("\\.");
 865                if (ref.length != 2) {
 866                    if (Utilities.isLoggerActive()) {
 867                        logger.severe("preValueFilter should have the format Class.Method");
 868                    }
 869                    return null;
 870                }
 871                String cl = ref[0];
 872                String methodname = ref[1];
 873                Class<?> newClass;
 874                try {
 875                    newClass = Class.forName("jd.captcha.specials." + cl);
 876                    preValueFilterParameterTypes = new Class[] { LetterComperator.class, this.getClass() };
 877                    preValueFilterMethod = newClass.getMethod(methodname, preValueFilterParameterTypes);
 878
 879                } catch (Exception e) {
 880                    JDLogger.exception(e);
 881                }
 882            }
 883            Method postValueFilterMethod = null;
 884            Class<?>[] postValueFilterParameterTypes = null;
 885            Object[] postValueFilterArguments = new Object[] { null, this };
 886            if (jas.getString("postValueFilter").length() > 0) {
 887                String[] ref = jas.getString("postValueFilter").split("\\.");
 888                if (ref.length != 2) {
 889                    if (Utilities.isLoggerActive()) {
 890                        logger.severe("postValueFilter should have the format Class.Method");
 891                    }
 892                    return null;
 893                }
 894                String cl = ref[0];
 895                String methodname = ref[1];
 896                Class<?> newClass;
 897                try {
 898                    newClass = Class.forName("jd.captcha.specials." + cl);
 899                    postValueFilterParameterTypes = new Class[] { LetterComperator.class, this.getClass() };
 900                    postValueFilterMethod = newClass.getMethod(methodname, postValueFilterParameterTypes);
 901
 902                } catch (Exception e) {
 903                    JDLogger.exception(e);
 904                }
 905            }
 906            for (Letter tmp : letterDB) {
 907                if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
 908
 909                if (Math.abs(tmp.getHeight() - letter.getHeight()) > bvY || Math.abs(tmp.getWidth() - letter.getWidth()) > bvX) {
 910                    continue;
 911                }
 912
 913                lc = new LetterComperator(letter, tmp);
 914                // commented out only experimental
 915                // lc.setScanVariance(0, 0);
 916                lc.setOwner(this);
 917
 918                if (preValueFilterMethod != null) {
 919                    preValueFilterArguments[0] = tmp;
 920                    preValueFilterArguments[1] = lc;
 921                    if (!((Boolean) preValueFilterMethod.invoke(null, preValueFilterArguments))) {
 922                        continue;
 923                    }
 924
 925                }
 926                lc.run();
 927                tt++;
 928                if (isShowDebugGui()) {
 929                    w.setText(0, line, "0° Quick " + tt);
 930                    w.setImage(1, line, lc.getA().getImage(2));
 931                    w.setText(2, line, lc.getA().getDim());
 932                    w.setImage(3, line, lc.getB().getImage(2));
 933                    w.setText(4, line, lc.getB().getDim());
 934                    w.setImage(5, line, lc.getIntersectionLetter().getImage(2));
 935                    w.setText(6, line, lc.getIntersectionLetter().getDim());
 936                    w.setText(7, line, lc);
 937                    line++;
 938                }
 939                postValueFilterArguments[0] = lc;
 940                if (postValueFilterMethod == null || (Boolean) postValueFilterMethod.invoke(null, postValueFilterArguments)) {
 941                    if (res == null || lc.getValityPercent() < res.getValityPercent()) {
 942                        if (res != null && res.getValityPercent() < lastPercent) {
 943                            lastPercent = res.getValityPercent();
 944                        }
 945                        res = lc;
 946                        if (jas.getDouble("LetterSearchLimitPerfectPercent") >= lc.getValityPercent()) {
 947                            if (Utilities.isLoggerActive()) {
 948                                logger.finer(" Perfect Match: " + res.getB().getDecodedValue() + res.getValityPercent() + " good:" + tmp.getGoodDetections() + " bad: " + tmp.getBadDetections() + " - " + res);
 949                            }
 950                            res.setDetectionType(LetterComperator.QUICKSCANPERFECTMATCH);
 951                            res.setReliability(lastPercent - res.getValityPercent());
 952                            return res;
 953                        }
 954                        // if(Utilities.isLoggerActive())logger.finer("dim "
 955                        // +
 956                        // lc.getA().getDim() + "|" + lc.getB().getDim() + " New
 957                        // Best value: " + lc.getDecodedValue() + " "
 958                        // +lc.getValityPercent() + " good:" +
 959                        // tmp.getGoodDetections() + " bad: " +
 960                        // tmp.getBadDetections() + " - " + lc);
 961                    } else if (res != null) {
 962                        if (lc.getValityPercent() < lastPercent) {
 963                            lastPercent = lc.getValityPercent();
 964                        }
 965                    }
 966                }
 967            }
 968
 969        } catch (Exception e) {
 970
 971            JDLogger.exception(e);
 972        }
 973        if (res != null && res.getB() != null) {
 974            if (Utilities.isLoggerActive()) {
 975                logger.finer(" Normal Match: " + res.getB().getDecodedValue() + " " + res.getValityPercent() + " good:" + res.getB().getGoodDetections() + " bad: " + res.getB().getBadDetections());
 976            }
 977            // if (Utilities.isLoggerActive()) logger.fine("Letter erkannt
 978            // in: " + (Utilities.getTimer() - startTime) + " ms");
 979            res.setReliability(lastPercent - res.getValityPercent());
 980            if (res.getReliability() >= jas.getDouble("quickScanReliabilityLimit") && res.getValityPercent() < jas.getDouble("quickScanValityLimit")) {
 981                res.setDetectionType(LetterComperator.QUICKSCANMATCH);
 982                logger.info("Qickscan found " + res.getValityPercent() + "<" + jas.getDouble("quickScanValityLimit"));
 983                return res;
 984            } else {
 985                if (Utilities.isLoggerActive()) {
 986                    logger.warning("Letter nicht ausreichend erkannt. Try Extended " + res.getReliability() + " - " + jas.getDouble("quickScanReliabilityLimit") + " /" + res.getValityPercent() + "-" + jas.getDouble("quickScanValityLimit"));
 987                }
 988                return getLetterExtended(letter);
 989            }
 990        } else {
 991            if (Utilities.isLoggerActive()) {
 992                logger.warning("Letter nicht erkannt. Try Extended");
 993            }
 994            return getLetterExtended(letter);
 995        }
 996
 997    }
 998
 999    /**
1000     * Sucht in der MTH ANch dem besten übereinstimmenem letter
1001     * 
1002     * @param letter
1003     *            (refferenz)
1004     * @return Letter. Beste Übereinstimmung
1005     */
1006    private LetterComperator getLetterExtended(Letter letter) {
1007        // long startTime = Utilities.getTimer();
1008        LetterComperator res = null;
1009        logger.info("Extended SCAN");
1010        double lastPercent = 100.0;
1011        JTextArea tf = null;
1012        try {
1013
1014            if (letterDB == null) {
1015                if (Utilities.isLoggerActive()) {
1016                    logger.severe("letterDB nicht vorhanden");
1017                }
1018                return null;
1019            }
1020
1021            Letter tmp;
1022            int leftAngle = jas.getInteger("scanAngleLeft");
1023            int rightAngle = jas.getInteger("scanAngleRight");
1024            if (leftAngle > rightAngle) {
1025                int temp = leftAngle;
1026                leftAngle = rightAngle;
1027                rightAngle = temp;
1028                if (Utilities.isLoggerActive()) {
1029                    logger.warning("param.scanAngleLeft>paramscanAngleRight");
1030                }
1031            }
1032            int steps = Math.max(1, jas.getInteger("scanAngleSteps"));
1033            boolean turnDB = jas.getBoolean("turnDB");
1034            int angle;
1035            Letter orgLetter = letter;
1036            LetterComperator lc;
1037
1038            ScrollPaneWindow w = null;
1039            if (isShowDebugGui()) {
1040                w = new ScrollPaneWindow();
1041
1042                w.setTitle(" Letter " + letter.getId());
1043            }
1044            int line = 0;
1045            lc = new LetterComperator(letter, null);
1046            lc.setOwner(this);
1047            res = lc;
1048
1049            Method preValueFilterMethod = null;
1050            Class<?>[] preValueFilterParameterTypes = null;
1051            Object[] preValueFilterArguments = new Object[] { null, this };
1052            if (jas.getString("preValueFilter").length() > 0) {
1053                String[] ref = jas.getString("preValueFilter").split("\\.");
1054                if (ref.length != 2) {
1055                    if (Utilities.isLoggerActive()) {
1056                        logger.severe("preValueFilter should have the format Class.Method");
1057                    }
1058                    return null;
1059                }
1060                String cl = ref[0];
1061                String methodname = ref[1];
1062                Class<?> newClass;
1063                try {
1064                    newClass = Class.forName("jd.captcha.specials." + cl);
1065                    preValueFilterParameterTypes = new Class[] { LetterComperator.class, this.getClass() };
1066                    preValueFilterMethod = newClass.getMethod(methodname, preValueFilterParameterTypes);
1067
1068                } catch (Exception e) {
1069                    JDLogger.exception(e);
1070                }
1071            }
1072            Method postValueFilterMethod = null;
1073            Class<?>[] postValueFilterParameterTypes = null;
1074            Object[] postValueFilterArguments = new Object[] { null, this };
1075            if (jas.getString("postValueFilter").length() > 0) {
1076                String[] ref = jas.getString("postValueFilter").split("\\.");
1077                if (ref.length != 2) {
1078                    if (Utilities.isLoggerActive()) {
1079                        logger.severe("postValueFilter should have the format Class.Method");
1080                    }
1081                    return null;
1082                }
1083                String cl = ref[0];
1084                String methodname = ref[1];
1085                Class<?> newClass;
1086                try {
1087                    newClass = Class.forName("jd.captcha.specials." + cl);
1088                    postValueFilterParameterTypes = new Class[] { LetterComperator.class, this.getClass() };
1089                    postValueFilterMethod = newClass.getMethod(methodname, postValueFilterParameterTypes);
1090
1091                } catch (Exception e) {
1092                    JDLogger.exception(e);
1093                }
1094            }
1095            for (angle = Utilities.getJumperStart(leftAngle, rightAngle); Utilities.checkJumper(angle, leftAngle, rightAngle); angle = Utilities.nextJump(angle, leftAngle, rightAngle, steps)) {
1096
1097                if (turnDB) {
1098                    letter = orgLetter;
1099                } else {
1100                    letter = orgLetter.turn(angle);
1101                }
1102                // if(Utilities.isLoggerActive())logger.finer(" Angle " +
1103                // angle + " : " + letter.getDim());
1104
1105                int tt = 0;
1106                for (Letter ltr : letterDB) {
1107                    if (Thread.currentThread().isInterrupted()) throw new InterruptedException();
1108
1109                    if (turnDB) {
1110                        tmp = ltr.turn(angle);
1111
1112                    } else {
1113                        tmp = ltr;
1114                    }
1115
1116                    if (Math.abs(tmp.getHeight() - letter.getHeight()) > jas.getInteger("borderVarianceY") || Math.abs(tmp.getWidth() - letter.getWidth()) > jas.getInteger("borderVarianceX")) {
1117                        continue;
1118                    }
1119
1120                    lc = new LetterComperator(letter, tmp);
1121                    lc.setOwner(this);
1122
1123                    if (preValueFilterMethod != null) {
1124                        preValueFilterArguments[0] = lc;
1125                        preValueFilterArguments[1] = this;
1126                        if (!((Boolean) preValueFilterMethod.invoke(null, preValueFilterArguments))) {
1127                            continue;
1128                        }
1129
1130                    }
1131                    lc.run();
1132                    // if(Utilities.isLoggerActive())logger.info("Duration:
1133                    // "+(Utilities.getTimer()-timer) +"
1134                    // Loops: "+lc.loopCounter);
1135                    tt++;
1136
1137                    if (isShowDebugGui()) {
1138                        w.setText(0, line, angle + "° " + tt);
1139                        w.setImage(1, line, lc.getA().getImage(2));
1140                        w.setText(2, line, lc.getA().getDim());
1141                        w.setImage(3, line, lc.getB().getImage(2));
1142                        w.setText(4, line, lc.getB().getDim());
1143                        w.setImage(5, line, lc.getIntersectionLetter().getImage(2));
1144                        w.setText(6, line, lc.getIntersectionLetter().getDim());
1145
1146                        w.setComponent(7, line, tf = new JTextArea());
1147                        tf.setText(lc.toString());
1148                        if (lc.getPreValityPercent() > jas.getInteger("preScanFilter") && jas.getInteger("preScanFilter") > 0) {
1149                            tf.setBackground(Color.LIGHT_GRAY);
1150                        }
1151                        line++;
1152                    }
1153                    postValueFilterArguments[0] = lc;
1154                    if (postValueFilterMethod == null || (Boolean) postValueFilterMethod.invoke(null, postValueFilterArguments)) {
1155
1156                        if (res == null || lc.getValityPercent() < res.getValityPercent()) {
1157                            if (res != null && res.getValityPercent() < lastPercent) {
1158                                lastPercent = res.getValityPercent();
1159                            }
1160                            res = lc;
1161
1162                            if (jas.getDouble("LetterSearchLimitPerfectPercent") >= lc.getValityPercent()) {
1163                                res.setDetectionType(LetterComperator.PERFECTMATCH);
1164                                res.setReliability(lastPercent - res.getValityPercent());
1165                                if (Utilities.isLoggerActive()) {
1166                                    logger.finer(" Perfect Match: " + res.getB().getDecodedValue() + " " + res.getValityPercent() + " good:" + tmp.getGoodDetections() + " bad: " + tmp.getBadDetections() + " - " + res);
1167                                }
1168                                if (isShowDebugGui()) {
1169                                    tf.setBackground(Color.GREEN);
1170                                }
1171                                return res;
1172                            }
1173                            if (isShowDebugGui()) {
1174                                tf.setBackground(Color.BLUE);
1175                            }
1176                            if (Utilities.isLoggerActive()) {
1177                                logger.finer("Angle " + angle + "dim " + lc.getA().getDim() + "|" + lc.getB().getDim() + " New Best value: " + lc.getDecodedValue() + " " + lc.getValityPercent() + " good:" + tmp.getGoodDetections() + " bad: " + tmp.getBadDetections() + " - " + lc);
1178                            }
1179
1180                        } else if (res != null) {
1181                            // if (Utilities.isLoggerActive()&&
1182                            // lc.getDecodedValue().equalsIgnoreCase("G"))
1183                            // logger.finer("Angle " + angle + "dim " +
1184                            // lc.getA().getDim() + "|" + lc.getB().getDim() + "
1185                            // value: " + lc.getDecodedValue() + " " +
1186                            // lc.getValityPercent() + " good:" +
1187                            // tmp.getGoodDetections() + " bad: " +
1188                            // tmp.getBadDetections() + " - " + lc);
1189
1190                            if (lc.getValityPercent() < lastPercent) {
1191                                lastPercent = lc.getValityPercent();
1192                            }
1193                        }
1194                    }
1195
1196                }
1197                // if(Utilities.isLoggerActive())logger.info("Full Angle scan
1198                // in
1199                // "+(Utilities.getTimer()-startTime2));
1200            }
1201            // w.refreshUI();
1202        } catch (Exception e) {
1203            JDLogger.exception(e);
1204        }
1205
1206        if (res != null && res.getB() != null) {
1207            if (Utilities.isLoggerActive()) {
1208                logger.finer(" Normal Match: " + res.getB().getDecodedValue() + " " + res.getValityPercent() + " good:" + res.getB().getGoodDetections() + " bad: " + res.getB().getBadDetections());
1209            }
1210
1211            res.setReliability(lastPercent - res.getValityPercent());
1212        } else {
1213            if (getJas().getInteger("preScanEmergencyFilter") > getJas().getInteger("preScanFilter")) {
1214                logger.warning("nicht erkannt. Verwende erweiterte Emergencydatenbank");
1215                int psf = getJas().getInteger("preScanFilter");
1216                getJas().set("preScanFilter", getJas().getInteger("preScanEmergencyFilter"));
1217                LetterComperator ret = getLetterExtended(letter);
1218                getJas().set("preScanFilter", psf);
1219                return ret;
1220
1221            }
1222            if (Utilities.isLoggerActive()) {
1223                logger.severe("Letter entgültig nicht erkannt");
1224            }
1225            if (isShowDebugGui() && tf != null) {
1226                tf.setBackground(Color.RED);
1227            }
1228
1229        }
1230
1231        return res;
1232
1233    }
1234
1235    /**
1236     * @return gibt die Lettermap als String zurück
1237     */
1238    private String getLetterMapString() {
1239        StringBuilder ret = new StringBuilder();
1240        int i = 0;
1241        for (int x = 0; x < letterMap.length; x++) {
1242            ret.append("|");
1243            i++;
1244            for (int y = 0; y < letterMap[0].length; y++) {
1245
1246                ret.append(letterMap[x][y]);
1247                i++;
1248                ret.append(",");
1249                i++;
1250            }
1251            ret.deleteCharAt(ret.length() - 1);
1252            if (Utilities.isLoggerActive()) {
1253                logger.fine("Db String: " + x * 100 / letterDB.size() + "%");
1254            }
1255        }
1256        ret.deleteCharAt(0);
1257        return ret.toString();
1258
1259    }
1260
1261    /**
1262     * @return the letterNum
1263     */
1264    public int getLetterNum() {
1265        return letterNum;
1266    }
1267
1268    /**
1269     * @return the method
1270     */
1271    public String getMethodDirName() {
1272        return methodDirName;
1273    }
1274
1275    /**
1276     * Gibt ein FileObject zu einem resourcestring zurück
1277     * 
1278     * @param arg
1279     * @return File zu arg
1280     */
1281    public File getResourceFile(String arg) {
1282        return JDUtilities.getResourceFile(JDUtilities.getJACMethodsDirectory() + methodDirName + "/" + arg);
1283    }
1284
1285    public Captcha getWorkingCaptcha() {
1286        return workingCaptcha;
1287    }
1288
1289    /**
1290     * Importiert PNG einzelbilder aus einem ordner und erstellt daraus eine
1291     * neue db
1292     */
1293    public void importDB(File path) {
1294        String pattern = JOptionPane.showInputDialog("PATTERN", "\\d+_(.*?)\\.");
1295        if (JOptionPane.showConfirmDialog(null, "Delete old db?") == JOptionPane.OK_OPTION) letterDB = new ArrayList<Letter>();
1296        getResourceFile("letters.mth").delete();
1297        System.out.println("LETTERS BEFORE: " + letterDB.size());
1298        Image image;
1299        Letter letter;
1300        File[] images = getImages(path.getAbsolutePath());
1301        for (File element : images) {
1302            image = Utilities.loadImage(element);
1303            try {
1304                image = ImageIO.read(element);
1305            } catch (IOException e) {
1306                JDLogger.exception(e);
1307            }
1308            System.out.println(element.getAbsolutePath());
1309            int width = image.getWidth(null);
1310            int height = image.getHeight(null);
1311            if (width <= 0 || height <= 0) {
1312                if (Utilities.isLoggerActive()) {
1313                    logger.severe("ERROR: Image nicht korrekt.");
1314                }
1315            }
1316
1317            Captcha cap = createCaptcha(image);
1318
1319            letter = new Letter();
1320            letter.setOwner(this);
1321            letter.setGrid(cap.grid);
1322            letter.setSourcehash(JDHash.getMD5(element));
1323
1324            String let = new Regex(element.getName(), pattern).getMatch(0);
1325
1326            letter.setDecodedValue(let);
1327            letter.clean();
1328            letter.removeSmallObjects(0.3, 0.5, 10);
1329            letter.setDecodedValue(let);
1330
1331            letterDB.add(letter);
1332
1333        }
1334        System.out.println("LETTERS AFTER: " + letterDB.size());
1335        sortLetterDB();
1336        saveMTHFile();
1337    }
1338
1339    /**
1340     * Prüft ob der übergeben hash in der MTH file ist
1341     * 
1342     * @param captchaHash
1343     * @return true/false
1344     */
1345    private boolean isCaptchaInMTH(String captchaHash) {
1346        if (letterDB == null) return false;
1347        for (Letter letter : letterDB) {
1348            if (letter.getSourcehash().equals(captchaHash)) return true;
1349        }
1350
1351        return false;
1352
1353    }
1354
1355    /**
1356     * @return the showDebugGui
1357     */
1358    public boolean isShowDebugGui() {
1359        return showDebugGui;
1360    }
1361
1362    /**
1363     * MTH File wird geladen und verarbeitet
1364     * 
1365     * @param f
1366     */
1367    public void loadMTHFile(File f) {
1368        String str = null;
1369        if (f.exists()) {
1370            str = JDIO.readFileToString(f);
1371        } else {
1372            str = "<jDownloader></jDownloader>";
1373        }
1374        Document mth = JDUtilities.parseXmlString(str, false);
1375        logger.info("Get file: " + f);
1376        if (mth == null) {
1377            if (Utilities.isLoggerActive()) {
1378                logger.severe("MTH FILE NOT AVAILABLE.");
1379            }
1380
1381        }
1382
1383        createLetterDBFormMTH(mth);
1384        // sortLetterDB();
1385
1386    }
1387
1388    /**
1389     * MTH File wird geladen und verarbeitet
1390     */
1391    public void loadMTHFile() {
1392        File f = getResourceFile("letters.mth");
1393        loadMTHFile(f);
1394        // sortLetterDB();
1395    }
1396
1397    /**
1398     * Entfernt Buchstaben mit einem schlechetb Bad/Good verhältniss
1399     */
1400    public void removeBadLetters() {
1401        Letter tmp;
1402        if (Utilities.isLoggerActive()) {
1403            logger.info("aktuelle DB Size: " + letterDB.size());
1404        }
1405        ListIterator<Letter> iter = letterDB.listIterator(letterDB.size());
1406        while (iter.hasPrevious()) {
1407            tmp = iter.previous();
1408            if (tmp.getBadDetections() > tmp.getGoodDetections() + 2) {
1409                if (Utilities.isLoggerActive()) {
1410                    logger.info("bad Letter entfernt: " + tmp.getDecodedValue() + " (" + tmp.getBadDetections() + "/" + tmp.getGoodDetections() + ")");
1411                }
1412                iter.remove();
1413            }
1414
1415        }
1416        if (Utilities.isLoggerActive()) {
1417            logger.info("neue DB Size: " + letterDB.size());
1418        }
1419
1420        sortLetterDB();
1421        saveMTHFile();
1422
1423    }
1424
1425    protected void removeLetterFromLibrary(Letter letter) {
1426
1427        logger.info("Remove" + letter + " : " + letterDB.remove(letter));
1428
1429    }
1430
1431    /**
1432     * Speichert die MTH File
1433     */
1434    public synchronized void saveMTHFile() {
1435        String xmlString = JDUtilities.createXmlString(createXMLFromLetterDB());
1436        if (!JDIO.writeLocalFile(getResourceFile("letters.mth"), xmlString)) {
1437            if (Utilities.isLoggerActive()) {
1438                logger.severe("MTHO file Konnte nicht gespeichert werden");
1439            }
1440        }
1441    }
1442
1443    /**
1444     * @param imageType
1445     *            the imageType to set
1446     */
1447    public void setImageType(String imageType) {
1448        if (Utilities.isLoggerActive()) {
1449            logger.finer("SET PARAMETER: [imageType] = " + imageType);
1450        }
1451        this.imageType = imageType;
1452    }
1453
1454    /**
1455     * @param letterNum
1456     *            the letterNum to set
1457     */
1458    public void setLetterNum(int letterNum) {
1459        if (Utilities.isLoggerActive()) {
1460            logger.finer("SET PARAMETER: [letterNum] = " + letterNum);
1461        }
1462        this.letterNum = letterNum;
1463    }
1464
1465    /**
1466     * @param showDebugGui
1467     *            the showDebugGui to set
1468     */
1469    public void setShowDebugGui(boolean showDebugGui) {
1470        this.showDebugGui = showDebugGui;
1471    }
1472
1473    public void setWorkingCaptcha(Captcha workingCaptcha) {
1474        this.workingCaptcha = workingCaptcha;
1475    }
1476
1477    /**
1478     * Debug Methode. Zeigt den Captcha in verschiedenen bearbeitungsstadien an
1479     * 
1480     * @param captchafile
1481     */
1482    public void showPreparedCaptcha(final File captchafile) {
1483
1484        if (!captchafile.exists()) {
1485            if (Utilities.isLoggerActive()) {
1486                logger.severe(captchafile.getAbsolutePath() + " existiert nicht");
1487            }
1488            return;
1489        }
1490
1491        Image captchaImage = Utilities.loadImage(captchafile);
1492        BasicWindow.showImage(captchaImage);
1493        Captcha captcha = createCaptcha(captchaImage);
1494
1495        int skWidth = captcha.getWidth();
1496        int skHeight = captcha.getHeight();
1497        if (skHeight > 200 || skWidth > 200) {
1498            if (skHeight > skWidth) {
1499                skWidth = 200 * skWidth / skHeight;
1500                skHeight = 200;
1501            } else {
1502                skHeight = 200 * skHeight / skWidth;
1503                skWidth = 200;
1504            }
1505        }
1506        logger.info("CAPTCHA :_" + checkCaptcha(captchafile, captcha));
1507        if (bw3 != null) {
1508            bw3.dispose();
1509        }
1510        bw3 = BasicWindow.showImage(captchaImage.getScaledInstance(skWidth, skHeight, 1), "Captchas");
1511        bw3.add(new JLabel("ORIGINAL"), Utilities.getGBC(2, 0, 2, 2));
1512        bw3.setLocationByScreenPercent(50, 70);
1513
1514        bw3.add(new ImageComponent(captcha.getImage(1).getScaledInstance(skWidth, skHeight, 1)), Utilities.getGBC(0, 2, 2, 2));
1515        bw3.add(new JLabel("Farbraum Anpassung"), Utilities.getGBC(2, 2, 2, 2));
1516        jas.executePrepareCommands(captchafile, captcha);
1517
1518        bw3.add(new ImageComponent(captcha.getImage(1).getScaledInstance(skWidth, skHeight, 1)), Utilities.getGBC(0, 4, 2, 2));
1519        bw3.add(new JLabel("Prepare Code ausgeführt"), Utilities.getGBC(2, 4, 2, 2));
1520
1521        // Hole die letters aus dem neuen captcha
1522
1523        // Utilities.wait(40000);
1524        // prüfe auf Erfolgreiche Lettererkennung
1525
1526        // Decoden. checkCaptcha verwendet dabei die gecachte Erkennung der
1527        // letters
1528
1529        Letter[] letters = captcha.getLetters(letterNum);
1530        if (letters == null) {
1531            if (Utilities.isLoggerActive()) {
1532                logger.severe("2. Lettererkennung ist fehlgeschlagen!");
1533            }
1534            return;
1535        }
1536
1537        bw3.add(new ImageComponent(captcha.getImageWithGaps(1).getScaledInstance(skWidth, skHeight, 1)), Utilities.getGBC(0, 6, 2, 2));
1538        bw3.add(new JLabel("Buchstaben freistellen"), Utilities.getGBC(2, 6, 2, 2));
1539        bw3.refreshUI();
1540        if (bw2 != null) {
1541            bw2.destroy();
1542        }
1543        bw2 = new BasicWindow();
1544        bw2.setTitle("Freigestellte Buchstaben");
1545        bw2.setLayout(new GridBagLayout());
1546        bw2.setSize(300, 300);
1547        if (Utilities.isLoggerActive()) {
1548            logger.info("display freistellen");
1549        }
1550        bw2.setAlwaysOnTop(true);
1551        bw2.setLocationByScreenPercent(50, 5);
1552        bw2.add(new JLabel("Aus Captcha:"), Utilities.getGBC(0, 0, 2, 2));
1553
1554        for (int i = 0; i < letters.length; i++) {
1555            bw2.add(new ImageComponent(letters[i].getImage((int) Math.ceil(jas.getDouble("simplifyFaktor")))), Utilities.getGBC(i * 2 + 2, 0, 2, 2));
1556        }
1557        bw2.setVisible(true);
1558        bw2.pack();
1559        bw2.setSize(300, bw2.getSize().height);
1560
1561        LetterComperator[] lcs = captcha.getLetterComperators();
1562        for (int i = 0; i < lcs.length; i++) {
1563            if (lcs[i] == null) continue;
1564
1565            bw2.add(new JLabel("Aus Datenbank:"), Utilities.getGBC(0, 6, 2, 2));
1566            Letter dif = lcs[i].getDifference();
1567            dif.removeSmallObjects(0.8, 0.8, 5);
1568            dif.clean();
1569            if (lcs[i].getB() != null) {
1570                bw2.add(new ImageComponent(lcs[i].getB().getImage((int) Math.ceil(jas.getDouble("simplifyFaktor")))), Utilities.getGBC(i * 2 + 2, 6, 2, 1));
1571                bw2.add(new ImageComponent(dif.getImage((int) Math.ceil(jas.getDouble("simplifyFaktor")))), Utilities.getGBC(i * 2 + 2, 7, 2, 1));
1572            } else {
1573                bw2.add(new JLabel("B unknown"), Utilities.getGBC(i * 2 + 2, 6, 2, 2));
1574            }
1575
1576            bw2.add(new JLabel("Wert:"), Utilities.getGBC(0, 8, 2, 2));
1577            bw2.add(new JLabel("Proz.:"), Utilities.getGBC(0, 10, 2, 2));
1578            bw2.add(new JLabel(lcs[i].getValityPercent() + "%"), Utilities.getGBC(i * 2 + 2, 10, 2, 2));
1579
1580        }
1581        JButton bt = new JButton("Train");
1582
1583        bw2.add(bt, Utilities.getGBC(0, 12, 2, 2));
1584        bw2.pack();
1585        bw2.repack();
1586
1587        bt.addActionListener(new ActionListener() {
1588
1589            public void actionPerformed(ActionEvent e) {
1590                JAntiCaptcha.this.trainCaptcha(captchafile, 4);
1591            }
1592
1593        });
1594    }
1595
1596    /**
1597     * Sortiert die letterDB Nach den bad Detections. Der Sortieralgo gehört
1598     * dringend überarbeitet!!! Diese Sortieren hilft die GUten Letter zuerst zu
1599     * prüfen.
1600     * 
1601     * @TODO Sortoer ALGO ändern. zu langsam!!
1602     */
1603    public void sortLetterDB() {
1604        Collections.sort(letterDB, new Comparator<Letter>() {
1605            public int compare(Letter a, Letter b) {
1606                try {
1607                    return a.getDecodedValue().compareToIgnoreCase(b.getDecodedValue()) * -1;
1608                } catch (Exception e) {
1609                    e.printStackTrace();
1610                    return 0;
1611                }
1612            }
1613        });
1614    }
1615
1616    /**
1617     * Diese methode wird aufgerufen um alle captchas im Ordner
1618     * methods/Methodname/captchas zu trainieren
1619     * 
1620     * @param path
1621     */
1622    public void trainAllCaptchas(String path) {
1623        int successFull = 0;
1624        int total = 0;
1625        logger.info("TRain " + path);
1626        File[] images = getImages(path);
1627        if (images == null) { return; }
1628        int newLetters;
1629        for (File element : images) {
1630            if (Utilities.isLoggerActive()) {
1631                logger.fine(element.toString());
1632            }
1633            int letternum = getLetterNum();
1634            newLetters = trainCaptcha(element, letternum);
1635
1636            if (Utilities.isLoggerActive()) {
1637                logger.fine("Erkannt: " + newLetters + "/" + getLetterNum());
1638            }
1639            if (newLetters > 0) {
1640                successFull += newLetters;
1641                total += getLetterNum();
1642                if (Utilities.isLoggerActive()) {
1643                    logger.info("Erkennungsrate: " + 100 * successFull / total);
1644                }
1645            } else if (newLetters == -2) {
1646                if (f != null) {
1647                    f.dispose();
1648                }
1649                break;
1650            }
1651
1652        }
1653
1654    }
1655
1656    public int trainCaptcha(final File captchafile, int letterNum) {
1657
1658        if (!captchafile.exists()) {
1659            if (Utilities.isLoggerActive()) {
1660                logger.severe(captchafile.getAbsolutePath() + " existiert nicht");
1661            }
1662            return -1;
1663        }
1664        if (isShowDebugGui()) {
1665            destroyScrollPaneWindows();
1666        }
1667        // Lade das Bild
1668        // Erstelle hashwert
1669        final String captchaHash = JDHash.getMD5(captchafile);
1670
1671        // Prüfe ob dieser captcha schon aufgenommen wurde und überspringe ihn
1672        // falls ja
1673        if (isCaptchaInMTH(captchaHash)) {
1674            if (Utilities.isLoggerActive()) {
1675                logger.fine("Captcha schon aufgenommen" + captchafile);
1676            }
1677            return -1;
1678        }
1679        // captcha erstellen
1680        Image captchaImage = Utilities.loadImage(captchafile);
1681
1682        final Captcha captcha = createCaptcha(captchaImage);
1683        int sk1Width = captcha.getWidth();
1684        int sk1Height = captcha.getHeight();
1685        if (sk1Height > 200 || sk1Width > 200) {
1686            if (sk1Height > sk1Width) {
1687                sk1Width = 200 * sk1Width / sk1Height;
1688                sk1Height = 200;
1689            } else {
1690                sk1Height = 200 * sk1Height / sk1Width;
1691                sk1Width = 200;
1692            }
1693        }
1694        final int skWidth = sk1Width;
1695        final int skHeight = sk1Height;
1696        String code = null;
1697        // Zeige das OriginalBild
1698        if (f != null) {
1699            f.dispose();
1700        }
1701        f = new JDialog(DummyFrame.getDialogParent());
1702        f.setLocation(500, 10);
1703        f.setLayout(new GridBagLayout());
1704        f.add(new JLabel("original captcha: " + captchafile.getName()), Utilities.getGBC(0, 0, 10, 1));
1705
1706        f.add(new ImageComponent(captcha.getImage().getScaledInstance(skWidth, skHeight, 1)), Utilities.getGBC(0, 1, 10, 1));
1707
1708        f.setSize(1400, 800);
1709        f.pack();
1710        f.setVisible(true);
1711
1712        // Führe das Prepare aus
1713        // jas.executePrepareCommands(captcha);
1714        // Hole die letters aus dem neuen captcha
1715        final String guess = checkCaptcha(captchafile, captcha);
1716        final Letter[] letters = captcha.getLetters(letterNum);
1717        if (letters == null) {
1718            File file = getResourceFile("detectionErrors5/" + System.currentTimeMillis() + "_" + captchafile.getName());
1719            file.getParentFile().mkdirs();
1720            captchafile.renameTo(file);
1721            if (Utilities.isLoggerActive()) {
1722                logger.severe("Letter detection error");
1723            }
1724            return -1;
1725        }
1726
1727        class MyRunnable implements Runnable {
1728            private String code = null;
1729            private int    ret  = 0;
1730
1731            public void run() {
1732                if (getCodeFromFileName(captchafile.getName()) == null) {
1733                    code = JOptionPane.showInputDialog("Bitte Captcha Code eingeben (Press enter to confirm " + guess, guess);
1734                    if (code != null && code.equals(guess)) {
1735                        code = "";
1736                    } else if (code == null) {
1737                        if (JOptionPane.showConfirmDialog(new JFrame(), "Ja (yes) = beenden (close) \t Nein (no) = nächstes Captcha (next captcha)") == JOptionPane.OK_OPTION) {
1738                            ret = -2;
1739                        }
1740                    }
1741                } else {
1742                    code = getCodeFromFileName(captchafile.getName());
1743                    if (Utilities.isLoggerActive()) {
1744                        logger.warning("captcha code für " + captchaHash + " verwendet: " + code);
1745                    }
1746                }
1747                synchronized (this) {
1748                    this.notify();
1749                }
1750            }
1751        }
1752        MyRunnable run = new MyRunnable();
1753        Thread inpThread = new Thread(run);
1754        inpThread.start();
1755        // Zeige das After-prepare Bild an
1756        f.add(new JLabel("Letter Detection"), Utilities.getGBC(0, 3, 10, 1));
1757
1758        f.add(new ImageComponent(captcha.getImageWithGaps(1).getScaledInstance(skWidth, skHeight, 1)), Utilities.getGBC(0, 4, 10, 1));
1759
1760        f.add(new JLabel("Seperated"), Utilities.getGBC(0, 5, 10, 1));
1761        for (int i = 0; i < letters.length; i++) {
1762            f.add(new ImageComponent(letters[i].getImage((int) Math.ceil(jas.getDouble("simplifyFaktor")))), Utilities.getGBC(i * 2 + 1, 6, 1, 1));
1763            JLabel jl = new JLabel("|");
1764            jl.setForeground(Color.RED);
1765            f.add(jl, Utilities.getGBC(i * 2 + 2, 6, 1, 1));
1766        }
1767        f.pack();
1768
1769        // Decoden. checkCaptcha verwendet dabei die gecachte Erkennung der
1770        // letters
1771
1772        final LetterComperator[] lcs = captcha.getLetterComperators();
1773        if (lcs == null) {
1774            File file = getResourceFile("detectionErrors5/" + System.currentTimeMillis() + "_" + captchafile.getName());
1775            file.getParentFile().mkdirs();
1776            captchafile.renameTo(file);
1777            if (Utilities.isLoggerActive()) {
1778                logger.severe("Letter detection error");
1779            }
1780            return -1;
1781        }
1782        if (lcs.length != letters.length) {
1783            logger.severe("ACHTUNG. lcs: " + lcs.length + " - letters: " + letters.length);
1784        }
1785        if (guess != null /* && guess.length() == getLetterNum() */) {
1786
1787            f.add(new JLabel("Letter Detection"), Utilities.getGBC(0, 3, 10, 1));
1788
1789            f.add(new ImageComponent(captcha.getImageWithGaps(1).getScaledInstance(skWidth, skHeight, 1)), Utilities.getGBC(0, 4, 10, 1));
1790
1791            f.add(new JLabel("Seperated"), Utilities.getGBC(0, 5, 10, 1));
1792            for (int i = 0; i < letters.length; i++) {
1793                f.add(new ImageComponent(letters[i].getImage((int) Math.ceil(jas.getDouble("simplifyFaktor")))), Utilities.getGBC(i * 2 + 1, 6, 1, 1));
1794                JLabel jl = new JLabel("|");
1795                jl.setForeground(Color.RED);
1796                f.add(jl, Utilities.getGBC(i * 2 + 2, 6, 1, 1));
1797            }
1798            f.pack();
1799
1800            for (int i = 0; i < lcs.length; i++) {
1801                if (lcs[i] != null && lcs[i].getB() != null) {
1802                    f.add(new ImageComponent(lcs[i].getB().getImage((int) Math.ceil(jas.getDouble("simplifyFaktor")))), Utilities.getGBC(i * 2 + 1, 8, 1, 1));
1803                } else {
1804                    f.add(new JLabel(""), Utilities.getGBC(i * 2 + 1, 8, 1, 1));
1805                }
1806                JLabel jl = new JLabel("|");
1807                jl.setForeground(Color.RED);
1808                f.add(jl, Utilities.getGBC(i * 2 + 2, 6, 1, 1));
1809
1810                if (lcs[i] != null && lcs[i].getB() != null) {
1811                    f.add(new JLabel("" + lcs[i].getDecodedValue()), Utilities.getGBC(i * 2 + 1, 9, 1, 1));
1812                } else {
1813                    f.add(new JLabel(""), Utilities.getGBC(i * 2 + 1, 9, 1, 1));
1814                }
1815                if (lcs[i] != null && lcs[i].getB() != null) {
1816                    f.add(new JLabel("" + Math.round(10 * lcs[i].getValityPercent()) / 10.0), Utilities.getGBC(i * 2 + 1, 10, 1, 1));
1817                } else {
1818                    f.add(new JLabel(""), Utilities.getGBC(i * 2 + 1, 10, 1, 1));
1819                }
1820            }
1821            f.pack();
1822        } else {
1823            if (Utilities.isLoggerActive()) {
1824                logger.warning("Erkennung fehlgeschlagen");
1825            }
1826        }
1827        f.add(new JLabel("prepared captcha"), Utilities.getGBC(0, 11, 10, 1));
1828
1829        f.add(new ImageComponent(captcha.getImage().getScaledInstance(skWidth, skHeight, 1)), Utilities.getGBC(0, 12, 10, 1));
1830        f.pack();
1831
1832        if (Utilities.isLoggerActive()) {
1833            logger.info("Decoded Captcha: " + guess + " Vality: " + captcha.getValityPercent());
1834        }
1835
1836        if (inpThread.isAlive()) {
1837            synchronized (run) {
1838                try {
1839                    run.wait();
1840                } catch (InterruptedException e) {
1841                    e.printStackTrace();
1842                }
1843            }
1844        }
1845        if (run.ret == -2) return -2;
1846        code = run.code;
1847        if (code == null) {
1848            File file = getResourceFile("detectionErrors3/" + System.currentTimeMillis() + "_" + captchafile.getName());
1849            file.getParentFile().mkdirs();
1850            captchafile.renameTo(file);
1851            if (Utilities.isLoggerActive()) {
1852                logger.severe("Captcha Input error");
1853            }
1854            return -1;
1855        }
1856        if (code.length() == 0) {
1857            code = guess;
1858        }
1859        if (code.length() != letters.length) {
1860            File file = getResourceFile("detectionErrors4/" + System.currentTimeMillis() + "_" + captchafile.getName());
1861            file.getParentFile().mkdirs();
1862            captchafile.renameTo(file);
1863            if (Utilities.isLoggerActive()) {
1864                logger.severe("Captcha Input error3");
1865            }
1866            return -1;
1867        }
1868        if (code.indexOf("-") < 0) {
1869            String[] oldName = captchafile.getName().split("\\.");
1870            String ext = oldName[oldName.length - 1];
1871            String newName = captchafile.getParentFile().getAbsolutePath() + "/captcha_" + getMethodDirName() + "_code" + code + "." + ext;
1872            captchafile.renameTo(new File(newName));
1873        }
1874        int ret = 0;
1875        for (int j = 0; j < letters.length; j++) {
1876            final int i = j;
1877
1878            if (!code.substring(i, i + 1).equals("-")) {
1879                if (guess != null && code.length() > i && guess.length() > i && code.substring(i, i + 1).equals(guess.substring(i, i + 1))) {
1880                    ret++;
1881                    if (lcs[i] != null) {
1882                        lcs[i].getB().markGood();
1883                    }
1884                    if (lcs[i].getValityPercent() > 50) {
1885                        letters[i].setOwner(this);
1886                        // letters[i].setTextGrid(letters[i].getPixelString());
1887                        letters[i].setSourcehash(captchaHash);
1888                        letters[i].setDecodedValue(code.substring(i, i + 1));
1889
1890                        new Thread(new Runnable() {
1891                            public void run() {
1892                                final BasicWindow bws = BasicWindow.showImage(letters[i].getImage(2), "" + letters[i].getDecodedValue());
1893                                try {
1894                                    Thread.sleep(1000);
1895                                } catch (InterruptedException e) {
1896                                    e.printStackTrace();
1897                                }
1898                                bws.dispose();
1899                            }
1900                        }).start();
1901
1902                        letterDB.add(letters[i]);
1903                    }
1904                    if (!jas.getBoolean("TrainOnlyUnknown")) {
1905                        letters[i].setOwner(this);
1906                        // letters[i].setTextGrid(letters[i].getPixelString());
1907                        letters[i].setSourcehash(captchaHash);
1908                        letters[i].setDecodedValue(code.substring(i, i + 1));
1909                        letterDB.add(letters[i]);
1910                        f.add(new JLabel("OK+"), Utilities.getGBC(i + 1, 13, 1, 1));
1911                    } else {
1912                        f.add(new JLabel("OK-"), Utilities.getGBC(i + 1, 13, 1, 1));
1913                        f.pack();
1914                    }
1915                } else {
1916                    if (Utilities.isLoggerActive()) {
1917                        logger.info(letterDB + " - ");
1918                    }
1919                    if (lcs != null && lcs[i] != null && letterDB.size() > 30 && lcs[i] != null && lcs[i].getB() != null) {
1920                        lcs[i].getB().markBad();
1921                    }
1922                    letters[i].setOwner(this);
1923                    // letters[i].setTextGrid(letters[i].getPixelString());
1924                    letters[i].setSourcehash(captchaHash);
1925                    letters[i].setDecodedValue(code.substring(i, i + 1));
1926
1927                    letterDB.add(letters[i]);
1928                    new Thread(new Runnable() {
1929                        public void run() {
1930                            final BasicWindow bws = BasicWindow.showImage(letters[i].getImage(2), "" + letters[i].getDecodedValue());
1931                            try {
1932                                Thread.sleep(1000);
1933                            } catch (InterruptedException e) {
1934                                e.printStackTrace();
1935                            }
1936                            bws.dispose();
1937                        }
1938                    }).start();
1939                    f.add(new JLabel("NO +"), Utilities.getGBC(i + 1, 13, 1, 1));
1940                    f.pack();
1941                }
1942            } else {
1943                f.add(new JLabel("-"), Utilities.getGBC(i + 1, 13, 1, 1));
1944                f.pack();
1945            }
1946            // mth.appendChild(element);
1947        }
1948        sortLetterDB();
1949        // das syncroniced kann das jetzt auch mit einem thread gemacht werden
1950        new Thread(new Runnable() {
1951            public void run() {
1952                saveMTHFile();
1953            }
1954        }).start();
1955        return ret;
1956    }
1957
1958    public void cleanLibrary(double d) {
1959        ArrayList<Letter> newDB = new ArrayList<Letter>();
1960        main: for (Letter let : letterDB) {
1961
1962            for (Letter n : newDB) {
1963                if (let.getDecodedValue().endsWith(n.getDecodedValue())) {
1964                    LetterComperator lc = new LetterComperator(let, n);
1965
1966                    lc.setOwner(this);
1967                    lc.run();
1968
1969                    n.getElementPixel();
1970
1971                    if (lc.getValityPercent() <= d) {
1972                        BasicWindow.showImage(let.getImage(), " OK ");
1973                        // BasicWindow.showImage(n.getImage(), " FILTERED " +
1974                        // lc.getValityPercent());
1975                        if (n.getElementPixel() > let.getElementPixel()) {
1976                            newDB.remove(let);
1977                            break;
1978                        } else {
1979                            continue main;
1980                        }
1981                    }
1982                }
1983            }
1984            newDB.add(let);
1985
1986        }
1987        letterDB = newDB;
1988        this.saveMTHFile();
1989    }
1990
1991    public static String getCaptcha(String path, String host) {
1992        if (JACMethod.hasMethod(host)) {
1993
1994            File file;
1995            if (path.contains("http://")) {
1996                try {
1997                    file = JDUtilities.getResourceFile("captchas/jac_captcha.img");
1998                    file.deleteOnExit();
1999
2000                    Browser.download(file, new Browser().openGetConnection(path));
2001                } catch (IOException e) {
2002                    return "Could not download captcha image";
2003                }
2004            } else {
2005                file = new File(path);
2006                if (!file.exists()) return "File does not exist";
2007            }
2008
2009            try {
2010                Image captchaImage = ImageIO.read(file);
2011                JAntiCaptcha jac = new JAntiCaptcha(host);
2012                Captcha captcha = jac.createCaptcha(captchaImage);
2013                return jac.checkCaptcha(file, captcha);
2014            } catch (Exception e) {
2015                return e.getStackTrace().toString();
2016            }
2017        } else {
2018            return "jDownloader has no method for " + host;
2019        }
2020    }
2021
2022}