[med-svn] [mpsqed] 06/08: New upstream version 0.9.3

Andreas Tille tille at debian.org
Tue Dec 12 17:22:45 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository mpsqed.

commit 9b6edc5ed79d59a0db1832e691f40860100ecf3a
Author: Andreas Tille <tille at debian.org>
Date:   Tue Dec 12 18:21:32 2017 +0100

    New upstream version 0.9.3
---
 Installer_jre.eit                                  |  Bin 0 -> 1363268 bytes
 Installer_nojre.eit                                |  Bin 0 -> 20380 bytes
 RKIToolsDoc/custom-cfg/common.xsl                  |   24 +
 RKIToolsDoc/custom-cfg/eclipse.xsl                 |   29 +
 RKIToolsDoc/custom-cfg/fo.xsl                      |   26 +
 RKIToolsDoc/custom-cfg/html.xsl                    |   29 +
 RKIToolsDoc/custom-cfg/htmlhelp.xsl                |   29 +
 RKIToolsDoc/custom-cfg/javahelp.xsl                |   29 +
 RKIToolsDoc/custom-cfg/local-entities.xml          |   19 +
 RKIToolsDoc/custom-cfg/localbuild.properties       |   22 +
 RKIToolsDoc/custom-cfg/localbuild.xml              |   32 +
 RKIToolsDoc/custom-cfg/manpages.xsl                |   29 +
 RKIToolsDoc/custom-cfg/rtf.xsl                     |   29 +
 RKIToolsDoc/custom-cfg/singlehtml.xsl              |   29 +
 RKIToolsDoc/custom-cfg/singlexhtml.xsl             |   29 +
 RKIToolsDoc/custom-cfg/slides.xsl                  |   29 +
 RKIToolsDoc/custom-cfg/style-common.css            |  453 +++++
 RKIToolsDoc/custom-cfg/style-eclipse.css           |  109 ++
 RKIToolsDoc/custom-cfg/style-javahelp.css          |   76 +
 RKIToolsDoc/custom-cfg/wordml.xsl                  |   29 +
 RKIToolsDoc/custom-cfg/xhtml.xsl                   |   29 +
 RKIToolsDoc/input/RKIToolsDoc.xml                  |   64 +
 RKIToolsDoc/input/book-include.xml                 |   30 +
 RKIToolsDoc/output/javahelp/hsviewer.jar           |  Bin 0 -> 32193 bytes
 RKIToolsDoc/output/javahelp/jh.jar                 |  Bin 0 -> 531676 bytes
 applet.policy                                      |    3 +
 build-before-profiler.xml                          |   69 +
 build.xml                                          |   74 +
 debian/changelog                                   |    5 -
 debian/compat                                      |    1 -
 debian/control                                     |   27 -
 debian/copyright                                   |   13 -
 debian/rules                                       |    6 -
 debian/source/format                               |    1 -
 debian/upstream/metadata                           |   13 -
 debian/watch                                       |    3 -
 helpSetMaker/docuData/RKIToolsExample.fasta        |   32 +
 helpSetMaker/docuData/analyzeMenu.png              |  Bin 0 -> 15287 bytes
 helpSetMaker/docuData/editMenu.png                 |  Bin 0 -> 6388 bytes
 helpSetMaker/docuData/fileMenu.png                 |  Bin 0 -> 4400 bytes
 helpSetMaker/docuData/helpMenu.png                 |  Bin 0 -> 1362 bytes
 helpSetMaker/docuData/mainWindow.png               |  Bin 0 -> 32808 bytes
 helpSetMaker/docuData/namesPane.png                |  Bin 0 -> 4548 bytes
 helpSetMaker/docuData/primer1.png                  |  Bin 0 -> 2453 bytes
 helpSetMaker/docuData/primerProduct.png            |  Bin 0 -> 5071 bytes
 helpSetMaker/docuData/pyrograms.png                |  Bin 0 -> 9796 bytes
 helpSetMaker/docuData/resizingSelection.png        |  Bin 0 -> 3352 bytes
 helpSetMaker/docuData/sequencePane.png             |  Bin 0 -> 6336 bytes
 helpSetMaker/docuData/settings.png                 |  Bin 0 -> 21021 bytes
 helpSetMaker/docuData/toolbar.png                  |  Bin 0 -> 3569 bytes
 helpSetMaker/docuData/viewMenu.png                 |  Bin 0 -> 3498 bytes
 helpSetMaker/hs/0844fec5.html                      |   25 +
 helpSetMaker/hs/268013c8.html                      |   10 +
 helpSetMaker/hs/2d4d2587.html                      |   29 +
 helpSetMaker/hs/35271893.html                      |   13 +
 helpSetMaker/hs/3e7a5715.html                      |   28 +
 helpSetMaker/hs/4ecd38e2.html                      |   34 +
 helpSetMaker/hs/6036f840.html                      |   10 +
 helpSetMaker/hs/6bc41f84.html                      |   12 +
 helpSetMaker/hs/86d0b0a1.html                      |   15 +
 helpSetMaker/hs/87de535b.html                      |   14 +
 helpSetMaker/hs/98c149b5.html                      |   15 +
 helpSetMaker/hs/9d452f38.html                      |   13 +
 helpSetMaker/hs/9ee3d3c6.html                      |   19 +
 helpSetMaker/hs/JavaHelpSearch/DOCS                |  Bin 0 -> 1349 bytes
 helpSetMaker/hs/JavaHelpSearch/DOCS.TAB            |    7 +
 helpSetMaker/hs/JavaHelpSearch/OFFSETS             |    2 +
 helpSetMaker/hs/JavaHelpSearch/POSITIONS           |  Bin 0 -> 2926 bytes
 helpSetMaker/hs/JavaHelpSearch/SCHEMA              |    2 +
 helpSetMaker/hs/JavaHelpSearch/TMAP                |  Bin 0 -> 8192 bytes
 helpSetMaker/hs/aa49edd7.html                      |   10 +
 helpSetMaker/hs/ae869282.html                      |   10 +
 helpSetMaker/hs/b139c808.html                      |   10 +
 helpSetMaker/hs/b69463fa.html                      |   16 +
 helpSetMaker/hs/c9e02254.html                      |   12 +
 helpSetMaker/hs/e9fd53d0.html                      |   31 +
 helpSetMaker/hs/ec633545.html                      |   10 +
 helpSetMaker/hs/f19dc10a.html                      |   32 +
 helpSetMaker/hs/main.hs                            |   23 +
 helpSetMaker/hs/map.jhm                            |   25 +
 helpSetMaker/hs/pics/analyzeMenu.png               |  Bin 0 -> 15287 bytes
 helpSetMaker/hs/pics/editMenu.png                  |  Bin 0 -> 6388 bytes
 helpSetMaker/hs/pics/fileMenu.png                  |  Bin 0 -> 4400 bytes
 helpSetMaker/hs/pics/mainWindow.png                |  Bin 0 -> 32808 bytes
 helpSetMaker/hs/pics/namesPane.png                 |  Bin 0 -> 4548 bytes
 helpSetMaker/hs/pics/primer1.png                   |  Bin 0 -> 2453 bytes
 helpSetMaker/hs/pics/primerProduct.png             |  Bin 0 -> 5071 bytes
 helpSetMaker/hs/pics/pyrograms.png                 |  Bin 0 -> 9796 bytes
 helpSetMaker/hs/pics/resizingSelection.png         |  Bin 0 -> 3352 bytes
 helpSetMaker/hs/pics/sequencePane.png              |  Bin 0 -> 6336 bytes
 helpSetMaker/hs/pics/settings.png                  |  Bin 0 -> 21021 bytes
 helpSetMaker/hs/pics/toolbar.png                   |  Bin 0 -> 3569 bytes
 helpSetMaker/hs/pics/viewMenu.png                  |  Bin 0 -> 3498 bytes
 helpSetMaker/hs/toc.xml                            |   31 +
 helpSetMaker/hsm.xml                               |  288 +++
 helpSetMaker/html/0844fec5.html                    |   31 +
 helpSetMaker/html/268013c8.html                    |   16 +
 helpSetMaker/html/2d4d2587.html                    |   35 +
 helpSetMaker/html/35271893.html                    |   19 +
 helpSetMaker/html/3e7a5715.html                    |   34 +
 helpSetMaker/html/4ecd38e2.html                    |   40 +
 helpSetMaker/html/6036f840.html                    |   16 +
 helpSetMaker/html/6bc41f84.html                    |   18 +
 helpSetMaker/html/86d0b0a1.html                    |   21 +
 helpSetMaker/html/87de535b.html                    |   20 +
 helpSetMaker/html/98c149b5.html                    |   21 +
 helpSetMaker/html/9d452f38.html                    |   19 +
 helpSetMaker/html/9ee3d3c6.html                    |   25 +
 helpSetMaker/html/aa49edd7.html                    |   16 +
 helpSetMaker/html/ae869282.html                    |   16 +
 helpSetMaker/html/b139c808.html                    |   16 +
 helpSetMaker/html/b69463fa.html                    |   22 +
 helpSetMaker/html/c9e02254.html                    |   18 +
 helpSetMaker/html/e9fd53d0.html                    |   37 +
 helpSetMaker/html/ec633545.html                    |   16 +
 helpSetMaker/html/f19dc10a.html                    |   38 +
 helpSetMaker/html/index.html                       |   10 +
 helpSetMaker/html/pics/analyzeMenu.png             |  Bin 0 -> 15287 bytes
 helpSetMaker/html/pics/editMenu.png                |  Bin 0 -> 6388 bytes
 helpSetMaker/html/pics/fileMenu.png                |  Bin 0 -> 4400 bytes
 helpSetMaker/html/pics/mainWindow.png              |  Bin 0 -> 32808 bytes
 helpSetMaker/html/pics/namesPane.png               |  Bin 0 -> 4548 bytes
 helpSetMaker/html/pics/primer1.png                 |  Bin 0 -> 2453 bytes
 helpSetMaker/html/pics/primerProduct.png           |  Bin 0 -> 5071 bytes
 helpSetMaker/html/pics/pyrograms.png               |  Bin 0 -> 9796 bytes
 helpSetMaker/html/pics/resizingSelection.png       |  Bin 0 -> 3352 bytes
 helpSetMaker/html/pics/sequencePane.png            |  Bin 0 -> 6336 bytes
 helpSetMaker/html/pics/settings.png                |  Bin 0 -> 21021 bytes
 helpSetMaker/html/pics/toolbar.png                 |  Bin 0 -> 3569 bytes
 helpSetMaker/html/pics/viewMenu.png                |  Bin 0 -> 3498 bytes
 helpSetMaker/html/toc.html                         |   34 +
 helpSetMaker/latex/doc.aux                         |   13 +
 helpSetMaker/latex/doc.log                         |  268 +++
 helpSetMaker/latex/doc.pdf                         |  Bin 0 -> 20874 bytes
 helpSetMaker/latex/doc.tex                         |   26 +
 helpSetMaker/latex/doc.toc                         |    3 +
 helpSetMaker/presets/dabrowskiw.xml                |   36 +
 helpSetMaker/src/0844fec5.stml                     |   11 +
 helpSetMaker/src/268013c8.stml                     |    4 +
 helpSetMaker/src/2d4d2587.stml                     |   15 +
 helpSetMaker/src/35271893.stml                     |    6 +
 helpSetMaker/src/3e7a5715.stml                     |   20 +
 helpSetMaker/src/4ecd38e2.stml                     |   17 +
 helpSetMaker/src/6036f840.stml                     |    3 +
 helpSetMaker/src/6bc41f84.stml                     |    5 +
 helpSetMaker/src/86d0b0a1.stml                     |    7 +
 helpSetMaker/src/87de535b.stml                     |    8 +
 helpSetMaker/src/98c149b5.stml                     |    8 +
 helpSetMaker/src/9d452f38.stml                     |    5 +
 helpSetMaker/src/9ee3d3c6.stml                     |   12 +
 helpSetMaker/src/aa49edd7.stml                     |    3 +
 helpSetMaker/src/ae869282.stml                     |    3 +
 helpSetMaker/src/b139c808.stml                     |    3 +
 helpSetMaker/src/b69463fa.stml                     |   10 +
 helpSetMaker/src/c9e02254.stml                     |    5 +
 helpSetMaker/src/e9fd53d0.stml                     |   17 +
 helpSetMaker/src/ec633545.stml                     |    3 +
 helpSetMaker/src/f19dc10a.stml                     |   19 +
 helpSetMaker/thumbnails/0e171431_100.jpg           |  Bin 0 -> 1834 bytes
 helpSetMaker/thumbnails/0e171431_200.jpg           |  Bin 0 -> 4566 bytes
 helpSetMaker/thumbnails/1ea36cbb_100.jpg           |  Bin 0 -> 1301 bytes
 helpSetMaker/thumbnails/1ea36cbb_200.jpg           |  Bin 0 -> 3367 bytes
 helpSetMaker/thumbnails/47bc4e12_100.jpg           |  Bin 0 -> 2043 bytes
 helpSetMaker/thumbnails/47bc4e12_200.jpg           |  Bin 0 -> 5908 bytes
 helpSetMaker/thumbnails/5031b155_100.jpg           |  Bin 0 -> 2460 bytes
 helpSetMaker/thumbnails/5031b155_200.jpg           |  Bin 0 -> 7769 bytes
 helpSetMaker/thumbnails/5cf69c5a_100.jpg           |  Bin 0 -> 1577 bytes
 helpSetMaker/thumbnails/70a6cf64_100.jpg           |  Bin 0 -> 2787 bytes
 helpSetMaker/thumbnails/70a6cf64_200.jpg           |  Bin 0 -> 6755 bytes
 helpSetMaker/thumbnails/8ee1d6f4_100.jpg           |  Bin 0 -> 2004 bytes
 helpSetMaker/thumbnails/90947dcc_100.jpg           |  Bin 0 -> 1165 bytes
 helpSetMaker/thumbnails/90947dcc_200.jpg           |  Bin 0 -> 2872 bytes
 helpSetMaker/thumbnails/99550228_100.jpg           |  Bin 0 -> 2235 bytes
 helpSetMaker/thumbnails/99550228_200.jpg           |  Bin 0 -> 7777 bytes
 helpSetMaker/thumbnails/b3efb285_100.jpg           |  Bin 0 -> 1479 bytes
 helpSetMaker/thumbnails/b3efb285_200.jpg           |  Bin 0 -> 4472 bytes
 helpSetMaker/thumbnails/c2400ae0_100.jpg           |  Bin 0 -> 4072 bytes
 helpSetMaker/thumbnails/d5635043_100.jpg           |  Bin 0 -> 1422 bytes
 helpSetMaker/thumbnails/e716f121_100.jpg           |  Bin 0 -> 923 bytes
 helpSetMaker/thumbnails/e716f121_200.jpg           |  Bin 0 -> 1660 bytes
 helpSetMaker/thumbnails/eab1139f_100.jpg           |  Bin 0 -> 1750 bytes
 helpSetMaker/thumbnails/eab1139f_200.jpg           |  Bin 0 -> 5408 bytes
 launch4j_jre.xml                                   |   22 +
 launch4j_nojre.xml                                 |   22 +
 manifest.mf                                        |    3 +
 nbproject/build-impl.xml                           | 1060 ++++++++++
 nbproject/build-impl.xml~                          |  709 +++++++
 nbproject/configs/JDK_1.5.properties               |    0
 nbproject/genfiles.properties                      |   11 +
 nbproject/private/config.properties                |    0
 nbproject/private/private.properties               |    7 +
 nbproject/private/private.xml                      |    4 +
 nbproject/private/profiler/attach.xml              |   12 +
 nbproject/private/profiler/configurations.xml      |  111 ++
 .../private/profiler/snapshot-1264676579774.nps    |  Bin 0 -> 242666 bytes
 .../private/profiler/snapshot-1264680472982.nps    |  Bin 0 -> 259793 bytes
 .../private/profiler/snapshot-1264680536100.nps    |  Bin 0 -> 260686 bytes
 nbproject/project.properties                       |   91 +
 nbproject/project.xml                              |   18 +
 resources/EditorName.png                           |  Bin 0 -> 7647 bytes
 resources/RKILogo.png                              |  Bin 0 -> 443 bytes
 resources/editor.ico                               |  Bin 0 -> 13094 bytes
 resources/icons/IUB.png                            |  Bin 0 -> 933 bytes
 resources/icons/help.png                           |  Bin 0 -> 786 bytes
 resources/icons/no_sequence_name.png               |  Bin 0 -> 1089 bytes
 resources/icons/non-IUB.png                        |  Bin 0 -> 894 bytes
 resources/icons/primer_display.png                 |  Bin 0 -> 914 bytes
 resources/icons/primer_length_display.png          |  Bin 0 -> 753 bytes
 resources/icons/primer_no_length_display.png       |  Bin 0 -> 739 bytes
 resources/icons/primer_no_temperature_display.png  |  Bin 0 -> 698 bytes
 resources/icons/primer_sequence_display.png        |  Bin 0 -> 923 bytes
 resources/icons/primer_temperature_display.png     |  Bin 0 -> 727 bytes
 resources/icons/sequence_name.png                  |  Bin 0 -> 982 bytes
 src/org/json/CDL.java                              |  261 +++
 src/org/json/Cookie.java                           |  169 ++
 src/org/json/CookieList.java                       |   90 +
 src/org/json/HTTP.java                             |  163 ++
 src/org/json/HTTPTokener.java                      |   77 +
 src/org/json/JSONArray.java                        |  934 +++++++++
 src/org/json/JSONException.java                    |   27 +
 src/org/json/JSONML.java                           |  455 +++++
 src/org/json/JSONObject.java                       | 1550 +++++++++++++++
 src/org/json/JSONString.java                       |   18 +
 src/org/json/JSONStringer.java                     |   78 +
 src/org/json/JSONTokener.java                      |  422 ++++
 src/org/json/JSONWriter.java                       |  323 +++
 src/org/json/Test.java                             |  624 ++++++
 src/org/json/XML.java                              |  437 +++++
 src/org/json/XMLTokener.java                       |  365 ++++
 src/org/rki/sequenceeditor/model/Alignment.java    |  499 +++++
 src/org/rki/sequenceeditor/model/Annotation.java   |   27 +
 .../rki/sequenceeditor/model/AnnotationList.java   |  117 ++
 src/org/rki/sequenceeditor/model/Base64.java       | 2053 ++++++++++++++++++++
 .../rki/sequenceeditor/model/BaseColorModel.java   |   22 +
 .../sequenceeditor/model/BaseColorModelMap.java    |   30 +
 .../sequenceeditor/model/ClientHttpRequest.java    |  552 ++++++
 src/org/rki/sequenceeditor/model/ColorModels.java  |  103 +
 src/org/rki/sequenceeditor/model/Data.java         |   18 +
 src/org/rki/sequenceeditor/model/Flowgram.java     |  143 ++
 src/org/rki/sequenceeditor/model/Globals.java      |   24 +
 src/org/rki/sequenceeditor/model/GroupKey.java     |   39 +
 src/org/rki/sequenceeditor/model/Letters.java      |  909 +++++++++
 .../rki/sequenceeditor/model/MasterSequence.java   |   33 +
 src/org/rki/sequenceeditor/model/Position.java     |   26 +
 src/org/rki/sequenceeditor/model/Primer.java       |  383 ++++
 src/org/rki/sequenceeditor/model/RKIFile.java      |   25 +
 src/org/rki/sequenceeditor/model/RKIFolder.java    |   25 +
 src/org/rki/sequenceeditor/model/SNP.java          |   13 +
 src/org/rki/sequenceeditor/model/Sequence.java     |  184 ++
 src/org/rki/sequenceeditor/model/Settings.java     |  191 ++
 src/org/rki/sequenceeditor/model/SizeMenuItem.java |   18 +
 .../rki/sequenceeditor/model/TripletMenuItem.java  |    9 +
 .../model/filters/BasicFastaFilter.java            |   77 +
 .../sequenceeditor/model/filters/FastaFilter.java  |  141 ++
 .../model/filters/GeneiousFilter.java              |  200 ++
 .../sequenceeditor/model/filters/LoadFilter.java   |   18 +
 .../sequenceeditor/model/filters/RSFFilter.java    |  281 +++
 .../sequenceeditor/model/filters/SaveFilter.java   |   17 +
 .../sequenceeditor/view/AnnotationTextField.java   |   17 +
 src/org/rki/sequenceeditor/view/BlingFilter.java   |   70 +
 .../sequenceeditor/view/ColorModelMenuItem.java    |   18 +
 src/org/rki/sequenceeditor/view/Editor.html        |   35 +
 src/org/rki/sequenceeditor/view/Editor.java        | 1399 +++++++++++++
 src/org/rki/sequenceeditor/view/EditorApp.java     | 1728 ++++++++++++++++
 .../rki/sequenceeditor/view/EditorInterface.java   |  107 +
 src/org/rki/sequenceeditor/view/EditorWindow.form  |  723 +++++++
 src/org/rki/sequenceeditor/view/EditorWindow.java  |  871 +++++++++
 src/org/rki/sequenceeditor/view/FindDialog.java    |   99 +
 src/org/rki/sequenceeditor/view/FlowFrame.form     |  146 ++
 src/org/rki/sequenceeditor/view/FlowFrame.java     |  200 ++
 src/org/rki/sequenceeditor/view/FlowPanel.java     |  123 ++
 src/org/rki/sequenceeditor/view/FlowViewer.java    |   51 +
 src/org/rki/sequenceeditor/view/GroupMenuItem.java |   27 +
 src/org/rki/sequenceeditor/view/IntDocument.java   |   29 +
 src/org/rki/sequenceeditor/view/Main.java          |   30 +
 src/org/rki/sequenceeditor/view/NamesPane.java     |  400 ++++
 src/org/rki/sequenceeditor/view/OptionsFrame.form  |  334 ++++
 src/org/rki/sequenceeditor/view/OptionsFrame.java  |  349 ++++
 .../rki/sequenceeditor/view/RKIFilesDialog.java    |  135 ++
 .../rki/sequenceeditor/view/RecentMenuItem.java    |   26 +
 src/org/rki/sequenceeditor/view/SequenceInfo.java  |   28 +
 src/org/rki/sequenceeditor/view/SequencePane.java  | 1448 ++++++++++++++
 src/org/rki/sequenceeditor/view/SequenceTip.java   |   32 +
 src/version.properties                             |    2 +
 284 files changed, 25833 insertions(+), 69 deletions(-)

diff --git a/Installer_jre.eit b/Installer_jre.eit
new file mode 100644
index 0000000..05dc61b
Binary files /dev/null and b/Installer_jre.eit differ
diff --git a/Installer_nojre.eit b/Installer_nojre.eit
new file mode 100644
index 0000000..17a8bce
Binary files /dev/null and b/Installer_nojre.eit differ
diff --git a/RKIToolsDoc/custom-cfg/common.xsl b/RKIToolsDoc/custom-cfg/common.xsl
new file mode 100644
index 0000000..13239cb
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/common.xsl
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:fo="http://www.w3.org/1999/XSL/Format"
+                version='1.0'>
+
+
+</xsl:stylesheet>
diff --git a/RKIToolsDoc/custom-cfg/eclipse.xsl b/RKIToolsDoc/custom-cfg/eclipse.xsl
new file mode 100644
index 0000000..817da32
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/eclipse.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+		version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/eclipse-book.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
diff --git a/RKIToolsDoc/custom-cfg/fo.xsl b/RKIToolsDoc/custom-cfg/fo.xsl
new file mode 100644
index 0000000..bee2136
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/fo.xsl
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:fo="http://www.w3.org/1999/XSL/Format"
+                version='1.0'>
+
+  <xsl:import href="../../../system/custom-xsl/fo-book.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
diff --git a/RKIToolsDoc/custom-cfg/html.xsl b/RKIToolsDoc/custom-cfg/html.xsl
new file mode 100644
index 0000000..042bd8a
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/html.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+		version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/html-book.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/RKIToolsDoc/custom-cfg/htmlhelp.xsl b/RKIToolsDoc/custom-cfg/htmlhelp.xsl
new file mode 100644
index 0000000..5462cd8
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/htmlhelp.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+		version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/htmlhelp-book.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/RKIToolsDoc/custom-cfg/javahelp.xsl b/RKIToolsDoc/custom-cfg/javahelp.xsl
new file mode 100644
index 0000000..50d5aee
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/javahelp.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+		version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/javahelp-book.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/RKIToolsDoc/custom-cfg/local-entities.xml b/RKIToolsDoc/custom-cfg/local-entities.xml
new file mode 100644
index 0000000..9f4216b
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/local-entities.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<!ENTITY local_entity "local entity (defined per document)">
diff --git a/RKIToolsDoc/custom-cfg/localbuild.properties b/RKIToolsDoc/custom-cfg/localbuild.properties
new file mode 100644
index 0000000..d6bef76
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/localbuild.properties
@@ -0,0 +1,22 @@
+# BEGIN Do not overwrite
+document.type = book
+# END Do not overwrite
+
+# Overwrite properties here
+
+# If you happen to have sub documents you can set here the document type of each one of those.
+#document.<sub_document_name>.type = article|book|set|website|slides...
+
+# These are needed for the 'eclipse' target
+eclipse.plugin.id=com.mycompany
+eclipse.plugin.name=Document Name
+eclipse.plugin.provider=My Company
+
+# The version of the eclipse plugin
+eclipse.plugin.version=${document.version}
+
+# The version of the document
+document.version = 1.0
+
+# The name of the folder whose content will be carbon copied to the output directory
+special.folder.name.carbonCopy=copy_to_output
diff --git a/RKIToolsDoc/custom-cfg/localbuild.xml b/RKIToolsDoc/custom-cfg/localbuild.xml
new file mode 100644
index 0000000..acd490d
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/localbuild.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<project>
+
+  <!--
+  You can add hooks here that perform your custom action at a given point.
+  Please see the manual (or the the file etc/build-output-formats.xml) for all
+  available hooks.
+  
+  Example:
+  
+  <target name="local-pre-init" >
+  </target>
+  -->
+
+</project>
\ No newline at end of file
diff --git a/RKIToolsDoc/custom-cfg/manpages.xsl b/RKIToolsDoc/custom-cfg/manpages.xsl
new file mode 100644
index 0000000..9a1b744
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/manpages.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+                version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/manpages.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
diff --git a/RKIToolsDoc/custom-cfg/rtf.xsl b/RKIToolsDoc/custom-cfg/rtf.xsl
new file mode 100644
index 0000000..da292db
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/rtf.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+		version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/rtf-book.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/RKIToolsDoc/custom-cfg/singlehtml.xsl b/RKIToolsDoc/custom-cfg/singlehtml.xsl
new file mode 100644
index 0000000..f433906
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/singlehtml.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+		version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/singlehtml-book.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/RKIToolsDoc/custom-cfg/singlexhtml.xsl b/RKIToolsDoc/custom-cfg/singlexhtml.xsl
new file mode 100644
index 0000000..2468973
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/singlexhtml.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+		version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/singlexhtml-book.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
diff --git a/RKIToolsDoc/custom-cfg/slides.xsl b/RKIToolsDoc/custom-cfg/slides.xsl
new file mode 100644
index 0000000..0153586
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/slides.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+                version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/slides.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
diff --git a/RKIToolsDoc/custom-cfg/style-common.css b/RKIToolsDoc/custom-cfg/style-common.css
new file mode 100644
index 0000000..b001aba
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/style-common.css
@@ -0,0 +1,453 @@
+/* Basic Settings:                                                            */
+
+body {
+	background-color: White; /* black foreground */
+	color: Black; /* center the body content in browser window */
+	margin: auto; /* padding ("inner margin") leaves space between */
+	padding: 24px; /* set width according to browser window width */
+	width: auto; /* text alignment */
+	text-align: justify; /* text-align: left; */
+}
+
+/* para */
+p {
+  /* font size, line height, font */
+  /* list of fonts provides fallbacks if a font is not present */
+  font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif;
+
+  /* margin (top - right - bottom - left) */
+  margin: 0 15px 6px 15px;
+}
+
+
+
+
+/* NEEDS TO BE CLEARED UP */
+
+
+p, td, li, dt, dd
+{
+  /* font size, line height, font */
+  /* list of fonts provides fallbacks if a font is not present */
+  font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif;
+}
+
+
+
+/* set font for most elements                    */
+/* p: paragraphs (regular text, docbook <para>)  */
+/* (...) */
+/* body: anything else  */
+body, p, td, li, dt, dd,
+{
+/* set font size and line height                             */
+/* list of fonts provides fallbacks if a font is not present */
+font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif;
+}
+
+/* images */
+/* docbook: <imageobject> */
+img {
+/* no margin */
+margin: 0;
+
+/* no padding ("inner margin") */
+padding: 0;
+
+/* no border */
+border: 0;
+}
+
+
+/* emphasized text, can occur in most places */
+/* docbook: <emphasis> */
+em {
+/* bold face, higher number is more bold */
+font-weight: 600;
+/* italic */
+font-style: italic;
+}
+
+
+/* sect(ion)1 title */
+h2 {
+	font-family: Georgia, Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */
+	font-size: 125%; /* bold face, higher number is more bold */
+	font-weight: 600; /* underlined text */
+	text-decoration: none; /* foreground color: dark blue */
+	color: Black; /* background color: gray */
+	background-color: Orange; /* margin settings are top - right - bottom - left (think clockwise) */
+	margin: 15px 0 15px 0; /* padding ("inner margin") settings are top - right - bottom - left */
+/* (think clockwise)                                                 */
+	padding: 8px 15px 8px 15px; 
+	/* border: 1px solid #000; */
+}
+
+
+/* sect(ion)2 title */
+h3 {
+	font-family: Georgia, Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */
+	font-size: 110%; /* bold face, higher number is more bold */
+	font-weight: 600; /* underlined text */
+	text-decoration: none; /* foreground color: dark blue */
+	color: Black; /* background-color is a very light grey */
+	background-color: #fefefe; /* padding ("inner margin") settings are top - right - bottom - left */
+/* (think clockwise)                                                 */
+	padding: 0 0 0 15px;
+}
+
+
+/* sect(ion)3 title */
+h4 {
+	font-family: Georgia, Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */
+	font-size: 100%; /* bold face, higher number is more bold */
+	font-weight: 600; /* underlined text */
+	text-decoration: none; /* foreground color: dark blue */
+	color: Black; /* background-color is a very light grey */
+	background-color: #fefefe; /* padding ("inner margin") settings are top - right - bottom - left */
+/* (think clockwise)                                                 */
+	padding: 0 0 0 15px;
+}
+
+
+/* sect(ion)4 title */
+h5 {
+	font-family: Georgia, Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */
+	font-size: 100%; /* bold face, higher number is more bold */
+	font-weight: 300; /* not underlined */
+	text-decoration: none; /* foreground color: dark blue */
+	color: Black; /* background-color is a very light grey */
+	background-color: #fefefe; /* padding ("inner margin") settings are top - right - bottom - left */
+/* (think clockwise)                                                 */
+	padding: 0 0 0 15px;
+}
+
+/* the following formats refer to the docbook tags of the same name           */
+/* for more information, see the docbook reference at                         */
+/* http://www.docbook.org/tdg/en/html/docbook.html                            */
+
+.mediaobject
+{
+/* center */
+text-align: center;
+}
+
+
+/*  */
+.calloutlist, .figure, .table
+{
+/* margin settings are top - right - bottom - left (think clockwise) */
+margin: 15px 30px 15px 30px;
+}
+
+
+/*  */
+.itemizedlist, .variablelist {
+/* margin settings are top - right - bottom - left (think clockwise) */
+margin: 15px 30px 15px 15px;
+}
+
+/* blockquote formatting is a little more complex    */
+/* because block quotes are rendered as a html table */
+
+/* blockquote block */
+.blockquote
+{
+/* override bottom margin, the other margins are inherited */
+margin-bottom: 30px;
+}
+
+.blockquote p, .blockquote td
+{
+/* set font size and line height                             */
+/* list of fonts provides fallbacks if a font is not present */
+font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif;
+
+/* bold face, higher number is more bold */
+font-weight: 450;
+}
+
+
+.epigraph
+{
+/* override bottom margin, the other margins are inherited */
+margin-bottom: 30px;
+}
+
+.epigraph p, .epigraph td
+{
+/* set font size and line height                             */
+/* list of fonts provides fallbacks if a font is not present */
+font: 10px/14px Verdana, Arial, Helvetica, Sans-Serif;
+
+/* bold face, higher number is more bold */
+font-weight: 600;
+}
+
+
+
+/* custom header and footer that are displayed on all pages */
+#customheader, #customfooter
+{
+/* list of fonts provides fallbacks if a font is not present */
+font-family: Verdana, Arial, Helvetica, Sans-Serif;
+
+/* font size, relative to body font size */
+font-size: 80%;
+
+/* line height, relative to body font size */
+line-height: 200%;
+
+
+text-align: center;
+vertical-align: middle;
+color: #fff;
+background-color: #009;
+}
+
+
+/* leave more space between last paragraph and footer  */
+/* some browser do not add up the bottom margin of the prior element */
+/* and the top margin of the footer */
+#customfooter {
+margin-top: 15px;
+}
+
+
+
+/* table { margin: 0 15px 6px 15px; } */
+
+
+/* title and navigation links in header and footer */
+.navheader th, .navheader td, .navfooter th, .navfooter td
+{
+font-size: 11px;
+font-weight: 450;
+}
+
+
+/* table of contents, list of figures and list of tables */
+.toc, .list-of-figures, .list-of-tables, .list-of-examples
+{
+/* margin settings are top - right - bottom - left (think clockwise) */
+margin: 15px 30px 15px 15px;
+}
+
+
+/* the "headings" are rendered as paragraphs */
+.toc p, .list-of-figures p, .list-of-tables p, .list-of-examples p
+{
+/* no margin */
+margin: 0;
+}
+
+
+.figure
+{
+/* margin settings are top - right - bottom - left (think clockwise) */
+margin: 5px 5px 5px 5px;
+
+/* no padding ("inner border") */
+padding: 0;
+
+/* no border */
+border: 0;
+
+/* center text */
+text-align: center;
+}
+
+
+/* figure title */
+.figure p, .table p, .example p
+{
+font-size: 80%;
+}
+
+
+/*
+acronym {
+      border-bottom: 1px dashed #00cc00;
+      cursor: help;
+}
+*/
+
+
+/* admonition headings */
+div.note, div.important, div.warning, div.caution, div.tip
+{
+padding: 0px 15px 0px 0px;
+}
+
+div.note th, div.important th, div.warning th, div.caution th, div.tip th
+{
+/* set font size and line height                             */
+/* list of fonts provides fallbacks if a font is not present */
+font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif;
+
+font-weight: 600;
+
+text-decoration: underline;
+
+/* left align */
+text-align: left;
+}
+
+.note p, .important p, .warning p, .caution p, .tip p
+{
+margin: 0;
+}
+
+.note img, .important img, .warning img, .caution img, .tip img
+{
+margin: 0px 15px 0px 15px;
+}
+
+
+/* programlisting */
+pre.programlisting
+{
+/* non-proportional font */
+/* list of fonts provides fallbacks if a font is not present */
+font-family: "Courier New", Courier, Monospace;
+
+/* color: black */
+color: #000;
+
+/* background color: gray */
+background-color: #eee;
+
+/* no margin */
+margin: 0;
+
+/* gray dotted border, 1 px wide */
+border: 1px dotted #ddd;
+
+/* padding ("inner margin") settings are top - right - bottom - left */
+/* (think clockwise)                                                 */
+padding: 6px 6px 6px 6px;
+}
+
+
+/* title page */
+
+
+/* heading1 is used for document title */
+h1
+{
+	font-family: Georgia,Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */
+	font-size: 150%; /* bold face, higher number is more bold */
+	font-weight: 600; /* line height, relative to body line height */
+	line-height: 250%; /* center */
+	text-align: center; /* foreground color: dark blue */
+	color: Black; /* background color: gray */
+	background-color: Orange; /* margin settings are top - right - bottom - left (think clockwise) */
+	margin: 15px 0 15px 0; /* no padding ("inner margin") */
+	padding: 15;
+	border: 1px solid #000;	
+}
+
+
+
+/* author on title page is formatted as h3          */
+/* these settings overwrite the regular h3 settings */
+h3.author {
+/* set font size and line height                             */
+/* list of fonts provides fallbacks in case selected fonts are not present */
+font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif;
+
+/* bold face, higher number is more bold */
+font-weight: 600;
+
+/* do not underline */
+text-decoration: none;
+
+/* center text */
+text-align: center;
+
+/* color: black */
+color: #000;
+
+/* background-color is a very light grey */
+/* alternative: #fff = white             */
+background-color: #fefefe;
+
+/* margin settings are top - right - bottom - left (think clockwise) */
+margin: 0 15px 15px 15px;
+
+/* no padding */
+padding: 0;
+
+/* no border */
+border: 0;
+}
+
+
+/* copyright and date */
+.copyright, .pubdate
+{
+/* list of fonts provides fallbacks if a font is not present */
+font-family: Verdana, Arial, Helvetica, Sans-Serif;
+
+/* font size, relative to body font size */
+font-size: 90%;
+
+/* center */
+text-align: center;
+
+/* margin settings are top - right - bottom - left (think clockwise) */
+margin: 15px 15px 15px 15px;
+
+/* no padding ("inner margin") */
+padding: 0;
+
+/* no border */
+border: 0;
+}
+
+
+/* legal notice box */
+div.legalnotice
+{
+	font-family: Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */
+	font-size: 90%; /* color: black */
+	color: #000; /* background color: gray */
+	background-color: Orange; /* margin settings are top - right - bottom - left (think clockwise) */
+	margin: 10px 45px 10px 45px; /* padding ("inner margin") settings are top - right - bottom - left */
+	padding: 5px 5px 5px 5px; /* solid black border, 1px wide */
+	border: 1px solid #000;
+}
+
+
+table {
+	/* border: thin solid orange; */
+	border-spacing: 0pt;
+	margin-top: 5;
+	margin-bottom: 5;
+}
+
+td {
+	font-family: SansSerif, Arial, Helvetica, sans-serif;
+    padding-left: 1;
+    padding-right: 1;
+    padding-top: 1;
+    padding-bottom: 1	
+}
+
+th {
+	 /* border: thin solid orange; */	 
+    padding-left: 1;
+    padding-right: 1;
+    padding-top: 1;
+    padding-bottom: 1	
+}
+
+.informaltable {
+   border-collapse: collapse;
+	table-layout: auto;
+}
+
+.revhistory {
+   border-collapse: collapse;
+	table-layout: auto;
+}
\ No newline at end of file
diff --git a/RKIToolsDoc/custom-cfg/style-eclipse.css b/RKIToolsDoc/custom-cfg/style-eclipse.css
new file mode 100644
index 0000000..f43bf3e
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/style-eclipse.css
@@ -0,0 +1,109 @@
+body  {font-size: 10pt;
+	font-family: SansSerif, Arial, Helvetica, sans-serif;
+	margin-left: 10;
+	margin-right: 5;
+	color: Black;
+	background-color: White}
+
+h1 {
+  font-size: 18pt;
+}
+
+h2 {
+  font-size: 16pt;
+}
+
+h3 {
+  font-size: 14pt;
+}
+
+h4 {
+  font-size: 12pt;
+}
+
+table {
+  font-size: 10pt;
+  border-style: none;
+  border-color: silver;
+  margin-top: 5;
+  margin-bottom: 5
+}
+
+td {font-size: 10pt;
+    font-family: SansSerif, Arial, Helvetica, sans-serif;
+    border-color: silver;
+    padding-left: 1;
+    padding-right: 1;
+    padding-top: 1;
+    padding-bottom: 1}
+
+th {border-style: none;
+    font-weight: bold;
+    border-color: silver;
+    padding-left: 1;
+    padding-right: 1;
+    padding-top: 1;
+    padding-bottom: 1}
+
+kbd {
+  font-family: monospace;
+  font-weight: bold;
+}
+
+var {
+  font-style: italic;
+}
+
+ol {
+  margin-bottom: 1em;
+}
+
+dt {
+  font-weight: bold;
+  margin-top: 1em;
+}
+
+li {
+  margin-top: 1em;
+}
+
+span.control {
+  font-weight: bold;
+}
+
+span.name {
+  font-style: italic;
+  font-weight: bold;
+}
+
+span.action {
+  font-style: italic;
+}
+
+span.code {
+  font-family: monospace;
+}
+
+span.menu {
+  color: #660033;
+  font-weight: bold;
+}
+
+span.filefolder {
+  font-family: monospace;
+}
+
+blockquote {
+  background-color: #e8e8e8;
+  border: 1pt black;
+  margin: 2em; border: 1px solid black;
+  padding: 1em;
+}
+
+.tasks, .reference, .faq {
+  padding-left: 18px;
+  font-size: 14pt;
+  background-image:url(images/bullet14.png);
+  background-repeat: no-repeat;
+  background-position: left;
+ }
\ No newline at end of file
diff --git a/RKIToolsDoc/custom-cfg/style-javahelp.css b/RKIToolsDoc/custom-cfg/style-javahelp.css
new file mode 100644
index 0000000..29440e5
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/style-javahelp.css
@@ -0,0 +1,76 @@
+/*
+ * jhexamples.css      06/17/2003
+ *
+ * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ */
+
+body  {font-size: 12pt;
+	font-family: SansSerif, Arial, Helvetica, sans-serif;
+	margin-left: 10;
+	margin-right: 5;
+	color: Black;
+	background-color: White}
+
+p  {font-size: 12pt;
+     margin-top: 5;
+     margin-bottom: 5}
+
+
+h1 { font-size: 22pt;
+     font-weight: bold;
+     margin-top: 0;
+     margin-bottom: 10}
+
+h2 { font-size: 18pt;
+     font-weight: bold;
+     margin-top: 20;
+     margin-bottom: 10}
+
+h3 { font-size: 14pt;
+     font-weight: bold;
+     margin-top: 10;
+     margin-bottom: 5}
+
+h4 { font-size: 12pt;
+     font-weight: bold;
+     margin-top: 10;
+     margin-bottom: 5}
+
+ol {margin-top: 5;
+     margin-bottom: 0;
+     margin-left: 30}
+
+li {margin-top: 0;
+    margin-bottom: 5}
+        
+li p{margin-top: 5;
+        margin-bottom: 0}
+
+ul {margin-top: 5;
+    margin-bottom: 0;
+    margin-left: 30}
+        
+table {border-style: none;
+       border-color: silver;
+       margin-top: 5;
+       margin-bottom: 5}
+
+td {font-size: 12pt;
+    font-family: SansSerif, Arial, Helvetica, sans-serif;
+    border-color: silver;
+    padding-left: 1;
+    padding-right: 1;
+    padding-top: 1;
+    padding-bottom: 1}
+
+th {border-style: none;
+    border-color: silver;
+    padding-left: 1;
+    padding-right: 1;
+    padding-top: 1;
+    padding-bottom: 1}
+
+small {font-size: x-small}
+
diff --git a/RKIToolsDoc/custom-cfg/wordml.xsl b/RKIToolsDoc/custom-cfg/wordml.xsl
new file mode 100644
index 0000000..3eecdf5
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/wordml.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+                version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/wordml-book.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
diff --git a/RKIToolsDoc/custom-cfg/xhtml.xsl b/RKIToolsDoc/custom-cfg/xhtml.xsl
new file mode 100644
index 0000000..2ced74b
--- /dev/null
+++ b/RKIToolsDoc/custom-cfg/xhtml.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+                xmlns:doc="http://nwalsh.com/xsl/documentation/1.0"
+                xmlns:exsl="http://exslt.org/common"
+                xmlns:set="http://exslt.org/sets"
+		version="1.0"
+                exclude-result-prefixes="doc exsl set">
+
+  <xsl:import href="../../../system/custom-xsl/xhtml-book.xsl"/>
+  <xsl:import href="common.xsl"/>
+
+</xsl:stylesheet>
diff --git a/RKIToolsDoc/input/RKIToolsDoc.xml b/RKIToolsDoc/input/RKIToolsDoc.xml
new file mode 100644
index 0000000..398f4da
--- /dev/null
+++ b/RKIToolsDoc/input/RKIToolsDoc.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- This file is part of DobuDish                                           -->
+
+<!-- DobuDish is free software; you can redistribute it and/or modify        -->
+<!-- it under the terms of the GNU General Public License as published by    -->
+<!-- the Free Software Foundation; either version 2 of the License, or       -->
+<!-- (at your option) any later version.                                     -->
+
+<!-- DobuDish is distributed in the hope that it will be useful,             -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of          -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           -->
+<!-- GNU General Public License for more details.                            -->
+
+<!-- You should have received a copy of the GNU General Public License       -->
+<!-- along with DobuDish; if not, write to the Free Software                 -->
+<!-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+          "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
+  [
+    <!ENTITY % global.entities SYSTEM "../../../system/custom-xsl/global-entities.xml">
+    %global.entities;
+
+    <!ENTITY % entities SYSTEM "../custom-cfg/local-entities.xml">
+    %entities;
+  ]
+>
+
+<book lang="en">
+
+  <bookinfo>
+
+   <title>Book Title</title>
+    <pubdate>2006</pubdate>
+    <copyright>
+      <year>2006</year>
+      <holder>AGYNAMIX</holder>
+    </copyright>
+
+  </bookinfo>
+
+<chapter>
+  <title>Chapter</title>
+
+  <sect1>
+    <title>Section 1 </title>
+
+    <para>
+      We can provide a framework for, but you have to write the text.
+    </para>
+
+  </sect1>
+
+</chapter>
+
+<!-- Via XInclude we can include document parts
+     You can use Xalan's xpointer features to select parts of your included document
+     or include all of it.
+-->
+<xi:include href="book-include.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+
+</book>
diff --git a/RKIToolsDoc/input/book-include.xml b/RKIToolsDoc/input/book-include.xml
new file mode 100644
index 0000000..244c9c3
--- /dev/null
+++ b/RKIToolsDoc/input/book-include.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+          "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
+  [
+    <!ENTITY % global.entities SYSTEM "../../../system/custom-xsl/global-entities.xml">
+    %global.entities;
+
+    <!ENTITY % entities SYSTEM "../custom-cfg/local-entities.xml">
+    %entities;
+  ]
+>
+
+<ximy:includelist xmlns:ximy="http://www.agynamix.de/XincludeExtension">
+
+<chapter>
+  <title>An included Chapter</title>
+
+  <sect1>
+    <title>First Section</title>
+
+    <para>
+      This text comes from an xincluded document.
+    </para>
+
+  </sect1>
+
+</chapter>
+
+</ximy:includelist>
diff --git a/RKIToolsDoc/output/javahelp/hsviewer.jar b/RKIToolsDoc/output/javahelp/hsviewer.jar
new file mode 100644
index 0000000..565d7a9
Binary files /dev/null and b/RKIToolsDoc/output/javahelp/hsviewer.jar differ
diff --git a/RKIToolsDoc/output/javahelp/jh.jar b/RKIToolsDoc/output/javahelp/jh.jar
new file mode 100644
index 0000000..c38233a
Binary files /dev/null and b/RKIToolsDoc/output/javahelp/jh.jar differ
diff --git a/applet.policy b/applet.policy
new file mode 100644
index 0000000..53a9d40
--- /dev/null
+++ b/applet.policy
@@ -0,0 +1,3 @@
+grant {
+permission java.security.AllPermission;
+};
diff --git a/build-before-profiler.xml b/build-before-profiler.xml
new file mode 100644
index 0000000..1b515b6
--- /dev/null
+++ b/build-before-profiler.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<project name="SequenceEditor" default="default" basedir=".">
+    <description>Builds, tests, and runs the project SequenceEditor.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="SequenceEditor-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..bfcfa93
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="SequenceEditor" default="default" basedir=".">
+    <description>Builds, tests, and runs the project SequenceEditor.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="SequenceEditor-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index 35106a6..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,5 +0,0 @@
-mpsqed (0.9.3-1) unstable; urgency=low
-
-  * Initial release (Closes: #<bug>)
-
- -- Andreas Tille <tille at debian.org>  Thu, 14 Jun 2012 14:21:03 +0200
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index f599e28..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-10
diff --git a/debian/control b/debian/control
deleted file mode 100644
index c9ea14a..0000000
--- a/debian/control
+++ /dev/null
@@ -1,27 +0,0 @@
-Source: mpsqed
-Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Andreas Tille <tille at debian.org>
-Section: science
-Priority: optional
-Build-Depends: debhelper (>= 10)
-Standards-Version: 3.9.8
-Vcs-Browser: https://anonscm.debian.org/viewvc/debian-med/trunk/packages/mpsqed/trunk/
-Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/mpsqed/trunk/
-Homepage: http://sourceforge.net/projects/mpsqed/
-
-Package: mpsqed
-Architecture: any
-Depends: ${shlibs:Depends},
-         ${misc:Depends}
-Description: alignment editor and multiplex pyrosequencing assay designer
- Molecular-based diagnostic assays are the gold standard for infectious
- diseases today, since they allow a rapid and sensitive identification
- and typing of various pathogens. While PCR can be designed to be
- specific for a certain pathogen, a subsequent sequence analysis is
- frequently required for confirmation or typing. The design of
- appropriate PCR-based assays is a complex task, especially when
- conserved discriminating polymorphisms are rare or if the number of
- types which need to be differentiated is high. One extremely useful but
- underused method for this purpose is the multiplex pyrosequencing
- technique. mPSQed is a program developed at the Robert Koch Institute
- and targeted at facilitating the creation of such assays.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index 952082b..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,13 +0,0 @@
-Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: mPSQed
-Upstream-Contact: DabrowskiW at rki.de
-Source: http://sourceforge.net/projects/mpsqed/files/
-
-Files: *
-Copyright: © 2011-2012 Piotr Wojtek Dabrowski <DabrowskiW at rki.de>
-                       Andreas Nitsche <NitscheA at rki.de>
-License: LGPL-2+
-
-Files: debian/*
-Copyright: © 2012 Andreas Tille <tille at debian.org>
-License: LGPL-2+
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index 6055261..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/make -f
-
-# DH_VERBOSE := 1
-
-%:
-	dh $@
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
deleted file mode 100644
index ac3b213..0000000
--- a/debian/upstream/metadata
+++ /dev/null
@@ -1,13 +0,0 @@
-Reference:
-  Author: Piotr Wojtek Dabrowski and Andreas Nitsche
-  Title: "mPSQed: A Software for the Design of Multiplex Pyrosequencing Assays"
-  Journal: PLoS One
-  Year: 2012
-  Volume: 7
-  Number: 6
-  Pages: e38140
-  DOI: 10.1371/journal.pone.0038140
-  PMID: 22675516
-  URL: http://www.plosone.org/article/info%3Adoi%2F10.1371%2Fjournal.pone.0038140
-  eprint: http://www.plosone.org/article/fetchObjectAttachment.action?uri=info%3Adoi%2F10.1371%2Fjournal.pone.0038140&representation=PDF
-
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index 4c96ef8..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,3 +0,0 @@
-# That's only the binary JAR distribution
-#version=3
-#http://sf.net/mpsqed/mPSQed\.(\d[\d\.]+)\.(?:tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
diff --git a/helpSetMaker/docuData/RKIToolsExample.fasta b/helpSetMaker/docuData/RKIToolsExample.fasta
new file mode 100644
index 0000000..26339ae
--- /dev/null
+++ b/helpSetMaker/docuData/RKIToolsExample.fasta
@@ -0,0 +1,32 @@
+>1.1
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCATGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCTTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>1.2
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCATGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCTTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>1.3
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCATGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCTTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>1.4
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCATGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCTTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>1.5
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCATGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCTTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>1.6
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCATGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCTTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>1.7
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCATGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCTTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>1.8 
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCATGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCTTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>1.9
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCATGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCTTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>1.10
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCATGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCTTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>2.1
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCACGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCCTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>2.2
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCACGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCCTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>2.3
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCACGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCCTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>2.4
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCACGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCCTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>2.5
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCACGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCCTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
+>2.6 
+CAGAAAATCCAGCTACTATAATAGGCTCACCGATGATCATTGGCAAAATCCTATATTGTACCAGATTAATGAGAGCATATTTCATTTCCAATAATTCTGCTAGTTCTTGAGACATTGATTTATTTGATGAATCTAGTTGGTTCTCTAGATACTCTACCATTTCTGCCGCATACAATAACTTGTTAGATAAAATCAGGGTTATCAAAGTGTTTAGCGTGGCTAGAATAGTGGGCTTGCACGTATTAAAGAATGCGGTAGTATGAGTAAACCGTTTTAACGAATTATATAGTCTCCAGAAATCTGTGGCGTTGCATACATGAGCTGAATGACATCGAAGATTGTCCAATATTTTTAATAGCTGCTCCTTGTCCATTATTTCTATATTTGACTCGCAACAATTGTAGATACCATTAATCACCGATTCCTTTTTCGATGCTGGACAATAGCACAATTGTTTAGCTTTGGACTCTATGTATTCAGAATTAATAGATA [...]
diff --git a/helpSetMaker/docuData/analyzeMenu.png b/helpSetMaker/docuData/analyzeMenu.png
new file mode 100644
index 0000000..fe77481
Binary files /dev/null and b/helpSetMaker/docuData/analyzeMenu.png differ
diff --git a/helpSetMaker/docuData/editMenu.png b/helpSetMaker/docuData/editMenu.png
new file mode 100644
index 0000000..1e6fbff
Binary files /dev/null and b/helpSetMaker/docuData/editMenu.png differ
diff --git a/helpSetMaker/docuData/fileMenu.png b/helpSetMaker/docuData/fileMenu.png
new file mode 100644
index 0000000..05ee971
Binary files /dev/null and b/helpSetMaker/docuData/fileMenu.png differ
diff --git a/helpSetMaker/docuData/helpMenu.png b/helpSetMaker/docuData/helpMenu.png
new file mode 100644
index 0000000..6cba116
Binary files /dev/null and b/helpSetMaker/docuData/helpMenu.png differ
diff --git a/helpSetMaker/docuData/mainWindow.png b/helpSetMaker/docuData/mainWindow.png
new file mode 100644
index 0000000..3bd75d6
Binary files /dev/null and b/helpSetMaker/docuData/mainWindow.png differ
diff --git a/helpSetMaker/docuData/namesPane.png b/helpSetMaker/docuData/namesPane.png
new file mode 100644
index 0000000..ba46701
Binary files /dev/null and b/helpSetMaker/docuData/namesPane.png differ
diff --git a/helpSetMaker/docuData/primer1.png b/helpSetMaker/docuData/primer1.png
new file mode 100644
index 0000000..345b34d
Binary files /dev/null and b/helpSetMaker/docuData/primer1.png differ
diff --git a/helpSetMaker/docuData/primerProduct.png b/helpSetMaker/docuData/primerProduct.png
new file mode 100644
index 0000000..9667fee
Binary files /dev/null and b/helpSetMaker/docuData/primerProduct.png differ
diff --git a/helpSetMaker/docuData/pyrograms.png b/helpSetMaker/docuData/pyrograms.png
new file mode 100644
index 0000000..ba5c497
Binary files /dev/null and b/helpSetMaker/docuData/pyrograms.png differ
diff --git a/helpSetMaker/docuData/resizingSelection.png b/helpSetMaker/docuData/resizingSelection.png
new file mode 100644
index 0000000..78015e0
Binary files /dev/null and b/helpSetMaker/docuData/resizingSelection.png differ
diff --git a/helpSetMaker/docuData/sequencePane.png b/helpSetMaker/docuData/sequencePane.png
new file mode 100644
index 0000000..f86336b
Binary files /dev/null and b/helpSetMaker/docuData/sequencePane.png differ
diff --git a/helpSetMaker/docuData/settings.png b/helpSetMaker/docuData/settings.png
new file mode 100644
index 0000000..f3efec7
Binary files /dev/null and b/helpSetMaker/docuData/settings.png differ
diff --git a/helpSetMaker/docuData/toolbar.png b/helpSetMaker/docuData/toolbar.png
new file mode 100644
index 0000000..bd6eaa0
Binary files /dev/null and b/helpSetMaker/docuData/toolbar.png differ
diff --git a/helpSetMaker/docuData/viewMenu.png b/helpSetMaker/docuData/viewMenu.png
new file mode 100644
index 0000000..886de81
Binary files /dev/null and b/helpSetMaker/docuData/viewMenu.png differ
diff --git a/helpSetMaker/hs/0844fec5.html b/helpSetMaker/hs/0844fec5.html
new file mode 100644
index 0000000..322a015
--- /dev/null
+++ b/helpSetMaker/hs/0844fec5.html
@@ -0,0 +1,25 @@
+<html>
+<head>
+<title>Toolbar</title>
+</head>
+<body class="doc">
+<h1>Toolbar</h1>
+<br><p align="center">
+<img src="pics/toolbar.png" width="163" height="34"><br>
+<em>The toolbar</em></p><br>
+
+<p>The toolbar contains five buttons for quick access to often-used display functionality:
+<ul><li>
+<p>IUB/AGTC: Selects whether to show the consensus sequence as simple majority or as IUB code for non-conserved residues</p>
+</li><li>
+<p>Primer/AGTC: Selects whether to display/edit primer names or primer sequence</p>
+</li><li>
+<p>Primer melting temperature: Switches the display of primer melting temperature (calculated using the stacking model) on or off</p>
+</li><li>
+<p>Primer length: Switches the display of primer length on or off</p>
+</li><li>
+<p>Sequence name: Switches the display of the sequence name under the mouse cursor on or off</p>
+</li></ul>
+</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/268013c8.html b/helpSetMaker/hs/268013c8.html
new file mode 100644
index 0000000..14e636f
--- /dev/null
+++ b/helpSetMaker/hs/268013c8.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>Supported formats</title>
+</head>
+<body class="doc">
+<h1>Supported formats</h1>
+
+<p>Several formats are supported for loading and saving files. Expect this list to grow with time, as theprogram is designed to make adding supported formats easy.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/2d4d2587.html b/helpSetMaker/hs/2d4d2587.html
new file mode 100644
index 0000000..0aebe67
--- /dev/null
+++ b/helpSetMaker/hs/2d4d2587.html
@@ -0,0 +1,29 @@
+<html>
+<head>
+<title>File</title>
+</head>
+<body class="doc">
+<h1>File</h1>
+
+<p>The file menu allows the loading and saving of documents.</p>
+<br><p align="center">
+<img src="pics/fileMenu.png" width="235" height="130"><br>
+<em>The file menu</em></p><br>
+
+<p>The following options are available:</p>
+
+<ul><li>
+<p>Load file: Loads a new file</p>
+</li><li>
+<p>Append from file: Appends sequences from a file to the currently open document</p>
+</li><li>
+<p>Save: Saves the currently open document</p>
+</li><li>
+<p>Save as: Saves the currently open document under a new name</p>
+</li><li>
+<p>Open recent: Shows a list of recently opened documents</p>
+</li></ul>
+
+<p>A list of formats for both loading and saving files is available in the section <a href="268013c8.html">Supported formats</a>.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/35271893.html b/helpSetMaker/hs/35271893.html
new file mode 100644
index 0000000..10e0dab
--- /dev/null
+++ b/helpSetMaker/hs/35271893.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>The main window</title>
+</head>
+<body class="doc">
+<h1>The main window</h1>
+
+<p>The main window is where all of the work is done in the Sequence Editor. This section will walk zou throught the elements of the main window and the operations which can be performed from here.</p>
+<br><p align="center">
+<img src="pics/mainWindow.png" width="961" height="633"><br>
+<em>The main window with a loaded alignment</em></p><br>
+</body>
+</html>
diff --git a/helpSetMaker/hs/3e7a5715.html b/helpSetMaker/hs/3e7a5715.html
new file mode 100644
index 0000000..235053f
--- /dev/null
+++ b/helpSetMaker/hs/3e7a5715.html
@@ -0,0 +1,28 @@
+<html>
+<head>
+<title>Annotations and primers</title>
+</head>
+<body class="doc">
+<h1>Annotations and primers</h1>
+
+<p>Annotations and primers are handled in the same way, with the exception of primers havind some extended functionality. As such, only the handling of primers will be describen in-depth.</p>
+
+<p>When a section of a sequence is selected and right-clicked, the option to add primers or annotations is provided through the context menu. Annotations can be added above or below the sequence, forward primers are always added above the sequence and reverse primers are always added beneath the sequence.</p>
+
+<p>The name of a primer/annotation can be changed by clicking on the primer/annotation, entering a new name and pressing the enter button. In case of primers, the sequence instead of the name can be displayed and edited by pressing the appropriate button on the <a href="0844fec5.html">toolbar</a>. The color of a primer/annotation can be changed by right-clicking on the primer/annotation and selecting "Change color".</p>
+
+<p>Between a primer and the sequence, an identity bar is displayed. It has two rows: The one closer to the sequence displays how well the base matches all sequences: Green means a perfect match, red means that there are sequences in the alignment which do not match the primer, and dark green means that the base in the primer is degenerated in a way which makes it match all sequences in the alignment. The same color code is used in the bar closer to the primer which shows how well the pri [...]
+<br><p align="center">
+<img src="pics/primer1.png" width="280" height="209"><br>
+<em>A reverse primer with two mismatches: One, on the right end, which fits neither the group nor the remaining sequences perfectly and one, on the left end, which fits all sequences in the group perfectly but not the sequences from other groups. The number on the left side shows the length of the primer, the number on the right side shows the meltimg temperature calculated according to the base stacking method.</em></p><br>
+
+<p>The right-click menu for the primer offers the option to degenerate the primer either to match all sequences in the group or to match all sequences in the alignment. </p>
+
+<p>Annotations and primers can be resized by dragging their ends or moved by dragging the center. When a primer is dragged or resized, it automatically adapts to the sequence it belongs to, except for degenerated bases or mismatches which have been entered manually: These positions are "locked" and will remain degenerated or mismatches.</p>
+
+<p>When a forward and a reverse primer are added to the same sequence, a dashed line will be drawn between them to show the product which would be generated during a PCR reaction. A box in the middle of this line displays the product size (excluding the primers). If the calculated primer melting temperatures are considered too far apart (default: 1 K, can be set in the settings window which is accessible through the <a href="f19dc10a.html">edit</a> menu), the line is red, otherwise the l [...]
+<br><p align="center">
+<img src="pics/primerProduct.png" width="1072" height="112"><br>
+<em>Two primers which could generate a product in a PCR but have melting temperatures which are considered too far apart.</em></p><br>
+</body>
+</html>
diff --git a/helpSetMaker/hs/4ecd38e2.html b/helpSetMaker/hs/4ecd38e2.html
new file mode 100644
index 0000000..d3260e5
--- /dev/null
+++ b/helpSetMaker/hs/4ecd38e2.html
@@ -0,0 +1,34 @@
+<html>
+<head>
+<title>Analyze</title>
+</head>
+<body class="doc">
+<h1>Analyze</h1>
+
+<p>The analysis menu offers some basic sequence analysis options.</p>
+<br><p align="center">
+<img src="pics/analyzeMenu.png" width="526" height="184"><br>
+<em>The analysis menu</em></p><br>
+
+<p>The following options are available:
+<ul><li>
+<p>Calculate master consensus: Calculates and displays the consensus sequence of all sequences in the alignment</p>
+</li><li>
+<p>Calculate group consensus: Calculates and displays the consensus sequence for every defined <a href="b69463fa.html">group</a></p>
+</li><li>
+<p>Keep consensus up to date: If this is checked, the consensus sequence(s) will automatically be updated whenever a sequence is modified.</p>
+</li><li>
+<p>Group identical sequences: A new group is created for each set of identical sequences in the alignment</p>
+</li><li>
+<p>Sort sequences: The sequences can be sorted by name, by degree of identity (to the consensus sequence or, if a reference sequence is selected, to the reference sequence) or by degree of identity within the current selection. Sorting maintains grouping: If sequences are grouped, then sorting will sort the sequences within each group individually</p>
+</li><li>
+<p>Find all SNPs: This automatically calculates master and group consensus sequences. Then, all positions are marked which are fully conserved within each of the defined groups but not across the whole alignment (meaning that they can be used to differentiate between at least two of the defined groups)</p>
+</li><li>
+<p>Show predicted flowgrams: If <a href="9ee3d3c6.html">pyrosequencing primers</a> are defined, the flowgrams are shown which would be generated during multiplex pyrosequencing for each of the defined <a href="b69463fa.html">groups</a>. A list of <a href="b69463fa.html">groups</a> which are expected to generate no unique pyrogram is provided.</p>
+</li></ul>
+</p>
+<br><p align="center">
+<img src="pics/pyrograms.png" width="260" height="258"><br>
+<em>Predicted pyrograms: The groups VARV and MPXV generate unique pyrograms with the two defined pyrosequencing primers, while the pyrograms for the groups All, VACV and CPXV are identical to each other.</em></p><br>
+</body>
+</html>
diff --git a/helpSetMaker/hs/6036f840.html b/helpSetMaker/hs/6036f840.html
new file mode 100644
index 0000000..6aaaeae
--- /dev/null
+++ b/helpSetMaker/hs/6036f840.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>Help</title>
+</head>
+<body class="doc">
+<h1>Help</h1>
+
+<p>This document can be opened from here ;)</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/6bc41f84.html b/helpSetMaker/hs/6bc41f84.html
new file mode 100644
index 0000000..14174f1
--- /dev/null
+++ b/helpSetMaker/hs/6bc41f84.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+<title>FASTA (import and export)</title>
+</head>
+<body class="doc">
+<h1>FASTA (import and export)</h1>
+
+<p>The default FASTA format can be both imported and exported. When exporting, two choices are available: The <i>Blank FASTA file</i>, which is a normal FASTA file and can be read by almost any sequence editor, has the disadvantage of losing grouping information (since the FASTA format does not provide any way to encode metadata). The other option, <i>FASTA file</i>, saves a file in a somewhat extended FASTA format. This file can still be read by most sequence editors, but it contains gr [...]
+
+<p>Files saved in the FASTA format lose all annotation information in any case.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/86d0b0a1.html b/helpSetMaker/hs/86d0b0a1.html
new file mode 100644
index 0000000..a899cc7
--- /dev/null
+++ b/helpSetMaker/hs/86d0b0a1.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<title>The sequence pane</title>
+</head>
+<body class="doc">
+<h1>The sequence pane</h1>
+<br><p align="center">
+<img src="pics/sequencePane.png" width="567" height="300"><br>
+<em>The sequence pane</em></p><br>
+
+<p>The sequence pane is where the sequences of the currently loaded alignment are displayed. If <a href="b69463fa.html">groups</a> have been defined and group <a href="4ecd38e2.html">consensus sequences have been calculated</a>, the consensus sequence and identity graph for each group is also shown.</p>
+
+<p>At the top, the currently displayed position in the alignment is shown. </p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/87de535b.html b/helpSetMaker/hs/87de535b.html
new file mode 100644
index 0000000..a79e908
--- /dev/null
+++ b/helpSetMaker/hs/87de535b.html
@@ -0,0 +1,14 @@
+<html>
+<head>
+<title>Moving, editing, master sequences</title>
+</head>
+<body class="doc">
+<h1>Moving, editing, master sequences</h1>
+
+<p>Sequences can be moved by selecting a name in the names pane and dragging it about. Several sequences can be selected by holding down either the shift or the control key while clicking on the names. The whole selection can then be moved together. Sequences can only be moved within a single <a href="b69463fa.html">group</a>. </p>
+
+<p>When a sequence name is right-cliked on, a context menu appears which allows to set the sequence as the master sequence (it will be displayed at the top of the alignment insead of the consensus sequence and differences to this sesquence will be highlighted instead of differences to the consensus sequence). The sequence can also be deleted or reverse-complemented in place. </p>
+
+<p>Sequences can also be sorted from the right-click menu. The behavior is identical to that of sorting from the <a href="4ecd38e2.html">Analyze</a> menu.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/98c149b5.html b/helpSetMaker/hs/98c149b5.html
new file mode 100644
index 0000000..47b1eb8
--- /dev/null
+++ b/helpSetMaker/hs/98c149b5.html
@@ -0,0 +1,15 @@
+<html>
+<head>
+<title>View</title>
+</head>
+<body class="doc">
+<h1>View</h1>
+
+<p>The view menu allows customizing the sequence display.</p>
+<br><p align="center">
+<img src="pics/viewMenu.png" width="189" height="108"><br>
+<em>The view menu</em></p><br>
+
+<p>The color models currently supported are: Monochrome, BioEdit (background), UPGMA (background) and UPGMA. In the background color models, the foreground color is always black.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/9d452f38.html b/helpSetMaker/hs/9d452f38.html
new file mode 100644
index 0000000..b97fe81
--- /dev/null
+++ b/helpSetMaker/hs/9d452f38.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<title>The names pane</title>
+</head>
+<body class="doc">
+<h1>The names pane</h1>
+
+<p>The names pane is where the names of the sequences in the alignment are displayed and where grouping is performed.</p>
+<br><p align="center">
+<img src="pics/namesPane.png" width="431" height="144"><br>
+<em>The names pane</em></p><br>
+</body>
+</html>
diff --git a/helpSetMaker/hs/9ee3d3c6.html b/helpSetMaker/hs/9ee3d3c6.html
new file mode 100644
index 0000000..e555133
--- /dev/null
+++ b/helpSetMaker/hs/9ee3d3c6.html
@@ -0,0 +1,19 @@
+<html>
+<head>
+<title>Multiplex pyrosequencing</title>
+</head>
+<body class="doc">
+<h1>Multiplex pyrosequencing</h1>
+
+<p>If <a href="3e7a5715.html">primers</a> have been defined, they can be set as pyrosequencing primers by right-clicking on them and selecting the "Is pyrosequencing primer" checkbox. Once pyrosequencing primers have been defined, the "Show predicted flowgrams" entry in the <a href="4ecd38e2.html">Analyze</a> menu can be selected to show the pyrograms which would be generated for each of the groups in a multiplex pyrosequencing assay. </p>
+<br><p align="center">
+<img src="pics/pyrograms.png" width="260" height="258"><br>
+<em>Predicted pyrograms for two pyrosequencing primers. The pyrograms for the groups All, VACV and CPXV are expected to be identical, while the groups VARV and MPXV are expected to generate unique pyrograms.</em></p><br>
+
+<p>Each group which generates a unique pyrogram is shown separately, while groups which cannot be differentiated using the defined primers because their pyrograms would be identical are shown together. </p>
+
+<p>While the window showing the predicted pyrograms is visible, the primers in the sequence pane can be resized, moved etc. The changes to the predicted pyrograms are updated in realtime, so that primers positions can easily be optimised.</p>
+
+<p>The flowgram length defines how many pyrosequencing cycles are to be considered in the analysis. The maximum flowgram length is the number of cycles which can be performed using the defined primers before a region would be sequenced which is not fully conserved within each of the groups - at this point, the pyrosequencing would result in several different pyrograms for the same group.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/JavaHelpSearch/DOCS b/helpSetMaker/hs/JavaHelpSearch/DOCS
new file mode 100644
index 0000000..40e3d0f
Binary files /dev/null and b/helpSetMaker/hs/JavaHelpSearch/DOCS differ
diff --git a/helpSetMaker/hs/JavaHelpSearch/DOCS.TAB b/helpSetMaker/hs/JavaHelpSearch/DOCS.TAB
new file mode 100644
index 0000000..16223ea
--- /dev/null
+++ b/helpSetMaker/hs/JavaHelpSearch/DOCS.TAB
@@ -0,0 +1,7 @@
+e������������������u�������������_��������������������������u������u����������������������������������u����������������������u�u��a�R���"�*�
+�*���,ң)��
+0�£���J��r��(̿0���3(ػ4���
+�Ҭ£
��������0�
�.��
+��
�/�
��0�ª���Œb�"͊0��0����(Œ*0��0�ꫯ�
+��
+�J�2*����º�������ꪪ���0����*���ꪪ������/��/��0���������
\ No newline at end of file
diff --git a/helpSetMaker/hs/JavaHelpSearch/OFFSETS b/helpSetMaker/hs/JavaHelpSearch/OFFSETS
new file mode 100644
index 0000000..23b7ad3
--- /dev/null
+++ b/helpSetMaker/hs/JavaHelpSearch/OFFSETS
@@ -0,0 +1,2 @@
+��&��4� ��W�D��
(cH@�L%�
+�hɐeʃJh�"'�g=Г�nh���@�Sk���bL�=��.�p�T��
\ No newline at end of file
diff --git a/helpSetMaker/hs/JavaHelpSearch/POSITIONS b/helpSetMaker/hs/JavaHelpSearch/POSITIONS
new file mode 100644
index 0000000..8502b35
Binary files /dev/null and b/helpSetMaker/hs/JavaHelpSearch/POSITIONS differ
diff --git a/helpSetMaker/hs/JavaHelpSearch/SCHEMA b/helpSetMaker/hs/JavaHelpSearch/SCHEMA
new file mode 100644
index 0000000..f73bd1b
--- /dev/null
+++ b/helpSetMaker/hs/JavaHelpSearch/SCHEMA
@@ -0,0 +1,2 @@
+JavaSearch 1.0
+TMAP bs=2048 rt=1 fl=-1 id1=540 id2=1
diff --git a/helpSetMaker/hs/JavaHelpSearch/TMAP b/helpSetMaker/hs/JavaHelpSearch/TMAP
new file mode 100644
index 0000000..e361a08
Binary files /dev/null and b/helpSetMaker/hs/JavaHelpSearch/TMAP differ
diff --git a/helpSetMaker/hs/aa49edd7.html b/helpSetMaker/hs/aa49edd7.html
new file mode 100644
index 0000000..b0d380d
--- /dev/null
+++ b/helpSetMaker/hs/aa49edd7.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>Navigating the sequences</title>
+</head>
+<body class="doc">
+<h1>Navigating the sequences</h1>
+
+<p>Sequence navigation is very basic and intuitive: Scrolling is possible either using the scroll bars or through holding the middle mouse button to "grab" the sequence pane and moving the mouse. Zooming can either be performed through the <a href="98c149b5.html">view menu</a> or by holding down the CTRL-key on the keyboard and moving the scroll wheel on the mouse.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/ae869282.html b/helpSetMaker/hs/ae869282.html
new file mode 100644
index 0000000..c539f0e
--- /dev/null
+++ b/helpSetMaker/hs/ae869282.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>mPSQed</title>
+</head>
+<body class="doc">
+<h1>mPSQed</h1>
+
+<p>This Sequence Editor developed at the Robert Koch Institute in Berlin, Germany aims to make the design of PCR and Multiplex Pyrosequencing assays based on nucleotide alignments easier. The following pages describe the main functions of the editor.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/b139c808.html b/helpSetMaker/hs/b139c808.html
new file mode 100644
index 0000000..bc036de
--- /dev/null
+++ b/helpSetMaker/hs/b139c808.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>Menus</title>
+</head>
+<body class="doc">
+<h1>Menus</h1>
+
+<p>This section walks through the menus available in the editor.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/b69463fa.html b/helpSetMaker/hs/b69463fa.html
new file mode 100644
index 0000000..882daae
--- /dev/null
+++ b/helpSetMaker/hs/b69463fa.html
@@ -0,0 +1,16 @@
+<html>
+<head>
+<title>Grouping</title>
+</head>
+<body class="doc">
+<h1>Grouping</h1>
+
+<p>Sequences can be organised in groups. This is useful for finding SNPs which could be used in species-specific assays using the "Find all SNPs" entry in the <a href="4ecd38e2.html">Analyze</a> menu or in the design of <a href="9ee3d3c6.html">multiplex pyrosequencing assays</a>.</p>
+
+<p>Sequences can be grouped together by <a href="87de535b.html">selecting</a> one or more sequences, right-clicking on the selection and then choosing the "Set as group" option. A group name can then be entered, and the selected sequences will be moved to a new group with that name. The group of a sequence is shown in braces in front of the sequence name and groups can be collapsed or expanded by clicking on the minur or plus sign in front of the first sequence in a group. </p>
+
+<p>Sequences can be moved from group to group by right-clicking on a sequence and selecting the target group from the "Add sequence to group" entry.</p>
+
+<p>There is no separate option to rename a group. However, empty groups will be deleted, so renaming a group can be done by selecting all sequences from a group, right-clicking, selecting "Set as group" and entering the new group name. All selected sequences will be moved to a new group with the new name, and the old group will be deleted since it will then be empty.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/c9e02254.html b/helpSetMaker/hs/c9e02254.html
new file mode 100644
index 0000000..fa2e7ff
--- /dev/null
+++ b/helpSetMaker/hs/c9e02254.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+<title>RSF (import and export)</title>
+</head>
+<body class="doc">
+<h1>RSF (import and export)</h1>
+
+<p>The Rich Sequence Format (RSF) is a format used by the program SeqLab. It is also the default format for the RKI Sequence Editor since it allows the saving of metadata. It is currently the only supported format which allows the saving of all grouping, annotation and primer information.</p>
+
+<p>As a result, it is recommended to save files in the RKI Sequence Editor using the Rich Sequence Format and only to export to one of the other supported format when data is exchanged with colleagues using another editor.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/e9fd53d0.html b/helpSetMaker/hs/e9fd53d0.html
new file mode 100644
index 0000000..d80cf62
--- /dev/null
+++ b/helpSetMaker/hs/e9fd53d0.html
@@ -0,0 +1,31 @@
+<html>
+<head>
+<title>Selecting, editing and copying</title>
+</head>
+<body class="doc">
+<h1>Selecting, editing and copying</h1>
+
+<p>Sequences can be selected using the mouse. An existing selection can be resized by grabbing one of its corners with the mouse and dragging. </p>
+<br><p align="center">
+<img src="pics/resizingSelection.png" width="192" height="178"><br>
+<em>Resizing an existing selection</em></p><br>
+
+<p>Selecting on a <a href="4ecd38e2.html">group consensus sequence</a> will select the specified region of all sequences within the group, selecting on the master consensus sequence will select the specified region of all sequences in the alignment. Once a selection has been made, it can be copied to the system buffer by right-clicking on it and selecting one of the following options:
+<ul><li>
+<p>Sequences: Copies the selected parts of the sequences, with each sequence in a separate line</p>
+</li><li>
+<p>Sequences with names: Copies the selected parts of the sequence, including the sequence names, in FASTA format. The sequence names will end with the selection range in braces (e.g.: ">DQ983239 (172 - 246)")</p>
+</li><li>
+<p>Master consensus sequence: Copies the master consensus sequence for the selected range</p>
+</li><li>
+<p>Group consensus sequence: Copies the consensus sequence for the selected group</p>
+</li></ul>
+</p>
+
+<p>When right-clicking on a selection, the option "Delete selected" is also available. This deletes the selected bases, shifting the bases following on the right-hand side left to fill the gap.</p>
+
+<p>The right-click menu for a sequence selection also contains two submenus for the adding of primers and annotations, which is described in-depth in the <a href="3e7a5715.html">next section</a>.</p>
+
+<p>Sequences can also be edited: When a single residue is clicked on, a cursor is shown around that residue. This cursor can be moved using the arrow keys on the keyboard. The base under the cursor can be modified through the keyboard (all IUPAC nucleotide codes can be entered). Clicking somewhere else in the sequence pane exits the editing mode.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/ec633545.html b/helpSetMaker/hs/ec633545.html
new file mode 100644
index 0000000..0829631
--- /dev/null
+++ b/helpSetMaker/hs/ec633545.html
@@ -0,0 +1,10 @@
+<html>
+<head>
+<title>Geneious (export only)</title>
+</head>
+<body class="doc">
+<h1>Geneious (export only)</h1>
+
+<p>The Geneious format is supported only for exporting files. It can be read by the bioinformatics workbench <a target="_blank" href="http://www.geneious.com">Geneious</a>. Using this file format preserves annotation and grouping - however, since Geneious has no concept of sequence grouping within a single alignment, grouping information is effectively lost when using this format.</p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/f19dc10a.html b/helpSetMaker/hs/f19dc10a.html
new file mode 100644
index 0000000..5400c2a
--- /dev/null
+++ b/helpSetMaker/hs/f19dc10a.html
@@ -0,0 +1,32 @@
+<html>
+<head>
+<title>Edit </title>
+</head>
+<body class="doc">
+<h1>Edit </h1>
+
+<p>The edit menu allows copying sequences and modifying the settings.</p>
+<br><p align="center">
+<img src="pics/editMenu.png" width="328" height="111"><br>
+<em>The edit menu</em></p><br>
+
+<p>When copying sequences, the following options are available:</p>
+
+<ul><li>
+<p>Sequences: Copies the selected nucleotides. If several sequences are selected, the nucleotides from each sequence will be copied in a separate line.</p>
+</li><li>
+<p>Sequences with names: Copies the selected sequence parts in FASTA format, with sequence names and selected nucleotides. This can be useful for example for blasting several sequences at once.</p>
+</li><li>
+<p>Master consensus sequence: Copies the master consensus sequence for the selected part of the alignment.</p>
+</li><li>
+<p>Group consensus sequence: Copies the group consensus sequence for the selected part of the alignment.</p>
+</li></ul>
+
+<p>The settings option allows editing the general settings of the program. Currently, the only configurable section pertains to primers:</p>
+<br><p align="center">
+<img src="pics/settings.png" width="413" height="331"><br>
+<em>The settings window</em></p><br>
+
+<p>The top three options are used when calculating the melting temperature (tm) of primers. If two primers can create an amplification product and their tm differs by too much, a warning can be displayed. The tm difference necessary for this warning to appear and the color of the warning can be set in the last two options. </p>
+</body>
+</html>
diff --git a/helpSetMaker/hs/main.hs b/helpSetMaker/hs/main.hs
new file mode 100644
index 0000000..afab8d3
--- /dev/null
+++ b/helpSetMaker/hs/main.hs
@@ -0,0 +1,23 @@
+<?xml version='1.0' encoding='ISO-8859-1' ?>
+<!DOCTYPE helpset PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp HelpSet Version 2.0//EN" "http://java.sun.com/products/javahelp/helpset_2_0.dtd">
+<helpset version="2.0">
+<title>RKI Sequence Editor</title>
+<maps>
+<homeID>_file.ae869282</homeID>
+<mapref location="map.jhm" />
+</maps>
+<view xml:lang="ar" mergetype="javax.help.UniteAppendMerge">
+  <name>TOC</name>
+  <label>helpset.toc.title</label>
+  <type>javax.help.TOCView</type>
+  <data>toc.xml</data>
+</view>
+<view xml:lang="ar">
+<name>Search</name>
+<label>helpset.search.title</label>
+<type>javax.help.SearchView</type>
+<data engine="com.sun.java.help.search.DefaultSearchEngine">
+JavaHelpSearch
+</data>
+</view>
+</helpset>
diff --git a/helpSetMaker/hs/map.jhm b/helpSetMaker/hs/map.jhm
new file mode 100644
index 0000000..2452a64
--- /dev/null
+++ b/helpSetMaker/hs/map.jhm
@@ -0,0 +1,25 @@
+<?xml version='1.0' encoding='ISO-8859-1' ?>
+<!DOCTYPE map PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp Map Version 2.0//EN" "http://java.sun.com/products/javahelp/map_2_0.dtd">
+<map version="2.0">
+<mapID target="_file.ae869282" url="ae869282.html" />
+<mapID target="_file.35271893" url="35271893.html" />
+<mapID target="_file.b139c808" url="b139c808.html" />
+<mapID target="_file.2d4d2587" url="2d4d2587.html" />
+<mapID target="edit" url="f19dc10a.html" />
+<mapID target="view" url="98c149b5.html" />
+<mapID target="analyze" url="4ecd38e2.html" />
+<mapID target="_file.6036f840" url="6036f840.html" />
+<mapID target="toolbar" url="0844fec5.html" />
+<mapID target="_file.86d0b0a1" url="86d0b0a1.html" />
+<mapID target="_file.aa49edd7" url="aa49edd7.html" />
+<mapID target="_file.e9fd53d0" url="e9fd53d0.html" />
+<mapID target="primers" url="3e7a5715.html" />
+<mapID target="multiplexPyrosequencing" url="9ee3d3c6.html" />
+<mapID target="_file.9d452f38" url="9d452f38.html" />
+<mapID target="selecting" url="87de535b.html" />
+<mapID target="grouping" url="b69463fa.html" />
+<mapID target="formats" url="268013c8.html" />
+<mapID target="_file.6bc41f84" url="6bc41f84.html" />
+<mapID target="_file.c9e02254" url="c9e02254.html" />
+<mapID target="_file.ec633545" url="ec633545.html" />
+</map>
diff --git a/helpSetMaker/hs/pics/analyzeMenu.png b/helpSetMaker/hs/pics/analyzeMenu.png
new file mode 100644
index 0000000..fe77481
Binary files /dev/null and b/helpSetMaker/hs/pics/analyzeMenu.png differ
diff --git a/helpSetMaker/hs/pics/editMenu.png b/helpSetMaker/hs/pics/editMenu.png
new file mode 100644
index 0000000..1e6fbff
Binary files /dev/null and b/helpSetMaker/hs/pics/editMenu.png differ
diff --git a/helpSetMaker/hs/pics/fileMenu.png b/helpSetMaker/hs/pics/fileMenu.png
new file mode 100644
index 0000000..05ee971
Binary files /dev/null and b/helpSetMaker/hs/pics/fileMenu.png differ
diff --git a/helpSetMaker/hs/pics/mainWindow.png b/helpSetMaker/hs/pics/mainWindow.png
new file mode 100644
index 0000000..3bd75d6
Binary files /dev/null and b/helpSetMaker/hs/pics/mainWindow.png differ
diff --git a/helpSetMaker/hs/pics/namesPane.png b/helpSetMaker/hs/pics/namesPane.png
new file mode 100644
index 0000000..ba46701
Binary files /dev/null and b/helpSetMaker/hs/pics/namesPane.png differ
diff --git a/helpSetMaker/hs/pics/primer1.png b/helpSetMaker/hs/pics/primer1.png
new file mode 100644
index 0000000..345b34d
Binary files /dev/null and b/helpSetMaker/hs/pics/primer1.png differ
diff --git a/helpSetMaker/hs/pics/primerProduct.png b/helpSetMaker/hs/pics/primerProduct.png
new file mode 100644
index 0000000..9667fee
Binary files /dev/null and b/helpSetMaker/hs/pics/primerProduct.png differ
diff --git a/helpSetMaker/hs/pics/pyrograms.png b/helpSetMaker/hs/pics/pyrograms.png
new file mode 100644
index 0000000..ba5c497
Binary files /dev/null and b/helpSetMaker/hs/pics/pyrograms.png differ
diff --git a/helpSetMaker/hs/pics/resizingSelection.png b/helpSetMaker/hs/pics/resizingSelection.png
new file mode 100644
index 0000000..78015e0
Binary files /dev/null and b/helpSetMaker/hs/pics/resizingSelection.png differ
diff --git a/helpSetMaker/hs/pics/sequencePane.png b/helpSetMaker/hs/pics/sequencePane.png
new file mode 100644
index 0000000..f86336b
Binary files /dev/null and b/helpSetMaker/hs/pics/sequencePane.png differ
diff --git a/helpSetMaker/hs/pics/settings.png b/helpSetMaker/hs/pics/settings.png
new file mode 100644
index 0000000..f3efec7
Binary files /dev/null and b/helpSetMaker/hs/pics/settings.png differ
diff --git a/helpSetMaker/hs/pics/toolbar.png b/helpSetMaker/hs/pics/toolbar.png
new file mode 100644
index 0000000..bd6eaa0
Binary files /dev/null and b/helpSetMaker/hs/pics/toolbar.png differ
diff --git a/helpSetMaker/hs/pics/viewMenu.png b/helpSetMaker/hs/pics/viewMenu.png
new file mode 100644
index 0000000..886de81
Binary files /dev/null and b/helpSetMaker/hs/pics/viewMenu.png differ
diff --git a/helpSetMaker/hs/toc.xml b/helpSetMaker/hs/toc.xml
new file mode 100644
index 0000000..4683c99
--- /dev/null
+++ b/helpSetMaker/hs/toc.xml
@@ -0,0 +1,31 @@
+<?xml version='1.0' encoding='ISO-8859-1' ?>
+<!DOCTYPE toc PUBLIC "-//Sun Microsystems Inc.//DTD JavaHelp TOC Version 2.0//EN" "http://java.sun.com/products/javahelp/toc_2_0.dtd">
+<toc version="2.0">
+<tocitem text="RKI Sequence Editor" target="_file.ae869282">
+<tocitem text="The main window" target="_file.35271893">
+<tocitem text="Menus" target="_file.b139c808">
+<tocitem text="File" target="_file.2d4d2587" />
+<tocitem text="Edit " target="edit" />
+<tocitem text="View" target="view" />
+<tocitem text="Analyze" target="analyze" />
+<tocitem text="Help" target="_file.6036f840" />
+</tocitem>
+<tocitem text="Toolbar" target="toolbar" />
+<tocitem text="The sequence pane" target="_file.86d0b0a1">
+<tocitem text="Navigating the sequences" target="_file.aa49edd7" />
+<tocitem text="Selecting, editing and copying" target="_file.e9fd53d0" />
+<tocitem text="Annotations and primers" target="primers" />
+<tocitem text="Multiplex pyrosequencing" target="multiplexPyrosequencing" />
+</tocitem>
+<tocitem text="The names pane" target="_file.9d452f38">
+<tocitem text="Moving, editing, master sequences" target="selecting" />
+<tocitem text="Grouping" target="grouping" />
+</tocitem>
+</tocitem>
+<tocitem text="Supported formats" target="formats">
+<tocitem text="FASTA (import and export)" target="_file.6bc41f84" />
+<tocitem text="RSF (import and export)" target="_file.c9e02254" />
+<tocitem text="Geneious (export only)" target="_file.ec633545" />
+</tocitem>
+</tocitem>
+</toc>
diff --git a/helpSetMaker/hsm.xml b/helpSetMaker/hsm.xml
new file mode 100644
index 0000000..ee149c8
--- /dev/null
+++ b/helpSetMaker/hsm.xml
@@ -0,0 +1,288 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<HelpSetMaker>
+<DocumentProperties>
+<Value Key="eclipse.makeintro">false</Value>
+<Value Key="eclipse.quotation">none</Value>
+<Value Key="general.locale">ar</Value>
+<Value Key="general.uselabelforfilename">false</Value>
+<Value Key="helpset.createjarfile">false</Value>
+<Value Key="helpset.fulltextsearch">true</Value>
+<Value Key="helpset.mainlocalesuffix">false</Value>
+<Value Key="helpset.navigation.bottom">none</Value>
+<Value Key="helpset.navigation.top">none</Value>
+<Value Key="helpset.quotation">none</Value>
+<Value Key="helpset.scaleimages">false</Value>
+<Value Key="helpset.titletag">false</Value>
+<Value Key="html4.cssfortree">false</Value>
+<Value Key="html4.navigation.bottom">none</Value>
+<Value Key="html4.navigation.top">none</Value>
+<Value Key="html4.quotation">none</Value>
+<Value Key="html4.scaleimages">false</Value>
+<Value Key="html4.titletag">false</Value>
+<Value Key="latex.firstsection.ownpage">false</Value>
+<Value Key="latex.firstsection.type">abstract</Value>
+<Value Key="latex.fontsize">10pt</Value>
+<Value Key="latex.fontstyle">cm</Value>
+<Value Key="latex.image.frame">false</Value>
+<Value Key="latex.ownpage">false</Value>
+<Value Key="latex.papertype">a4paper</Value>
+<Value Key="latex.paragraph">inset</Value>
+<Value Key="latex.quotation">none</Value>
+<Value Key="latex.references">empty</Value>
+<Value Key="latex.scaleimages">false</Value>
+<Value Key="latex.sectioning.deepest">section</Value>
+<Value Key="latex.sectioning.uppermost">part</Value>
+<Value Key="latex.sides">oneside</Value>
+<Value Key="latex.usehyperref">false</Value>
+<Value Key="preview.unscaledimages">false</Value>
+<Value Key="project.charset">ISO-8859-1</Value>
+<Value Key="stml.charset">UTF-8</Value>
+</DocumentProperties>
+<DocumentTree>
+<DocumentNode>
+<Filename>ae869282</Filename>
+<Title>mPSQed</Title>
+<FullTextSearch>true</FullTextSearch>
+<DocumentNode>
+<Filename>35271893</Filename>
+<Title>The main window</Title>
+<FullTextSearch>true</FullTextSearch>
+<DocumentNode>
+<Filename>b139c808</Filename>
+<Title>Menus</Title>
+<FullTextSearch>true</FullTextSearch>
+<DocumentNode>
+<Filename>2d4d2587</Filename>
+<Title>File</Title>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>f19dc10a</Filename>
+<Title>Edit </Title>
+<Label>edit</Label>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>98c149b5</Filename>
+<Title>View</Title>
+<Label>view</Label>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>4ecd38e2</Filename>
+<Title>Analyze</Title>
+<Label>analyze</Label>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>6036f840</Filename>
+<Title>Help</Title>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+</DocumentNode>
+<DocumentNode>
+<Filename>0844fec5</Filename>
+<Title>Toolbar</Title>
+<Label>toolbar</Label>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>86d0b0a1</Filename>
+<Title>The sequence pane</Title>
+<FullTextSearch>true</FullTextSearch>
+<DocumentNode>
+<Filename>aa49edd7</Filename>
+<Title>Navigating the sequences</Title>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>e9fd53d0</Filename>
+<Title>Selecting, editing and copying</Title>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>3e7a5715</Filename>
+<Title>Annotations and primers</Title>
+<Label>primers</Label>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>9ee3d3c6</Filename>
+<Title>Multiplex pyrosequencing</Title>
+<Label>multiplexPyrosequencing</Label>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+</DocumentNode>
+<DocumentNode>
+<Filename>9d452f38</Filename>
+<Title>The names pane</Title>
+<FullTextSearch>true</FullTextSearch>
+<DocumentNode>
+<Filename>87de535b</Filename>
+<Title>Moving, editing, master sequences</Title>
+<Label>selecting</Label>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>b69463fa</Filename>
+<Title>Grouping</Title>
+<Label>grouping</Label>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+</DocumentNode>
+</DocumentNode>
+<DocumentNode>
+<Filename>268013c8</Filename>
+<Title>Supported formats</Title>
+<Label>formats</Label>
+<FullTextSearch>true</FullTextSearch>
+<DocumentNode>
+<Filename>6bc41f84</Filename>
+<Title>FASTA (import and export)</Title>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>c9e02254</Filename>
+<Title>RSF (import and export)</Title>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+<DocumentNode>
+<Filename>ec633545</Filename>
+<Title>Geneious (export only)</Title>
+<FullTextSearch>true</FullTextSearch>
+</DocumentNode>
+</DocumentNode>
+</DocumentNode>
+<Label Name="analyze">4ecd38e2</Label>
+<Label Name="edit">f19dc10a</Label>
+<Label Name="formats">268013c8</Label>
+<Label Name="grouping">b69463fa</Label>
+<Label Name="multiplexPyrosequencing">9ee3d3c6</Label>
+<Label Name="primers">3e7a5715</Label>
+<Label Name="selecting">87de535b</Label>
+<Label Name="toolbar">0844fec5</Label>
+<Label Name="view">98c149b5</Label>
+</DocumentTree>
+<ImageLibrary>
+<Root>docuData</Root>
+<Image Name="analyzeMenu.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1296227003000</Timestamp>
+<Width>526</Width>
+<Height>184</Height>
+<Width.INTERN>200</Width.INTERN>
+<Height.INTERN>69</Height.INTERN>
+</Image>
+<Image Name="editMenu.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1296226783000</Timestamp>
+<Width>328</Width>
+<Height>111</Height>
+<Width.INTERN>200</Width.INTERN>
+<Height.INTERN>67</Height.INTERN>
+</Image>
+<Image Name="fileMenu.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1296222845000</Timestamp>
+<Width>235</Width>
+<Height>130</Height>
+<Width.INTERN>200</Width.INTERN>
+<Height.INTERN>110</Height.INTERN>
+</Image>
+<Image Name="helpMenu.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1296227040000</Timestamp>
+<Width>101</Width>
+<Height>46</Height>
+</Image>
+<Image Name="mainWindow.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1296222580000</Timestamp>
+<Width>961</Width>
+<Height>633</Height>
+<Width.INTERN>200</Width.INTERN>
+<Height.INTERN>131</Height.INTERN>
+</Image>
+<Image Name="namesPane.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1313748983000</Timestamp>
+<Width>431</Width>
+<Height>144</Height>
+<Width.INTERN>200</Width.INTERN>
+<Height.INTERN>66</Height.INTERN>
+</Image>
+<Image Name="primer1.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1313487159000</Timestamp>
+<Width>280</Width>
+<Height>209</Height>
+<Width.INTERN>200</Width.INTERN>
+<Height.INTERN>149</Height.INTERN>
+</Image>
+<Image Name="primerProduct.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1313506502000</Timestamp>
+<Width>1072</Width>
+<Height>112</Height>
+<Width.INTERN>200</Width.INTERN>
+<Height.INTERN>20</Height.INTERN>
+</Image>
+<Image Name="pyrograms.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1313411902000</Timestamp>
+<Width>260</Width>
+<Height>258</Height>
+<Width.INTERN>200</Width.INTERN>
+<Height.INTERN>198</Height.INTERN>
+</Image>
+<Image Name="resizingSelection.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1313414107000</Timestamp>
+<Width>192</Width>
+<Height>178</Height>
+</Image>
+<Image Name="sequencePane.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1313412504000</Timestamp>
+<Width>567</Width>
+<Height>300</Height>
+<Width.INTERN>200</Width.INTERN>
+<Height.INTERN>105</Height.INTERN>
+</Image>
+<Image Name="settings.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1296227358000</Timestamp>
+<Width>413</Width>
+<Height>331</Height>
+<Width.INTERN>200</Width.INTERN>
+<Height.INTERN>160</Height.INTERN>
+</Image>
+<Image Name="toolbar.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1313412201000</Timestamp>
+<Width>163</Width>
+<Height>34</Height>
+</Image>
+<Image Name="viewMenu.png">
+<Foundry>docuData</Foundry>
+<Timestamp>1296226867000</Timestamp>
+<Width>189</Width>
+<Height>108</Height>
+</Image>
+<ThumbName Image="analyzeMenu.png">1ea36cbb</ThumbName>
+<ThumbName Image="editMenu.png">90947dcc</ThumbName>
+<ThumbName Image="fileMenu.png">0e171431</ThumbName>
+<ThumbName Image="helpMenu.png">5cf69c5a</ThumbName>
+<ThumbName Image="mainWindow.png">eab1139f</ThumbName>
+<ThumbName Image="namesPane.png">b3efb285</ThumbName>
+<ThumbName Image="primer1.png">5031b155</ThumbName>
+<ThumbName Image="primerProduct.png">e716f121</ThumbName>
+<ThumbName Image="pyrograms.png">70a6cf64</ThumbName>
+<ThumbName Image="resizingSelection.png">c2400ae0</ThumbName>
+<ThumbName Image="sequencePane.png">99550228</ThumbName>
+<ThumbName Image="settings.png">47bc4e12</ThumbName>
+<ThumbName Image="toolbar.png">d5635043</ThumbName>
+<ThumbName Image="viewMenu.png">8ee1d6f4</ThumbName>
+<ThumbnailSize>100</ThumbnailSize>
+</ImageLibrary>
+</HelpSetMaker>
diff --git a/helpSetMaker/html/0844fec5.html b/helpSetMaker/html/0844fec5.html
new file mode 100644
index 0000000..341e8bb
--- /dev/null
+++ b/helpSetMaker/html/0844fec5.html
@@ -0,0 +1,31 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=0844fec5 -->
+<title>Toolbar</title>
+</head>
+<body class="doc">
+<h1>Toolbar</h1>
+<br/><p align="center">
+<img src="pics/toolbar.png" width="163" height="34" /><br/>
+<em>The toolbar</em></p><br/>
+
+<p>The toolbar contains five buttons for quick access to often-used display functionality:
+<ul><li>
+<p>IUB/AGTC: Selects whether to show the consensus sequence as simple majority or as IUB code for non-conserved residues</p>
+</li><li>
+<p>Primer/AGTC: Selects whether to display/edit primer names or primer sequence</p>
+</li><li>
+<p>Primer melting temperature: Switches the display of primer melting temperature (calculated using the stacking model) on or off</p>
+</li><li>
+<p>Primer length: Switches the display of primer length on or off</p>
+</li><li>
+<p>Sequence name: Switches the display of the sequence name under the mouse cursor on or off</p>
+</li></ul>
+</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/268013c8.html b/helpSetMaker/html/268013c8.html
new file mode 100644
index 0000000..33d2ad9
--- /dev/null
+++ b/helpSetMaker/html/268013c8.html
@@ -0,0 +1,16 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=268013c8 -->
+<title>Supported formats</title>
+</head>
+<body class="doc">
+<h1>Supported formats</h1>
+
+<p>Several formats are supported for loading and saving files. Expect this list to grow with time, as theprogram is designed to make adding supported formats easy.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/2d4d2587.html b/helpSetMaker/html/2d4d2587.html
new file mode 100644
index 0000000..403ca0b
--- /dev/null
+++ b/helpSetMaker/html/2d4d2587.html
@@ -0,0 +1,35 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=2d4d2587 -->
+<title>File</title>
+</head>
+<body class="doc">
+<h1>File</h1>
+
+<p>The file menu allows the loading and saving of documents.</p>
+<br/><p align="center">
+<img src="pics/fileMenu.png" width="235" height="130" /><br/>
+<em>The file menu</em></p><br/>
+
+<p>The following options are available:</p>
+
+<ul><li>
+<p>Load file: Loads a new file</p>
+</li><li>
+<p>Append from file: Appends sequences from a file to the currently open document</p>
+</li><li>
+<p>Save: Saves the currently open document</p>
+</li><li>
+<p>Save as: Saves the currently open document under a new name</p>
+</li><li>
+<p>Open recent: Shows a list of recently opened documents</p>
+</li></ul>
+
+<p>A list of formats for both loading and saving files is available in the section <a href="268013c8.html">Supported formats</a>.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/35271893.html b/helpSetMaker/html/35271893.html
new file mode 100644
index 0000000..4c1c37d
--- /dev/null
+++ b/helpSetMaker/html/35271893.html
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=35271893 -->
+<title>The main window</title>
+</head>
+<body class="doc">
+<h1>The main window</h1>
+
+<p>The main window is where all of the work is done in the Sequence Editor. This section will walk zou throught the elements of the main window and the operations which can be performed from here.</p>
+<br/><p align="center">
+<img src="pics/mainWindow.png" width="961" height="633" /><br/>
+<em>The main window with a loaded alignment</em></p><br/>
+</body>
+</html>
diff --git a/helpSetMaker/html/3e7a5715.html b/helpSetMaker/html/3e7a5715.html
new file mode 100644
index 0000000..696ae4c
--- /dev/null
+++ b/helpSetMaker/html/3e7a5715.html
@@ -0,0 +1,34 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=3e7a5715 -->
+<title>Annotations and primers</title>
+</head>
+<body class="doc">
+<h1>Annotations and primers</h1>
+
+<p>Annotations and primers are handled in the same way, with the exception of primers havind some extended functionality. As such, only the handling of primers will be describen in-depth.</p>
+
+<p>When a section of a sequence is selected and right-clicked, the option to add primers or annotations is provided through the context menu. Annotations can be added above or below the sequence, forward primers are always added above the sequence and reverse primers are always added beneath the sequence.</p>
+
+<p>The name of a primer/annotation can be changed by clicking on the primer/annotation, entering a new name and pressing the enter button. In case of primers, the sequence instead of the name can be displayed and edited by pressing the appropriate button on the <a href="0844fec5.html">toolbar</a>. The color of a primer/annotation can be changed by right-clicking on the primer/annotation and selecting "Change color".</p>
+
+<p>Between a primer and the sequence, an identity bar is displayed. It has two rows: The one closer to the sequence displays how well the base matches all sequences: Green means a perfect match, red means that there are sequences in the alignment which do not match the primer, and dark green means that the base in the primer is degenerated in a way which makes it match all sequences in the alignment. The same color code is used in the bar closer to the primer which shows how well the pri [...]
+<br/><p align="center">
+<img src="pics/primer1.png" width="280" height="209" /><br/>
+<em>A reverse primer with two mismatches: One, on the right end, which fits neither the group nor the remaining sequences perfectly and one, on the left end, which fits all sequences in the group perfectly but not the sequences from other groups. The number on the left side shows the length of the primer, the number on the right side shows the meltimg temperature calculated according to the base stacking method.</em></p><br/>
+
+<p>The right-click menu for the primer offers the option to degenerate the primer either to match all sequences in the group or to match all sequences in the alignment. </p>
+
+<p>Annotations and primers can be resized by dragging their ends or moved by dragging the center. When a primer is dragged or resized, it automatically adapts to the sequence it belongs to, except for degenerated bases or mismatches which have been entered manually: These positions are "locked" and will remain degenerated or mismatches.</p>
+
+<p>When a forward and a reverse primer are added to the same sequence, a dashed line will be drawn between them to show the product which would be generated during a PCR reaction. A box in the middle of this line displays the product size (excluding the primers). If the calculated primer melting temperatures are considered too far apart (default: 1 K, can be set in the settings window which is accessible through the <a href="f19dc10a.html">edit</a> menu), the line is red, otherwise the l [...]
+<br/><p align="center">
+<img src="pics/primerProduct.png" width="1072" height="112" /><br/>
+<em>Two primers which could generate a product in a PCR but have melting temperatures which are considered too far apart.</em></p><br/>
+</body>
+</html>
diff --git a/helpSetMaker/html/4ecd38e2.html b/helpSetMaker/html/4ecd38e2.html
new file mode 100644
index 0000000..32c1341
--- /dev/null
+++ b/helpSetMaker/html/4ecd38e2.html
@@ -0,0 +1,40 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=4ecd38e2 -->
+<title>Analyze</title>
+</head>
+<body class="doc">
+<h1>Analyze</h1>
+
+<p>The analysis menu offers some basic sequence analysis options.</p>
+<br/><p align="center">
+<img src="pics/analyzeMenu.png" width="526" height="184" /><br/>
+<em>The analysis menu</em></p><br/>
+
+<p>The following options are available:
+<ul><li>
+<p>Calculate master consensus: Calculates and displays the consensus sequence of all sequences in the alignment</p>
+</li><li>
+<p>Calculate group consensus: Calculates and displays the consensus sequence for every defined <a href="b69463fa.html">group</a></p>
+</li><li>
+<p>Keep consensus up to date: If this is checked, the consensus sequence(s) will automatically be updated whenever a sequence is modified.</p>
+</li><li>
+<p>Group identical sequences: A new group is created for each set of identical sequences in the alignment</p>
+</li><li>
+<p>Sort sequences: The sequences can be sorted by name, by degree of identity (to the consensus sequence or, if a reference sequence is selected, to the reference sequence) or by degree of identity within the current selection. Sorting maintains grouping: If sequences are grouped, then sorting will sort the sequences within each group individually</p>
+</li><li>
+<p>Find all SNPs: This automatically calculates master and group consensus sequences. Then, all positions are marked which are fully conserved within each of the defined groups but not across the whole alignment (meaning that they can be used to differentiate between at least two of the defined groups)</p>
+</li><li>
+<p>Show predicted flowgrams: If <a href="9ee3d3c6.html">pyrosequencing primers</a> are defined, the flowgrams are shown which would be generated during multiplex pyrosequencing for each of the defined <a href="b69463fa.html">groups</a>. A list of <a href="b69463fa.html">groups</a> which are expected to generate no unique pyrogram is provided.</p>
+</li></ul>
+</p>
+<br/><p align="center">
+<img src="pics/pyrograms.png" width="260" height="258" /><br/>
+<em>Predicted pyrograms: The groups VARV and MPXV generate unique pyrograms with the two defined pyrosequencing primers, while the pyrograms for the groups All, VACV and CPXV are identical to each other.</em></p><br/>
+</body>
+</html>
diff --git a/helpSetMaker/html/6036f840.html b/helpSetMaker/html/6036f840.html
new file mode 100644
index 0000000..f728996
--- /dev/null
+++ b/helpSetMaker/html/6036f840.html
@@ -0,0 +1,16 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=6036f840 -->
+<title>Help</title>
+</head>
+<body class="doc">
+<h1>Help</h1>
+
+<p>This document can be opened from here ;)</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/6bc41f84.html b/helpSetMaker/html/6bc41f84.html
new file mode 100644
index 0000000..15a32f9
--- /dev/null
+++ b/helpSetMaker/html/6bc41f84.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=6bc41f84 -->
+<title>FASTA (import and export)</title>
+</head>
+<body class="doc">
+<h1>FASTA (import and export)</h1>
+
+<p>The default FASTA format can be both imported and exported. When exporting, two choices are available: The <i>Blank FASTA file</i>, which is a normal FASTA file and can be read by almost any sequence editor, has the disadvantage of losing grouping information (since the FASTA format does not provide any way to encode metadata). The other option, <i>FASTA file</i>, saves a file in a somewhat extended FASTA format. This file can still be read by most sequence editors, but it contains gr [...]
+
+<p>Files saved in the FASTA format lose all annotation information in any case.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/86d0b0a1.html b/helpSetMaker/html/86d0b0a1.html
new file mode 100644
index 0000000..821b50f
--- /dev/null
+++ b/helpSetMaker/html/86d0b0a1.html
@@ -0,0 +1,21 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=86d0b0a1 -->
+<title>The sequence pane</title>
+</head>
+<body class="doc">
+<h1>The sequence pane</h1>
+<br/><p align="center">
+<img src="pics/sequencePane.png" width="567" height="300" /><br/>
+<em>The sequence pane</em></p><br/>
+
+<p>The sequence pane is where the sequences of the currently loaded alignment are displayed. If <a href="b69463fa.html">groups</a> have been defined and group <a href="4ecd38e2.html">consensus sequences have been calculated</a>, the consensus sequence and identity graph for each group is also shown.</p>
+
+<p>At the top, the currently displayed position in the alignment is shown. </p>
+</body>
+</html>
diff --git a/helpSetMaker/html/87de535b.html b/helpSetMaker/html/87de535b.html
new file mode 100644
index 0000000..7d93d2a
--- /dev/null
+++ b/helpSetMaker/html/87de535b.html
@@ -0,0 +1,20 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=87de535b -->
+<title>Moving, editing, master sequences</title>
+</head>
+<body class="doc">
+<h1>Moving, editing, master sequences</h1>
+
+<p>Sequences can be moved by selecting a name in the names pane and dragging it about. Several sequences can be selected by holding down either the shift or the control key while clicking on the names. The whole selection can then be moved together. Sequences can only be moved within a single <a href="b69463fa.html">group</a>. </p>
+
+<p>When a sequence name is right-cliked on, a context menu appears which allows to set the sequence as the master sequence (it will be displayed at the top of the alignment insead of the consensus sequence and differences to this sesquence will be highlighted instead of differences to the consensus sequence). The sequence can also be deleted or reverse-complemented in place. </p>
+
+<p>Sequences can also be sorted from the right-click menu. The behavior is identical to that of sorting from the <a href="4ecd38e2.html">Analyze</a> menu.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/98c149b5.html b/helpSetMaker/html/98c149b5.html
new file mode 100644
index 0000000..00b0d19
--- /dev/null
+++ b/helpSetMaker/html/98c149b5.html
@@ -0,0 +1,21 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=98c149b5 -->
+<title>View</title>
+</head>
+<body class="doc">
+<h1>View</h1>
+
+<p>The view menu allows customizing the sequence display.</p>
+<br/><p align="center">
+<img src="pics/viewMenu.png" width="189" height="108" /><br/>
+<em>The view menu</em></p><br/>
+
+<p>The color models currently supported are: Monochrome, BioEdit (background), UPGMA (background) and UPGMA. In the background color models, the foreground color is always black.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/9d452f38.html b/helpSetMaker/html/9d452f38.html
new file mode 100644
index 0000000..b4c24ab
--- /dev/null
+++ b/helpSetMaker/html/9d452f38.html
@@ -0,0 +1,19 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=9d452f38 -->
+<title>The names pane</title>
+</head>
+<body class="doc">
+<h1>The names pane</h1>
+
+<p>The names pane is where the names of the sequences in the alignment are displayed and where grouping is performed.</p>
+<br/><p align="center">
+<img src="pics/namesPane.png" width="431" height="144" /><br/>
+<em>The names pane</em></p><br/>
+</body>
+</html>
diff --git a/helpSetMaker/html/9ee3d3c6.html b/helpSetMaker/html/9ee3d3c6.html
new file mode 100644
index 0000000..68c85e2
--- /dev/null
+++ b/helpSetMaker/html/9ee3d3c6.html
@@ -0,0 +1,25 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=9ee3d3c6 -->
+<title>Multiplex pyrosequencing</title>
+</head>
+<body class="doc">
+<h1>Multiplex pyrosequencing</h1>
+
+<p>If <a href="3e7a5715.html">primers</a> have been defined, they can be set as pyrosequencing primers by right-clicking on them and selecting the "Is pyrosequencing primer" checkbox. Once pyrosequencing primers have been defined, the "Show predicted flowgrams" entry in the <a href="4ecd38e2.html">Analyze</a> menu can be selected to show the pyrograms which would be generated for each of the groups in a multiplex pyrosequencing assay. </p>
+<br/><p align="center">
+<img src="pics/pyrograms.png" width="260" height="258" /><br/>
+<em>Predicted pyrograms for two pyrosequencing primers. The pyrograms for the groups All, VACV and CPXV are expected to be identical, while the groups VARV and MPXV are expected to generate unique pyrograms.</em></p><br/>
+
+<p>Each group which generates a unique pyrogram is shown separately, while groups which cannot be differentiated using the defined primers because their pyrograms would be identical are shown together. </p>
+
+<p>While the window showing the predicted pyrograms is visible, the primers in the sequence pane can be resized, moved etc. The changes to the predicted pyrograms are updated in realtime, so that primers positions can easily be optimised.</p>
+
+<p>The flowgram length defines how many pyrosequencing cycles are to be considered in the analysis. The maximum flowgram length is the number of cycles which can be performed using the defined primers before a region would be sequenced which is not fully conserved within each of the groups - at this point, the pyrosequencing would result in several different pyrograms for the same group.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/aa49edd7.html b/helpSetMaker/html/aa49edd7.html
new file mode 100644
index 0000000..92a8470
--- /dev/null
+++ b/helpSetMaker/html/aa49edd7.html
@@ -0,0 +1,16 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=aa49edd7 -->
+<title>Navigating the sequences</title>
+</head>
+<body class="doc">
+<h1>Navigating the sequences</h1>
+
+<p>Sequence navigation is very basic and intuitive: Scrolling is possible either using the scroll bars or through holding the middle mouse button to "grab" the sequence pane and moving the mouse. Zooming can either be performed through the <a href="98c149b5.html">view menu</a> or by holding down the CTRL-key on the keyboard and moving the scroll wheel on the mouse.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/ae869282.html b/helpSetMaker/html/ae869282.html
new file mode 100644
index 0000000..8a64e0e
--- /dev/null
+++ b/helpSetMaker/html/ae869282.html
@@ -0,0 +1,16 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=ae869282 -->
+<title>mPSQed</title>
+</head>
+<body class="doc">
+<h1>mPSQed</h1>
+
+<p>This Sequence Editor developed at the Robert Koch Institute in Berlin, Germany aims to make the design of PCR and Multiplex Pyrosequencing assays based on nucleotide alignments easier. The following pages describe the main functions of the editor.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/b139c808.html b/helpSetMaker/html/b139c808.html
new file mode 100644
index 0000000..d3a8a52
--- /dev/null
+++ b/helpSetMaker/html/b139c808.html
@@ -0,0 +1,16 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=b139c808 -->
+<title>Menus</title>
+</head>
+<body class="doc">
+<h1>Menus</h1>
+
+<p>This section walks through the menus available in the editor.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/b69463fa.html b/helpSetMaker/html/b69463fa.html
new file mode 100644
index 0000000..296795a
--- /dev/null
+++ b/helpSetMaker/html/b69463fa.html
@@ -0,0 +1,22 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=b69463fa -->
+<title>Grouping</title>
+</head>
+<body class="doc">
+<h1>Grouping</h1>
+
+<p>Sequences can be organised in groups. This is useful for finding SNPs which could be used in species-specific assays using the "Find all SNPs" entry in the <a href="4ecd38e2.html">Analyze</a> menu or in the design of <a href="9ee3d3c6.html">multiplex pyrosequencing assays</a>.</p>
+
+<p>Sequences can be grouped together by <a href="87de535b.html">selecting</a> one or more sequences, right-clicking on the selection and then choosing the "Set as group" option. A group name can then be entered, and the selected sequences will be moved to a new group with that name. The group of a sequence is shown in braces in front of the sequence name and groups can be collapsed or expanded by clicking on the minur or plus sign in front of the first sequence in a group. </p>
+
+<p>Sequences can be moved from group to group by right-clicking on a sequence and selecting the target group from the "Add sequence to group" entry.</p>
+
+<p>There is no separate option to rename a group. However, empty groups will be deleted, so renaming a group can be done by selecting all sequences from a group, right-clicking, selecting "Set as group" and entering the new group name. All selected sequences will be moved to a new group with the new name, and the old group will be deleted since it will then be empty.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/c9e02254.html b/helpSetMaker/html/c9e02254.html
new file mode 100644
index 0000000..7584e25
--- /dev/null
+++ b/helpSetMaker/html/c9e02254.html
@@ -0,0 +1,18 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=c9e02254 -->
+<title>RSF (import and export)</title>
+</head>
+<body class="doc">
+<h1>RSF (import and export)</h1>
+
+<p>The Rich Sequence Format (RSF) is a format used by the program SeqLab. It is also the default format for the RKI Sequence Editor since it allows the saving of metadata. It is currently the only supported format which allows the saving of all grouping, annotation and primer information.</p>
+
+<p>As a result, it is recommended to save files in the RKI Sequence Editor using the Rich Sequence Format and only to export to one of the other supported format when data is exchanged with colleagues using another editor.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/e9fd53d0.html b/helpSetMaker/html/e9fd53d0.html
new file mode 100644
index 0000000..7f1cb12
--- /dev/null
+++ b/helpSetMaker/html/e9fd53d0.html
@@ -0,0 +1,37 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=e9fd53d0 -->
+<title>Selecting, editing and copying</title>
+</head>
+<body class="doc">
+<h1>Selecting, editing and copying</h1>
+
+<p>Sequences can be selected using the mouse. An existing selection can be resized by grabbing one of its corners with the mouse and dragging. </p>
+<br/><p align="center">
+<img src="pics/resizingSelection.png" width="192" height="178" /><br/>
+<em>Resizing an existing selection</em></p><br/>
+
+<p>Selecting on a <a href="4ecd38e2.html">group consensus sequence</a> will select the specified region of all sequences within the group, selecting on the master consensus sequence will select the specified region of all sequences in the alignment. Once a selection has been made, it can be copied to the system buffer by right-clicking on it and selecting one of the following options:
+<ul><li>
+<p>Sequences: Copies the selected parts of the sequences, with each sequence in a separate line</p>
+</li><li>
+<p>Sequences with names: Copies the selected parts of the sequence, including the sequence names, in FASTA format. The sequence names will end with the selection range in braces (e.g.: ">DQ983239 (172 - 246)")</p>
+</li><li>
+<p>Master consensus sequence: Copies the master consensus sequence for the selected range</p>
+</li><li>
+<p>Group consensus sequence: Copies the consensus sequence for the selected group</p>
+</li></ul>
+</p>
+
+<p>When right-clicking on a selection, the option "Delete selected" is also available. This deletes the selected bases, shifting the bases following on the right-hand side left to fill the gap.</p>
+
+<p>The right-click menu for a sequence selection also contains two submenus for the adding of primers and annotations, which is described in-depth in the <a href="3e7a5715.html">next section</a>.</p>
+
+<p>Sequences can also be edited: When a single residue is clicked on, a cursor is shown around that residue. This cursor can be moved using the arrow keys on the keyboard. The base under the cursor can be modified through the keyboard (all IUPAC nucleotide codes can be entered). Clicking somewhere else in the sequence pane exits the editing mode.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/ec633545.html b/helpSetMaker/html/ec633545.html
new file mode 100644
index 0000000..6a06b79
--- /dev/null
+++ b/helpSetMaker/html/ec633545.html
@@ -0,0 +1,16 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=ec633545 -->
+<title>Geneious (export only)</title>
+</head>
+<body class="doc">
+<h1>Geneious (export only)</h1>
+
+<p>The Geneious format is supported only for exporting files. It can be read by the bioinformatics workbench <a target="_blank" href="http://www.geneious.com">Geneious</a>. Using this file format preserves annotation and grouping - however, since Geneious has no concept of sequence grouping within a single alignment, grouping information is effectively lost when using this format.</p>
+</body>
+</html>
diff --git a/helpSetMaker/html/f19dc10a.html b/helpSetMaker/html/f19dc10a.html
new file mode 100644
index 0000000..036f2e9
--- /dev/null
+++ b/helpSetMaker/html/f19dc10a.html
@@ -0,0 +1,38 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta name="date" content="20120112104753" />
+<!-- created with HelpSetMaker, ID=f19dc10a -->
+<title>Edit </title>
+</head>
+<body class="doc">
+<h1>Edit </h1>
+
+<p>The edit menu allows copying sequences and modifying the settings.</p>
+<br/><p align="center">
+<img src="pics/editMenu.png" width="328" height="111" /><br/>
+<em>The edit menu</em></p><br/>
+
+<p>When copying sequences, the following options are available:</p>
+
+<ul><li>
+<p>Sequences: Copies the selected nucleotides. If several sequences are selected, the nucleotides from each sequence will be copied in a separate line.</p>
+</li><li>
+<p>Sequences with names: Copies the selected sequence parts in FASTA format, with sequence names and selected nucleotides. This can be useful for example for blasting several sequences at once.</p>
+</li><li>
+<p>Master consensus sequence: Copies the master consensus sequence for the selected part of the alignment.</p>
+</li><li>
+<p>Group consensus sequence: Copies the group consensus sequence for the selected part of the alignment.</p>
+</li></ul>
+
+<p>The settings option allows editing the general settings of the program. Currently, the only configurable section pertains to primers:</p>
+<br/><p align="center">
+<img src="pics/settings.png" width="413" height="331" /><br/>
+<em>The settings window</em></p><br/>
+
+<p>The top three options are used when calculating the melting temperature (tm) of primers. If two primers can create an amplification product and their tm differs by too much, a warning can be displayed. The tm difference necessary for this warning to appear and the color of the warning can be set in the last two options. </p>
+</body>
+</html>
diff --git a/helpSetMaker/html/index.html b/helpSetMaker/html/index.html
new file mode 100644
index 0000000..b63d227
--- /dev/null
+++ b/helpSetMaker/html/index.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd"><HTML><HEAD><meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1'></meta>
+<TITLE>mPSQed</title></head>
+<FRAMESET cols="20%,80%">
+<FRAME src="toc.html" name="tocFrame">
+<FRAME src="ae869282.html" name="textFrame">
+</FRAMESET>
+<NOFRAMES>
+<H2>html4.framealert.title</H2><p>html4.framealert.info</p>
+</noframes>
+</html>
\ No newline at end of file
diff --git a/helpSetMaker/html/pics/analyzeMenu.png b/helpSetMaker/html/pics/analyzeMenu.png
new file mode 100644
index 0000000..fe77481
Binary files /dev/null and b/helpSetMaker/html/pics/analyzeMenu.png differ
diff --git a/helpSetMaker/html/pics/editMenu.png b/helpSetMaker/html/pics/editMenu.png
new file mode 100644
index 0000000..1e6fbff
Binary files /dev/null and b/helpSetMaker/html/pics/editMenu.png differ
diff --git a/helpSetMaker/html/pics/fileMenu.png b/helpSetMaker/html/pics/fileMenu.png
new file mode 100644
index 0000000..05ee971
Binary files /dev/null and b/helpSetMaker/html/pics/fileMenu.png differ
diff --git a/helpSetMaker/html/pics/mainWindow.png b/helpSetMaker/html/pics/mainWindow.png
new file mode 100644
index 0000000..3bd75d6
Binary files /dev/null and b/helpSetMaker/html/pics/mainWindow.png differ
diff --git a/helpSetMaker/html/pics/namesPane.png b/helpSetMaker/html/pics/namesPane.png
new file mode 100644
index 0000000..ba46701
Binary files /dev/null and b/helpSetMaker/html/pics/namesPane.png differ
diff --git a/helpSetMaker/html/pics/primer1.png b/helpSetMaker/html/pics/primer1.png
new file mode 100644
index 0000000..345b34d
Binary files /dev/null and b/helpSetMaker/html/pics/primer1.png differ
diff --git a/helpSetMaker/html/pics/primerProduct.png b/helpSetMaker/html/pics/primerProduct.png
new file mode 100644
index 0000000..9667fee
Binary files /dev/null and b/helpSetMaker/html/pics/primerProduct.png differ
diff --git a/helpSetMaker/html/pics/pyrograms.png b/helpSetMaker/html/pics/pyrograms.png
new file mode 100644
index 0000000..ba5c497
Binary files /dev/null and b/helpSetMaker/html/pics/pyrograms.png differ
diff --git a/helpSetMaker/html/pics/resizingSelection.png b/helpSetMaker/html/pics/resizingSelection.png
new file mode 100644
index 0000000..78015e0
Binary files /dev/null and b/helpSetMaker/html/pics/resizingSelection.png differ
diff --git a/helpSetMaker/html/pics/sequencePane.png b/helpSetMaker/html/pics/sequencePane.png
new file mode 100644
index 0000000..f86336b
Binary files /dev/null and b/helpSetMaker/html/pics/sequencePane.png differ
diff --git a/helpSetMaker/html/pics/settings.png b/helpSetMaker/html/pics/settings.png
new file mode 100644
index 0000000..f3efec7
Binary files /dev/null and b/helpSetMaker/html/pics/settings.png differ
diff --git a/helpSetMaker/html/pics/toolbar.png b/helpSetMaker/html/pics/toolbar.png
new file mode 100644
index 0000000..bd6eaa0
Binary files /dev/null and b/helpSetMaker/html/pics/toolbar.png differ
diff --git a/helpSetMaker/html/pics/viewMenu.png b/helpSetMaker/html/pics/viewMenu.png
new file mode 100644
index 0000000..886de81
Binary files /dev/null and b/helpSetMaker/html/pics/viewMenu.png differ
diff --git a/helpSetMaker/html/toc.html b/helpSetMaker/html/toc.html
new file mode 100644
index 0000000..3f6e0cc
--- /dev/null
+++ b/helpSetMaker/html/toc.html
@@ -0,0 +1,34 @@
+<html><head><meta http-equiv='Content-Type' content='text/html; charset=ISO-8859-1'></meta>
+<title>HTML4TOC</title>
+<style>
+li { margin-left: -5mm; }
+</style>
+</head><body class="toc">
+<a class="toc1" href="ae869282.html" target="textFrame">mPSQed</a><br />
+<ul class="toc2"><li class="toc2"><a class="toc2" href="35271893.html" target="textFrame">The main window</a>
+<ul class="toc3"><li class="toc3"><a class="toc3" href="b139c808.html" target="textFrame">Menus</a>
+<ul class="toc4"><li class="toc4"><a class="toc4" href="2d4d2587.html" target="textFrame">File</a></li>
+<li class="toc4"><a class="toc4" href="f19dc10a.html" target="textFrame">Edit </a></li>
+<li class="toc4"><a class="toc4" href="98c149b5.html" target="textFrame">View</a></li>
+<li class="toc4"><a class="toc4" href="4ecd38e2.html" target="textFrame">Analyze</a></li>
+<li class="toc4"><a class="toc4" href="6036f840.html" target="textFrame">Help</a></li>
+</ul></li>
+<li class="toc3"><a class="toc3" href="0844fec5.html" target="textFrame">Toolbar</a></li>
+<li class="toc3"><a class="toc3" href="86d0b0a1.html" target="textFrame">The sequence pane</a>
+<ul class="toc4"><li class="toc4"><a class="toc4" href="aa49edd7.html" target="textFrame">Navigating the sequences</a></li>
+<li class="toc4"><a class="toc4" href="e9fd53d0.html" target="textFrame">Selecting, editing and copying</a></li>
+<li class="toc4"><a class="toc4" href="3e7a5715.html" target="textFrame">Annotations and primers</a></li>
+<li class="toc4"><a class="toc4" href="9ee3d3c6.html" target="textFrame">Multiplex pyrosequencing</a></li>
+</ul></li>
+<li class="toc3"><a class="toc3" href="9d452f38.html" target="textFrame">The names pane</a>
+<ul class="toc4"><li class="toc4"><a class="toc4" href="87de535b.html" target="textFrame">Moving, editing, master sequences</a></li>
+<li class="toc4"><a class="toc4" href="b69463fa.html" target="textFrame">Grouping</a></li>
+</ul></li>
+</ul></li>
+<li class="toc2"><a class="toc2" href="268013c8.html" target="textFrame">Supported formats</a>
+<ul class="toc3"><li class="toc3"><a class="toc3" href="6bc41f84.html" target="textFrame">FASTA (import and export)</a></li>
+<li class="toc3"><a class="toc3" href="c9e02254.html" target="textFrame">RSF (import and export)</a></li>
+<li class="toc3"><a class="toc3" href="ec633545.html" target="textFrame">Geneious (export only)</a></li>
+</ul></li>
+</ul>
+</body></html>
diff --git a/helpSetMaker/latex/doc.aux b/helpSetMaker/latex/doc.aux
new file mode 100644
index 0000000..7723ec3
--- /dev/null
+++ b/helpSetMaker/latex/doc.aux
@@ -0,0 +1,13 @@
+\relax 
+\select at language{english}
+\@writefile{toc}{\select at language{english}}
+\@writefile{lof}{\select at language{english}}
+\@writefile{lot}{\select at language{english}}
+\select at language{english}
+\@writefile{toc}{\select at language{english}}
+\@writefile{lof}{\select at language{english}}
+\@writefile{lot}{\select at language{english}}
+\select at language{english}
+\@writefile{toc}{\select at language{english}}
+\@writefile{lof}{\select at language{english}}
+\@writefile{lot}{\select at language{english}}
diff --git a/helpSetMaker/latex/doc.log b/helpSetMaker/latex/doc.log
new file mode 100644
index 0000000..432536f
--- /dev/null
+++ b/helpSetMaker/latex/doc.log
@@ -0,0 +1,268 @@
+This is pdfTeX, Version 3.1415926-1.40.10 (TeX Live 2009/Debian) (format=pdflatex 2010.10.28)  28 JAN 2011 13:47
+entering extended mode
+ restricted \write18 enabled.
+ %&-line parsing enabled.
+**doc.tex
+(./doc.tex
+LaTeX2e <2009/09/24>
+Babel <v3.8l> and hyphenation patterns for english, usenglishmax, dumylang, noh
+yphenation, ngerman, german, german-x-2009-06-19, ngerman-x-2009-06-19, loaded.
+
+(/usr/share/texmf-texlive/tex/latex/base/article.cls
+Document Class: article 2007/10/19 v1.4h Standard LaTeX document class
+(/usr/share/texmf-texlive/tex/latex/base/size10.clo
+File: size10.clo 2007/10/19 v1.4h Standard LaTeX file (size option)
+)
+\c at part=\count79
+\c at section=\count80
+\c at subsection=\count81
+\c at subsubsection=\count82
+\c at paragraph=\count83
+\c at subparagraph=\count84
+\c at figure=\count85
+\c at table=\count86
+\abovecaptionskip=\skip41
+\belowcaptionskip=\skip42
+\bibindent=\dimen102
+)
+(/usr/share/texmf-texlive/tex/latex/base/fontenc.sty
+Package: fontenc 2005/09/27 v1.99g Standard LaTeX package
+
+(/usr/share/texmf-texlive/tex/latex/base/t1enc.def
+File: t1enc.def 2005/09/27 v1.99g Standard LaTeX file
+LaTeX Font Info:    Redeclaring font encoding T1 on input line 43.
+))
+(/usr/share/texmf-texlive/tex/latex/anysize/anysize.sty
+Package: anysize 1994/08/13 setting margin sizes
+
+document style option `anysize' loaded
+Michael Salzenberg, Thomas Esser, Dirk Hillbrecht
+Version 1.0, Aug 13, 1994
+\@Leftmargin=\dimen103
+\@Rightmargin=\dimen104
+\@Topmargin=\dimen105
+\@Bottommargin=\dimen106
+) (/usr/share/texmf-texlive/tex/latex/base/inputenc.sty
+Package: inputenc 2008/03/30 v1.1d Input encoding file
+\inpenc at prehook=\toks14
+\inpenc at posthook=\toks15
+
+(/usr/share/texmf-texlive/tex/latex/base/latin1.def
+File: latin1.def 2008/03/30 v1.1d Input encoding file
+))
+(/usr/share/texmf-texlive/tex/generic/babel/babel.sty
+Package: babel 2008/07/06 v3.8l The Babel package
+
+(/usr/share/texmf-texlive/tex/generic/babel/english.ldf
+Language: english 2005/03/30 v3.3o English support from the babel system
+
+(/usr/share/texmf-texlive/tex/generic/babel/babel.def
+File: babel.def 2008/07/06 v3.8l Babel common definitions
+\babel at savecnt=\count87
+\U at D=\dimen107
+)
+\l at british = a dialect from \language\l at english 
+\l at UKenglish = a dialect from \language\l at english 
+\l at canadian = a dialect from \language\l at american 
+\l at australian = a dialect from \language\l at british 
+\l at newzealand = a dialect from \language\l at british 
+))
+(/usr/share/texmf-texlive/tex/latex/hyphenat/hyphenat.sty
+Package: hyphenat 2009/09/02 v2.3c hyphenation utilities
+
+
+Package hyphenat Warning: *******************************
+(hyphenat)                * You have used the htt option.
+(hyphenat)                * You are likely to get many Font Warning messages.
+(hyphenat)                * These can usually be ignored.
+(hyphenat)                *******************************.
+
+\langwohyphens=\language8
+LaTeX Info: Redefining \_ on input line 43.
+) (/usr/share/texmf-texlive/tex/latex/graphics/graphicx.sty
+Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR)
+
+(/usr/share/texmf-texlive/tex/latex/graphics/keyval.sty
+Package: keyval 1999/03/16 v1.13 key=value parser (DPC)
+\KV at toks@=\toks16
+)
+(/usr/share/texmf-texlive/tex/latex/graphics/graphics.sty
+Package: graphics 2009/02/05 v1.0o Standard LaTeX Graphics (DPC,SPQR)
+
+(/usr/share/texmf-texlive/tex/latex/graphics/trig.sty
+Package: trig 1999/03/16 v1.09 sin cos tan (DPC)
+)
+(/etc/texmf/tex/latex/config/graphics.cfg
+File: graphics.cfg 2009/08/28 v1.8 graphics configuration of TeX Live
+)
+Package graphics Info: Driver file: pdftex.def on input line 91.
+
+(/usr/share/texmf-texlive/tex/latex/pdftex-def/pdftex.def
+File: pdftex.def 2009/08/25 v0.04m Graphics/color for pdfTeX
+\Gread at gobject=\count88
+))
+\Gin at req@height=\dimen108
+\Gin at req@width=\dimen109
+) (./doc.aux)
+\openout1 = `doc.aux'.
+
+LaTeX Font Info:    Checking defaults for OML/cmm/m/it on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for T1/cmr/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for OT1/cmr/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for OMS/cmsy/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for OMX/cmex/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Checking defaults for U/cmr/m/n on input line 14.
+LaTeX Font Info:    ... okay on input line 14.
+LaTeX Font Info:    Try loading font information for T1+cmtt on input line 14.
+
+(/usr/share/texmf-texlive/tex/latex/base/t1cmtt.fd
+File: t1cmtt.fd 1999/05/25 v2.5h Standard LaTeX font definitions
+)
+
+LaTeX Font Warning: Font shape `T1/cmtt/b/n' undefined
+(Font)              using `T1/cmtt/m/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/b/it' undefined
+(Font)              using `T1/cmtt/b/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/b/sl' undefined
+(Font)              using `T1/cmtt/b/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/b/sc' undefined
+(Font)              using `T1/cmtt/b/n' instead on input line 14.
+
+LaTeX Font Info:    Font shape `T1/cmtt/bx/n' in size <10> not available
+(Font)              Font shape `T1/cmtt/m/n' tried instead on input line 14.
+LaTeX Font Info:    Font shape `T1/cmtt/bx/it' in size <10> not available
+(Font)              Font shape `T1/cmtt/m/it' tried instead on input line 14.
+
+LaTeX Font Warning: Font shape `T1/cmtt/bx/sl' undefined
+(Font)              using `T1/cmtt/bx/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/bx/sc' undefined
+(Font)              using `T1/cmtt/bx/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/sb/n' undefined
+(Font)              using `T1/cmtt/m/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/sb/it' undefined
+(Font)              using `T1/cmtt/sb/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/sb/sl' undefined
+(Font)              using `T1/cmtt/sb/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/sb/sc' undefined
+(Font)              using `T1/cmtt/sb/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/c/n' undefined
+(Font)              using `T1/cmtt/m/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/c/it' undefined
+(Font)              using `T1/cmtt/c/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/c/sl' undefined
+(Font)              using `T1/cmtt/c/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/c/sc' undefined
+(Font)              using `T1/cmtt/c/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/l/n' undefined
+(Font)              using `T1/cmtt/m/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/l/it' undefined
+(Font)              using `T1/cmtt/l/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/l/sl' undefined
+(Font)              using `T1/cmtt/l/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/l/sc' undefined
+(Font)              using `T1/cmtt/l/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/m/ui' undefined
+(Font)              using `T1/cmtt/m/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/bx/ui' undefined
+(Font)              using `T1/cmtt/bx/n' instead on input line 14.
+
+
+LaTeX Font Warning: Font shape `T1/cmtt/m/In' undefined
+(Font)              using `T1/cmtt/m/n' instead on input line 14.
+
+(/usr/share/texmf-texlive/tex/context/base/supp-pdf.mkii
+[Loading MPS to PDF converter (version 2006.09.02).]
+\scratchcounter=\count89
+\scratchdimen=\dimen110
+\scratchbox=\box26
+\nofMPsegments=\count90
+\nofMParguments=\count91
+\everyMPshowfont=\toks17
+\MPscratchCnt=\count92
+\MPscratchDim=\dimen111
+\MPnumerator=\count93
+\everyMPtoPDFconversion=\toks18
+)
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <12> on input line 16.
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <8> on input line 16.
+LaTeX Font Info:    External font `cmex10' loaded for size
+(Font)              <6> on input line 16.
+
+
+LaTeX Warning: No \author given.
+
+(./doc.toc)
+\tf at toc=\write3
+\openout3 = `doc.toc'.
+
+ [1
+
+{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] [2]
+(./doc.aux)
+
+LaTeX Font Warning: Some font shapes were not available, defaults substituted.
+
+ ) 
+Here is how much of TeX's memory you used:
+ 1591 strings out of 495021
+ 19181 string characters out of 1181034
+ 67356 words of memory out of 3000000
+ 4789 multiletter control sequences out of 15000+50000
+ 13012 words of font info for 34 fonts, out of 3000000 for 9000
+ 28 hyphenation exceptions out of 8191
+ 26i,6n,22p,290b,193s stack positions out of 5000i,500n,10000p,200000b,50000s
+ </home/dabrowskiw/.texmf-var/fonts/pk/ljfour/jknappen/ec/ecrm0900.600pk> </h
+ome/dabrowskiw/.texmf-var/fonts/pk/ljfour/jknappen/ec/ecbx0900.600pk> </home/da
+browskiw/.texmf-var/fonts/pk/ljfour/jknappen/ec/ecrm1000.600pk> </home/dabrowsk
+iw/.texmf-var/fonts/pk/ljfour/jknappen/ec/ecbx1440.600pk> </home/dabrowskiw/.te
+xmf-var/fonts/pk/ljfour/jknappen/ec/ecrm1200.600pk> </home/dabrowskiw/.texmf-va
+r/fonts/pk/ljfour/jknappen/ec/ecrm1728.600pk>
+Output written on doc.pdf (2 pages, 20874 bytes).
+PDF statistics:
+ 81 PDF objects out of 1000 (max. 8388607)
+ 0 named destinations out of 1000 (max. 500000)
+ 1 words of extra memory for PDF output out of 10000 (max. 10000000)
+
diff --git a/helpSetMaker/latex/doc.pdf b/helpSetMaker/latex/doc.pdf
new file mode 100644
index 0000000..e7d8ff4
Binary files /dev/null and b/helpSetMaker/latex/doc.pdf differ
diff --git a/helpSetMaker/latex/doc.tex b/helpSetMaker/latex/doc.tex
new file mode 100644
index 0000000..421f609
--- /dev/null
+++ b/helpSetMaker/latex/doc.tex
@@ -0,0 +1,26 @@
+\NeedsTeXFormat{LaTeX2e}
+\documentclass[10pt,a4paper,oneside,english]{article}
+\usepackage[T1]{fontenc}
+\usepackage{anysize}
+\marginsize{3.0cm}{2.0cm}{2.0cm}{2.0cm}
+\usepackage[latin1]{inputenc}
+\usepackage[english]{babel}
+\usepackage[htt]{hyphenat}
+\usepackage{graphicx}
+\newcommand{\hsmimage}[3]{\begin{figure}[!ht]\centering\includegraphics[width=#2]{#1}\caption{#3}\end{figure}}
+\newcommand{\clearemptydoublepage}{\newpage{\pagestyle{empty}\cleardoublepage}}
+\selectlanguage{english}
+\title{RKI Sequence Editor}
+\begin{document}
+\selectlanguage{english}
+\maketitle
+\tableofcontents
+\newpage
+
+\begin{abstract}
+This is a test
+
+
+\end{abstract}
+
+\end{document}
diff --git a/helpSetMaker/latex/doc.toc b/helpSetMaker/latex/doc.toc
new file mode 100644
index 0000000..c1bc397
--- /dev/null
+++ b/helpSetMaker/latex/doc.toc
@@ -0,0 +1,3 @@
+\select at language {english}
+\select at language {english}
+\select at language {english}
diff --git a/helpSetMaker/presets/dabrowskiw.xml b/helpSetMaker/presets/dabrowskiw.xml
new file mode 100644
index 0000000..7f72bbb
--- /dev/null
+++ b/helpSetMaker/presets/dabrowskiw.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<HelpSetMaker>
+<Engine>
+<Value Key="expensivelabelcheck">false</Value>
+<Value Key="ilsplit.lastlocation">230</Value>
+<Value Key="ilsplit.location">156</Value>
+<Value Key="showanchors">false</Value>
+<Value Key="showlabels">true</Value>
+<Value Key="split.location">373</Value>
+<Value Key="stmleditor.autoupdate">true</Value>
+<Value Key="stmleditor.showhtml">true</Value>
+<Value Key="vsplit.lastlocation">692</Value>
+<Value Key="vsplit.location">692</Value>
+</Engine>
+<EditorData Filename="ae869282">15,0</EditorData>
+<EditorData Filename="35271893">292,0</EditorData>
+<EditorData Filename="b139c808">75,0</EditorData>
+<EditorData Filename="2d4d2587">105,0</EditorData>
+<EditorData Filename="f19dc10a">24,0</EditorData>
+<EditorData Filename="98c149b5">23,0</EditorData>
+<EditorData Filename="4ecd38e2">29,0</EditorData>
+<EditorData Filename="6036f840">53,0</EditorData>
+<EditorData Filename="0844fec5">62,0</EditorData>
+<EditorData Filename="86d0b0a1">362,0</EditorData>
+<EditorData Filename="aa49edd7">378,0</EditorData>
+<EditorData Filename="e9fd53d0">1454,0</EditorData>
+<EditorData Filename="3e7a5715">3126,432</EditorData>
+<EditorData Filename="9ee3d3c6">1521,0</EditorData>
+<EditorData Filename="9d452f38">174,0</EditorData>
+<EditorData Filename="87de535b">57,0</EditorData>
+<EditorData Filename="b69463fa">788,0</EditorData>
+<EditorData Filename="268013c8">201,0</EditorData>
+<EditorData Filename="6bc41f84">871,0</EditorData>
+<EditorData Filename="c9e02254">539,0</EditorData>
+<EditorData Filename="ec633545">385,0</EditorData>
+</HelpSetMaker>
diff --git a/helpSetMaker/src/0844fec5.stml b/helpSetMaker/src/0844fec5.stml
new file mode 100644
index 0000000..5749d51
--- /dev/null
+++ b/helpSetMaker/src/0844fec5.stml
@@ -0,0 +1,11 @@
+:title Toolbar
+:label toolbar
+
+:image toolbar.png|The toolbar
+
+The toolbar contains five buttons for quick access to often-used display functionality:
+- IUB/AGTC: Selects whether to show the consensus sequence as simple majority or as IUB code for non-conserved residues
+- Primer/AGTC: Selects whether to display/edit primer names or primer sequence
+- Primer melting temperature: Switches the display of primer melting temperature (calculated using the stacking model) on or off
+- Primer length: Switches the display of primer length on or off
+- Sequence name: Switches the display of the sequence name under the mouse cursor on or off
\ No newline at end of file
diff --git a/helpSetMaker/src/268013c8.stml b/helpSetMaker/src/268013c8.stml
new file mode 100644
index 0000000..e1b1c2d
--- /dev/null
+++ b/helpSetMaker/src/268013c8.stml
@@ -0,0 +1,4 @@
+:title Supported formats
+:label formats
+
+Several formats are supported for loading and saving files. Expect this list to grow with time, as theprogram is designed to make adding supported formats easy.
\ No newline at end of file
diff --git a/helpSetMaker/src/2d4d2587.stml b/helpSetMaker/src/2d4d2587.stml
new file mode 100644
index 0000000..fc89ca2
--- /dev/null
+++ b/helpSetMaker/src/2d4d2587.stml
@@ -0,0 +1,15 @@
+:title File
+
+The file menu allows the loading and saving of documents.
+
+:image fileMenu.png|The file menu
+
+The following options are available:
+
+- Load file: Loads a new file
+- Append from file: Appends sequences from a file to the currently open document
+- Save: Saves the currently open document
+- Save as: Saves the currently open document under a new name
+- Open recent: Shows a list of recently opened documents
+
+A list of formats for both loading and saving files is available in the section <<formats|Supported formats>>.
\ No newline at end of file
diff --git a/helpSetMaker/src/35271893.stml b/helpSetMaker/src/35271893.stml
new file mode 100644
index 0000000..7e54ee7
--- /dev/null
+++ b/helpSetMaker/src/35271893.stml
@@ -0,0 +1,6 @@
+:title The main window
+
+The main window is where all of the work is done in the Sequence Editor. This section will walk zou throught the elements of the main window and the operations which can be performed from here.
+
+:image mainWindow.png|The main window with a loaded alignment|mainWindow
+
diff --git a/helpSetMaker/src/3e7a5715.stml b/helpSetMaker/src/3e7a5715.stml
new file mode 100644
index 0000000..0f6aaa9
--- /dev/null
+++ b/helpSetMaker/src/3e7a5715.stml
@@ -0,0 +1,20 @@
+:title Annotations and primers
+:label primers
+
+Annotations and primers are handled in the same way, with the exception of primers havind some extended functionality. As such, only the handling of primers will be describen in-depth.
+
+When a section of a sequence is selected and right-clicked, the option to add primers or annotations is provided through the context menu. Annotations can be added above or below the sequence, forward primers are always added above the sequence and reverse primers are always added beneath the sequence.
+
+The name of a primer/annotation can be changed by clicking on the primer/annotation, entering a new name and pressing the enter button. In case of primers, the sequence instead of the name can be displayed and edited by pressing the appropriate button on the <<toolbar|toolbar>>. The color of a primer/annotation can be changed by right-clicking on the primer/annotation and selecting "Change color".
+
+Between a primer and the sequence, an identity bar is displayed. It has two rows: The one closer to the sequence displays how well the base matches all sequences: Green means a perfect match, red means that there are sequences in the alignment which do not match the primer, and dark green means that the base in the primer is degenerated in a way which makes it match all sequences in the alignment. The same color code is used in the bar closer to the primer which shows how well the primer [...]
+
+:image primer1.png|A reverse primer with two mismatches: One, on the right end, which fits neither the group nor the remaining sequences perfectly and one, on the left end, which fits all sequences in the group perfectly but not the sequences from other groups. The number on the left side shows the length of the primer, the number on the right side shows the meltimg temperature calculated according to the base stacking method.
+
+The right-click menu for the primer offers the option to degenerate the primer either to match all sequences in the group or to match all sequences in the alignment. 
+
+Annotations and primers can be resized by dragging their ends or moved by dragging the center. When a primer is dragged or resized, it automatically adapts to the sequence it belongs to, except for degenerated bases or mismatches which have been entered manually: These positions are "locked" and will remain degenerated or mismatches.
+
+When a forward and a reverse primer are added to the same sequence, a dashed line will be drawn between them to show the product which would be generated during a PCR reaction. A box in the middle of this line displays the product size (excluding the primers). If the calculated primer melting temperatures are considered too far apart (default: 1 K, can be set in the settings window which is accessible through the <<edit|edit>> menu), the line is red, otherwise the line is black.
+
+:image primerProduct.png|Two primers which could generate a product in a PCR but have melting temperatures which are considered too far apart.
diff --git a/helpSetMaker/src/4ecd38e2.stml b/helpSetMaker/src/4ecd38e2.stml
new file mode 100644
index 0000000..4ac0883
--- /dev/null
+++ b/helpSetMaker/src/4ecd38e2.stml
@@ -0,0 +1,17 @@
+:title Analyze
+:label analyze
+
+The analysis menu offers some basic sequence analysis options.
+
+:image analyzeMenu.png|The analysis menu
+
+The following options are available:
+- Calculate master consensus: Calculates and displays the consensus sequence of all sequences in the alignment
+- Calculate group consensus: Calculates and displays the consensus sequence for every defined <<grouping|group>>
+- Keep consensus up to date: If this is checked, the consensus sequence(s) will automatically be updated whenever a sequence is modified.
+- Group identical sequences: A new group is created for each set of identical sequences in the alignment
+- Sort sequences: The sequences can be sorted by name, by degree of identity (to the consensus sequence or, if a reference sequence is selected, to the reference sequence) or by degree of identity within the current selection. Sorting maintains grouping: If sequences are grouped, then sorting will sort the sequences within each group individually
+- Find all SNPs: This automatically calculates master and group consensus sequences. Then, all positions are marked which are fully conserved within each of the defined groups but not across the whole alignment (meaning that they can be used to differentiate between at least two of the defined groups)
+- Show predicted flowgrams: If <<multiplexPyrosequencing|pyrosequencing primers>> are defined, the flowgrams are shown which would be generated during multiplex pyrosequencing for each of the defined <<grouping|groups>>. A list of <<grouping|groups>> which are expected to generate no unique pyrogram is provided.
+
+:image pyrograms.png|Predicted pyrograms: The groups VARV and MPXV generate unique pyrograms with the two defined pyrosequencing primers, while the pyrograms for the groups All, VACV and CPXV are identical to each other.
\ No newline at end of file
diff --git a/helpSetMaker/src/6036f840.stml b/helpSetMaker/src/6036f840.stml
new file mode 100644
index 0000000..53c6758
--- /dev/null
+++ b/helpSetMaker/src/6036f840.stml
@@ -0,0 +1,3 @@
+:title Help
+
+This document can be opened from here ;)
\ No newline at end of file
diff --git a/helpSetMaker/src/6bc41f84.stml b/helpSetMaker/src/6bc41f84.stml
new file mode 100644
index 0000000..bec2365
--- /dev/null
+++ b/helpSetMaker/src/6bc41f84.stml
@@ -0,0 +1,5 @@
+:title FASTA (import and export)
+
+The default FASTA format can be both imported and exported. When exporting, two choices are available: The //Blank FASTA file//, which is a normal FASTA file and can be read by almost any sequence editor, has the disadvantage of losing grouping information (since the FASTA format does not provide any way to encode metadata). The other option, //FASTA file//, saves a file in a somewhat extended FASTA format. This file can still be read by most sequence editors, but it contains grouping in [...]
+
+Files saved in the FASTA format lose all annotation information in any case.
\ No newline at end of file
diff --git a/helpSetMaker/src/86d0b0a1.stml b/helpSetMaker/src/86d0b0a1.stml
new file mode 100644
index 0000000..79bb691
--- /dev/null
+++ b/helpSetMaker/src/86d0b0a1.stml
@@ -0,0 +1,7 @@
+:title The sequence pane
+
+:image sequencePane.png|The sequence pane
+
+The sequence pane is where the sequences of the currently loaded alignment are displayed. If <<grouping|groups>> have been defined and group <<analyze|consensus sequences have been calculated>>, the consensus sequence and identity graph for each group is also shown.
+
+At the top, the currently displayed position in the alignment is shown. 
\ No newline at end of file
diff --git a/helpSetMaker/src/87de535b.stml b/helpSetMaker/src/87de535b.stml
new file mode 100644
index 0000000..8330c3a
--- /dev/null
+++ b/helpSetMaker/src/87de535b.stml
@@ -0,0 +1,8 @@
+:title Moving, editing, master sequences
+:label selecting
+
+Sequences can be moved by selecting a name in the names pane and dragging it about. Several sequences can be selected by holding down either the shift or the control key while clicking on the names. The whole selection can then be moved together. Sequences can only be moved within a single <<grouping|group>>. 
+
+When a sequence name is right-cliked on, a context menu appears which allows to set the sequence as the master sequence (it will be displayed at the top of the alignment insead of the consensus sequence and differences to this sesquence will be highlighted instead of differences to the consensus sequence). The sequence can also be deleted or reverse-complemented in place. 
+
+Sequences can also be sorted from the right-click menu. The behavior is identical to that of sorting from the <<analyze|Analyze>> menu.
\ No newline at end of file
diff --git a/helpSetMaker/src/98c149b5.stml b/helpSetMaker/src/98c149b5.stml
new file mode 100644
index 0000000..be87247
--- /dev/null
+++ b/helpSetMaker/src/98c149b5.stml
@@ -0,0 +1,8 @@
+:title View
+:label view
+
+The view menu allows customizing the sequence display.
+
+:image viewMenu.png|The view menu
+
+The color models currently supported are: Monochrome, BioEdit (background), UPGMA (background) and UPGMA. In the background color models, the foreground color is always black.
diff --git a/helpSetMaker/src/9d452f38.stml b/helpSetMaker/src/9d452f38.stml
new file mode 100644
index 0000000..aa84aa7
--- /dev/null
+++ b/helpSetMaker/src/9d452f38.stml
@@ -0,0 +1,5 @@
+:title The names pane
+
+The names pane is where the names of the sequences in the alignment are displayed and where grouping is performed.
+
+:image namesPane.png|The names pane
\ No newline at end of file
diff --git a/helpSetMaker/src/9ee3d3c6.stml b/helpSetMaker/src/9ee3d3c6.stml
new file mode 100644
index 0000000..2926327
--- /dev/null
+++ b/helpSetMaker/src/9ee3d3c6.stml
@@ -0,0 +1,12 @@
+:title Multiplex pyrosequencing
+:label multiplexPyrosequencing
+
+If <<primers|primers>> have been defined, they can be set as pyrosequencing primers by right-clicking on them and selecting the "Is pyrosequencing primer" checkbox. Once pyrosequencing primers have been defined, the "Show predicted flowgrams" entry in the <<analyze|Analyze>> menu can be selected to show the pyrograms which would be generated for each of the groups in a multiplex pyrosequencing assay. 
+
+:image pyrograms.png|Predicted pyrograms for two pyrosequencing primers. The pyrograms for the groups All, VACV and CPXV are expected to be identical, while the groups VARV and MPXV are expected to generate unique pyrograms.
+
+Each group which generates a unique pyrogram is shown separately, while groups which cannot be differentiated using the defined primers because their pyrograms would be identical are shown together. 
+
+While the window showing the predicted pyrograms is visible, the primers in the sequence pane can be resized, moved etc. The changes to the predicted pyrograms are updated in realtime, so that primers positions can easily be optimised.
+
+The flowgram length defines how many pyrosequencing cycles are to be considered in the analysis. The maximum flowgram length is the number of cycles which can be performed using the defined primers before a region would be sequenced which is not fully conserved within each of the groups - at this point, the pyrosequencing would result in several different pyrograms for the same group.
\ No newline at end of file
diff --git a/helpSetMaker/src/aa49edd7.stml b/helpSetMaker/src/aa49edd7.stml
new file mode 100644
index 0000000..227db41
--- /dev/null
+++ b/helpSetMaker/src/aa49edd7.stml
@@ -0,0 +1,3 @@
+:title Navigating the sequences
+
+Sequence navigation is very basic and intuitive: Scrolling is possible either using the scroll bars or through holding the middle mouse button to "grab" the sequence pane and moving the mouse. Zooming can either be performed through the <<view|view menu>> or by holding down the CTRL-key on the keyboard and moving the scroll wheel on the mouse.
\ No newline at end of file
diff --git a/helpSetMaker/src/ae869282.stml b/helpSetMaker/src/ae869282.stml
new file mode 100644
index 0000000..14f3052
--- /dev/null
+++ b/helpSetMaker/src/ae869282.stml
@@ -0,0 +1,3 @@
+:title mPSQed
+
+This Sequence Editor developed at the Robert Koch Institute in Berlin, Germany aims to make the design of PCR and Multiplex Pyrosequencing assays based on nucleotide alignments easier. The following pages describe the main functions of the editor.
\ No newline at end of file
diff --git a/helpSetMaker/src/b139c808.stml b/helpSetMaker/src/b139c808.stml
new file mode 100644
index 0000000..f6af0c8
--- /dev/null
+++ b/helpSetMaker/src/b139c808.stml
@@ -0,0 +1,3 @@
+:title Menus
+
+This section walks through the menus available in the editor.
\ No newline at end of file
diff --git a/helpSetMaker/src/b69463fa.stml b/helpSetMaker/src/b69463fa.stml
new file mode 100644
index 0000000..798ba42
--- /dev/null
+++ b/helpSetMaker/src/b69463fa.stml
@@ -0,0 +1,10 @@
+:title Grouping
+:label grouping
+
+Sequences can be organised in groups. This is useful for finding SNPs which could be used in species-specific assays using the "Find all SNPs" entry in the <<analyze|Analyze>> menu or in the design of <<multiplexPyrosequencing|multiplex pyrosequencing assays>>.
+
+Sequences can be grouped together by <<selecting|selecting>> one or more sequences, right-clicking on the selection and then choosing the "Set as group" option. A group name can then be entered, and the selected sequences will be moved to a new group with that name. The group of a sequence is shown in braces in front of the sequence name and groups can be collapsed or expanded by clicking on the minur or plus sign in front of the first sequence in a group. 
+
+Sequences can be moved from group to group by right-clicking on a sequence and selecting the target group from the "Add sequence to group" entry.
+
+There is no separate option to rename a group. However, empty groups will be deleted, so renaming a group can be done by selecting all sequences from a group, right-clicking, selecting "Set as group" and entering the new group name. All selected sequences will be moved to a new group with the new name, and the old group will be deleted since it will then be empty.
\ No newline at end of file
diff --git a/helpSetMaker/src/c9e02254.stml b/helpSetMaker/src/c9e02254.stml
new file mode 100644
index 0000000..c6f783f
--- /dev/null
+++ b/helpSetMaker/src/c9e02254.stml
@@ -0,0 +1,5 @@
+:title RSF (import and export)
+
+The Rich Sequence Format (RSF) is a format used by the program SeqLab. It is also the default format for the RKI Sequence Editor since it allows the saving of metadata. It is currently the only supported format which allows the saving of all grouping, annotation and primer information.
+
+As a result, it is recommended to save files in the RKI Sequence Editor using the Rich Sequence Format and only to export to one of the other supported format when data is exchanged with colleagues using another editor.
\ No newline at end of file
diff --git a/helpSetMaker/src/e9fd53d0.stml b/helpSetMaker/src/e9fd53d0.stml
new file mode 100644
index 0000000..0b96b95
--- /dev/null
+++ b/helpSetMaker/src/e9fd53d0.stml
@@ -0,0 +1,17 @@
+:title Selecting, editing and copying
+
+Sequences can be selected using the mouse. An existing selection can be resized by grabbing one of its corners with the mouse and dragging. 
+
+:image resizingSelection.png|Resizing an existing selection
+
+Selecting on a <<analyze|group consensus sequence>> will select the specified region of all sequences within the group, selecting on the master consensus sequence will select the specified region of all sequences in the alignment. Once a selection has been made, it can be copied to the system buffer by right-clicking on it and selecting one of the following options:
+- Sequences: Copies the selected parts of the sequences, with each sequence in a separate line
+- Sequences with names: Copies the selected parts of the sequence, including the sequence names, in FASTA format. The sequence names will end with the selection range in braces (e.g.: ">DQ983239 (172 - 246)")
+- Master consensus sequence: Copies the master consensus sequence for the selected range
+- Group consensus sequence: Copies the consensus sequence for the selected group
+
+When right-clicking on a selection, the option "Delete selected" is also available. This deletes the selected bases, shifting the bases following on the right-hand side left to fill the gap.
+
+The right-click menu for a sequence selection also contains two submenus for the adding of primers and annotations, which is described in-depth in the <<primers|next section>>.
+
+Sequences can also be edited: When a single residue is clicked on, a cursor is shown around that residue. This cursor can be moved using the arrow keys on the keyboard. The base under the cursor can be modified through the keyboard (all IUPAC nucleotide codes can be entered). Clicking somewhere else in the sequence pane exits the editing mode.
\ No newline at end of file
diff --git a/helpSetMaker/src/ec633545.stml b/helpSetMaker/src/ec633545.stml
new file mode 100644
index 0000000..8533e5a
--- /dev/null
+++ b/helpSetMaker/src/ec633545.stml
@@ -0,0 +1,3 @@
+:title Geneious (export only)
+
+The Geneious format is supported only for exporting files. It can be read by the bioinformatics workbench [[http://www.geneious.com|Geneious]]. Using this file format preserves annotation and grouping - however, since Geneious has no concept of sequence grouping within a single alignment, grouping information is effectively lost when using this format.
\ No newline at end of file
diff --git a/helpSetMaker/src/f19dc10a.stml b/helpSetMaker/src/f19dc10a.stml
new file mode 100644
index 0000000..e15eac2
--- /dev/null
+++ b/helpSetMaker/src/f19dc10a.stml
@@ -0,0 +1,19 @@
+:title Edit 
+:label edit
+
+The edit menu allows copying sequences and modifying the settings.
+
+:image editMenu.png|The edit menu
+
+When copying sequences, the following options are available:
+
+- Sequences: Copies the selected nucleotides. If several sequences are selected, the nucleotides from each sequence will be copied in a separate line.
+- Sequences with names: Copies the selected sequence parts in FASTA format, with sequence names and selected nucleotides. This can be useful for example for blasting several sequences at once.
+- Master consensus sequence: Copies the master consensus sequence for the selected part of the alignment.
+- Group consensus sequence: Copies the group consensus sequence for the selected part of the alignment.
+
+The settings option allows editing the general settings of the program. Currently, the only configurable section pertains to primers:
+
+:image settings.png|The settings window
+
+The top three options are used when calculating the melting temperature (tm) of primers. If two primers can create an amplification product and their tm differs by too much, a warning can be displayed. The tm difference necessary for this warning to appear and the color of the warning can be set in the last two options. 
diff --git a/helpSetMaker/thumbnails/0e171431_100.jpg b/helpSetMaker/thumbnails/0e171431_100.jpg
new file mode 100644
index 0000000..c7e29ec
Binary files /dev/null and b/helpSetMaker/thumbnails/0e171431_100.jpg differ
diff --git a/helpSetMaker/thumbnails/0e171431_200.jpg b/helpSetMaker/thumbnails/0e171431_200.jpg
new file mode 100644
index 0000000..cd0162b
Binary files /dev/null and b/helpSetMaker/thumbnails/0e171431_200.jpg differ
diff --git a/helpSetMaker/thumbnails/1ea36cbb_100.jpg b/helpSetMaker/thumbnails/1ea36cbb_100.jpg
new file mode 100644
index 0000000..94610a3
Binary files /dev/null and b/helpSetMaker/thumbnails/1ea36cbb_100.jpg differ
diff --git a/helpSetMaker/thumbnails/1ea36cbb_200.jpg b/helpSetMaker/thumbnails/1ea36cbb_200.jpg
new file mode 100644
index 0000000..2a5b32d
Binary files /dev/null and b/helpSetMaker/thumbnails/1ea36cbb_200.jpg differ
diff --git a/helpSetMaker/thumbnails/47bc4e12_100.jpg b/helpSetMaker/thumbnails/47bc4e12_100.jpg
new file mode 100644
index 0000000..52e1e91
Binary files /dev/null and b/helpSetMaker/thumbnails/47bc4e12_100.jpg differ
diff --git a/helpSetMaker/thumbnails/47bc4e12_200.jpg b/helpSetMaker/thumbnails/47bc4e12_200.jpg
new file mode 100644
index 0000000..503783c
Binary files /dev/null and b/helpSetMaker/thumbnails/47bc4e12_200.jpg differ
diff --git a/helpSetMaker/thumbnails/5031b155_100.jpg b/helpSetMaker/thumbnails/5031b155_100.jpg
new file mode 100644
index 0000000..91018c9
Binary files /dev/null and b/helpSetMaker/thumbnails/5031b155_100.jpg differ
diff --git a/helpSetMaker/thumbnails/5031b155_200.jpg b/helpSetMaker/thumbnails/5031b155_200.jpg
new file mode 100644
index 0000000..02e91ac
Binary files /dev/null and b/helpSetMaker/thumbnails/5031b155_200.jpg differ
diff --git a/helpSetMaker/thumbnails/5cf69c5a_100.jpg b/helpSetMaker/thumbnails/5cf69c5a_100.jpg
new file mode 100644
index 0000000..f766c8b
Binary files /dev/null and b/helpSetMaker/thumbnails/5cf69c5a_100.jpg differ
diff --git a/helpSetMaker/thumbnails/70a6cf64_100.jpg b/helpSetMaker/thumbnails/70a6cf64_100.jpg
new file mode 100644
index 0000000..193294d
Binary files /dev/null and b/helpSetMaker/thumbnails/70a6cf64_100.jpg differ
diff --git a/helpSetMaker/thumbnails/70a6cf64_200.jpg b/helpSetMaker/thumbnails/70a6cf64_200.jpg
new file mode 100644
index 0000000..b032862
Binary files /dev/null and b/helpSetMaker/thumbnails/70a6cf64_200.jpg differ
diff --git a/helpSetMaker/thumbnails/8ee1d6f4_100.jpg b/helpSetMaker/thumbnails/8ee1d6f4_100.jpg
new file mode 100644
index 0000000..25416d9
Binary files /dev/null and b/helpSetMaker/thumbnails/8ee1d6f4_100.jpg differ
diff --git a/helpSetMaker/thumbnails/90947dcc_100.jpg b/helpSetMaker/thumbnails/90947dcc_100.jpg
new file mode 100644
index 0000000..d18a8da
Binary files /dev/null and b/helpSetMaker/thumbnails/90947dcc_100.jpg differ
diff --git a/helpSetMaker/thumbnails/90947dcc_200.jpg b/helpSetMaker/thumbnails/90947dcc_200.jpg
new file mode 100644
index 0000000..f9865b7
Binary files /dev/null and b/helpSetMaker/thumbnails/90947dcc_200.jpg differ
diff --git a/helpSetMaker/thumbnails/99550228_100.jpg b/helpSetMaker/thumbnails/99550228_100.jpg
new file mode 100644
index 0000000..8641a6f
Binary files /dev/null and b/helpSetMaker/thumbnails/99550228_100.jpg differ
diff --git a/helpSetMaker/thumbnails/99550228_200.jpg b/helpSetMaker/thumbnails/99550228_200.jpg
new file mode 100644
index 0000000..59abd53
Binary files /dev/null and b/helpSetMaker/thumbnails/99550228_200.jpg differ
diff --git a/helpSetMaker/thumbnails/b3efb285_100.jpg b/helpSetMaker/thumbnails/b3efb285_100.jpg
new file mode 100644
index 0000000..f091d49
Binary files /dev/null and b/helpSetMaker/thumbnails/b3efb285_100.jpg differ
diff --git a/helpSetMaker/thumbnails/b3efb285_200.jpg b/helpSetMaker/thumbnails/b3efb285_200.jpg
new file mode 100644
index 0000000..5c27556
Binary files /dev/null and b/helpSetMaker/thumbnails/b3efb285_200.jpg differ
diff --git a/helpSetMaker/thumbnails/c2400ae0_100.jpg b/helpSetMaker/thumbnails/c2400ae0_100.jpg
new file mode 100644
index 0000000..e11ce82
Binary files /dev/null and b/helpSetMaker/thumbnails/c2400ae0_100.jpg differ
diff --git a/helpSetMaker/thumbnails/d5635043_100.jpg b/helpSetMaker/thumbnails/d5635043_100.jpg
new file mode 100644
index 0000000..ab526f7
Binary files /dev/null and b/helpSetMaker/thumbnails/d5635043_100.jpg differ
diff --git a/helpSetMaker/thumbnails/e716f121_100.jpg b/helpSetMaker/thumbnails/e716f121_100.jpg
new file mode 100644
index 0000000..322c54a
Binary files /dev/null and b/helpSetMaker/thumbnails/e716f121_100.jpg differ
diff --git a/helpSetMaker/thumbnails/e716f121_200.jpg b/helpSetMaker/thumbnails/e716f121_200.jpg
new file mode 100644
index 0000000..a9abacb
Binary files /dev/null and b/helpSetMaker/thumbnails/e716f121_200.jpg differ
diff --git a/helpSetMaker/thumbnails/eab1139f_100.jpg b/helpSetMaker/thumbnails/eab1139f_100.jpg
new file mode 100644
index 0000000..49183ae
Binary files /dev/null and b/helpSetMaker/thumbnails/eab1139f_100.jpg differ
diff --git a/helpSetMaker/thumbnails/eab1139f_200.jpg b/helpSetMaker/thumbnails/eab1139f_200.jpg
new file mode 100644
index 0000000..56e74ff
Binary files /dev/null and b/helpSetMaker/thumbnails/eab1139f_200.jpg differ
diff --git a/launch4j_jre.xml b/launch4j_jre.xml
new file mode 100644
index 0000000..060ec42
--- /dev/null
+++ b/launch4j_jre.xml
@@ -0,0 +1,22 @@
+<launch4jConfig>
+  <dontWrapJar>false</dontWrapJar>
+  <headerType>gui</headerType>
+  <jar>C:\Dokumente und Einstellungen\DabrowskiW\Eigene Dateien\NetBeansProjects\SequenceEditor\dist_jre\SequenceEditor.jar</jar>
+  <outfile>C:\Dokumente und Einstellungen\DabrowskiW\Eigene Dateien\NetBeansProjects\SequenceEditor\dist_jre\RKISequenceEditor.exe</outfile>
+  <errTitle></errTitle>
+  <cmdLine></cmdLine>
+  <chdir></chdir>
+  <priority>normal</priority>
+  <downloadUrl>http://java.com/download</downloadUrl>
+  <supportUrl></supportUrl>
+  <customProcName>false</customProcName>
+  <stayAlive>false</stayAlive>
+  <manifest></manifest>
+  <icon>C:\Dokumente und Einstellungen\DabrowskiW\Eigene Dateien\NetBeansProjects\SequenceEditor\resources\editor.ico</icon>
+  <jre>
+    <path>jre</path>
+    <minVersion></minVersion>
+    <maxVersion></maxVersion>
+    <jdkPreference>preferJre</jdkPreference>
+  </jre>
+</launch4jConfig>
\ No newline at end of file
diff --git a/launch4j_nojre.xml b/launch4j_nojre.xml
new file mode 100644
index 0000000..17508eb
--- /dev/null
+++ b/launch4j_nojre.xml
@@ -0,0 +1,22 @@
+<launch4jConfig>
+  <dontWrapJar>false</dontWrapJar>
+  <headerType>gui</headerType>
+  <jar>C:\Dokumente und Einstellungen\DabrowskiW\Eigene Dateien\NetBeansProjects\SequenceEditor\dist_nojre\SequenceEditor.jar</jar>
+  <outfile>C:\Dokumente und Einstellungen\DabrowskiW\Eigene Dateien\NetBeansProjects\SequenceEditor\dist_nojre\RKISequenceEditor.exe</outfile>
+  <errTitle></errTitle>
+  <cmdLine></cmdLine>
+  <chdir></chdir>
+  <priority>normal</priority>
+  <downloadUrl>http://java.com/download</downloadUrl>
+  <supportUrl></supportUrl>
+  <customProcName>false</customProcName>
+  <stayAlive>false</stayAlive>
+  <manifest></manifest>
+  <icon>C:\Dokumente und Einstellungen\DabrowskiW\Eigene Dateien\NetBeansProjects\SequenceEditor\resources\editor.ico</icon>
+  <jre>
+    <path></path>
+    <minVersion>1.6.0</minVersion>
+    <maxVersion></maxVersion>
+    <jdkPreference>preferJre</jdkPreference>
+  </jre>
+</launch4jConfig>
\ No newline at end of file
diff --git a/manifest.mf b/manifest.mf
new file mode 100644
index 0000000..328e8e5
--- /dev/null
+++ b/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/nbproject/build-impl.xml b/nbproject/build-impl.xml
new file mode 100644
index 0000000..325bd23
--- /dev/null
+++ b/nbproject/build-impl.xml
@@ -0,0 +1,1060 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+  - initialization
+  - compilation
+  - jar
+  - execution
+  - debugging
+  - javadoc
+  - junit compilation
+  - junit execution
+  - junit debugging
+  - applet
+  - cleanup
+
+        -->
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="SequenceEditor-impl">
+    <fail message="Please build using Ant 1.7.1 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.7.1"/>
+            </not>
+        </condition>
+    </fail>
+    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+    <!-- 
+                ======================
+                INITIALIZATION SECTION 
+                ======================
+            -->
+    <target name="-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init" name="-init-private">
+        <property file="nbproject/private/config.properties"/>
+        <property file="nbproject/private/configs/${config}.properties"/>
+        <property file="nbproject/private/private.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private" name="-init-user">
+        <property file="${user.properties.file}"/>
+        <!-- The two properties below are usually overridden -->
+        <!-- by the active platform. Just a fallback. -->
+        <property name="default.javac.source" value="1.4"/>
+        <property name="default.javac.target" value="1.4"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
+        <property file="nbproject/configs/${config}.properties"/>
+        <property file="nbproject/project.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+        <available file="${manifest.file}" property="manifest.available"/>
+        <condition property="splashscreen.available">
+            <and>
+                <not>
+                    <equals arg1="${application.splash}" arg2="" trim="true"/>
+                </not>
+                <available file="${application.splash}"/>
+            </and>
+        </condition>
+        <condition property="main.class.available">
+            <and>
+                <isset property="main.class"/>
+                <not>
+                    <equals arg1="${main.class}" arg2="" trim="true"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class">
+            <and>
+                <isset property="manifest.available"/>
+                <isset property="main.class.available"/>
+            </and>
+        </condition>
+        <condition property="do.archive">
+            <not>
+                <istrue value="${jar.archive.disabled}"/>
+            </not>
+        </condition>
+        <condition property="do.mkdist">
+            <and>
+                <isset property="do.archive"/>
+                <isset property="libs.CopyLibs.classpath"/>
+                <not>
+                    <istrue value="${mkdist.disabled}"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class+mkdist.available">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available">
+            <and>
+                <isset property="manifest.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+main.class.available">
+            <and>
+                <isset property="main.class.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+splashscreen.available">
+            <and>
+                <isset property="splashscreen.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="manifest.available-mkdist.available">
+            <or>
+                <istrue value="${manifest.available}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="manifest.available+main.class-mkdist.available">
+            <or>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="have.tests">
+            <or>
+                <available file="${test.src.dir}"/>
+            </or>
+        </condition>
+        <condition property="have.sources">
+            <or>
+                <available file="${src.hs.dir}"/>
+                <available file="${src.dir}"/>
+                <available file="${src.resources.dir}"/>
+            </or>
+        </condition>
+        <condition property="netbeans.home+have.tests">
+            <and>
+                <isset property="netbeans.home"/>
+                <isset property="have.tests"/>
+            </and>
+        </condition>
+        <condition property="no.javadoc.preview">
+            <and>
+                <isset property="javadoc.preview"/>
+                <isfalse value="${javadoc.preview}"/>
+            </and>
+        </condition>
+        <property name="run.jvmargs" value=""/>
+        <property name="javac.compilerargs" value=""/>
+        <property name="work.dir" value="${basedir}"/>
+        <condition property="no.deps">
+            <and>
+                <istrue value="${no.dependencies}"/>
+            </and>
+        </condition>
+        <property name="javac.debug" value="true"/>
+        <property name="javadoc.preview" value="true"/>
+        <property name="application.args" value=""/>
+        <property name="source.encoding" value="${file.encoding}"/>
+        <property name="runtime.encoding" value="${source.encoding}"/>
+        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+            <and>
+                <isset property="javadoc.encoding"/>
+                <not>
+                    <equals arg1="${javadoc.encoding}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <property name="javadoc.encoding.used" value="${source.encoding}"/>
+        <property name="includes" value="**"/>
+        <property name="excludes" value=""/>
+        <property name="do.depend" value="false"/>
+        <condition property="do.depend.true">
+            <istrue value="${do.depend}"/>
+        </condition>
+        <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+        <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+            <length length="0" string="${endorsed.classpath}" when="greater"/>
+        </condition>
+        <condition else="false" property="jdkBug6558476">
+            <and>
+                <matches pattern="1\.[56]" string="${java.specification.version}"/>
+                <not>
+                    <os family="unix"/>
+                </not>
+            </and>
+        </condition>
+        <property name="javac.fork" value="${jdkBug6558476}"/>
+        <property name="jar.index" value="false"/>
+        <property name="jar.index.metainf" value="${jar.index}"/>
+        <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
+    </target>
+    <target name="-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+        <fail unless="src.hs.dir">Must set src.hs.dir</fail>
+        <fail unless="src.dir">Must set src.dir</fail>
+        <fail unless="src.resources.dir">Must set src.resources.dir</fail>
+        <fail unless="test.src.dir">Must set test.src.dir</fail>
+        <fail unless="build.dir">Must set build.dir</fail>
+        <fail unless="dist.dir">Must set dist.dir</fail>
+        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+        <fail unless="dist.jar">Must set dist.jar</fail>
+    </target>
+    <target name="-init-macrodef-property">
+        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${@{value}}"/>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.hs.dir}:${src.dir}:${src.resources.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <mkdir dir="@{apgeneratedsrcdir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <compilerarg value="-processorpath"/>
+                    <compilerarg path="@{processorpath}:${empty.dir}"/>
+                    <compilerarg line="${ap.processors.internal}"/>
+                    <compilerarg line="${annotation.processing.processor.options}"/>
+                    <compilerarg value="-s"/>
+                    <compilerarg path="@{apgeneratedsrcdir}"/>
+                    <compilerarg line="${ap.proc.none.internal}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.hs.dir}:${src.dir}:${src.resources.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
+        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.hs.dir}:${src.dir}:${src.resources.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <sequential>
+                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </depend>
+            </sequential>
+        </macrodef>
+        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <sequential>
+                <fail unless="javac.includes">Must set javac.includes</fail>
+                <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
+                    <path>
+                        <filelist dir="@{destdir}" files="${javac.includes}"/>
+                    </path>
+                    <globmapper from="*.java" to="*.class"/>
+                </pathconvert>
+                <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
+                <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
+                <delete>
+                    <files includesfile="${javac.includesfile.binary}"/>
+                </delete>
+                <delete>
+                    <fileset file="${javac.includesfile.binary}"/>
+                </delete>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-junit">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <classpath>
+                        <path path="${run.test.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" name="profile-init"/>
+    <target name="-profile-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-profile-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target name="-profile-init-macrodef-profile">
+        <macrodef name="resolve">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${env.@{value}}"/>
+            </sequential>
+        </macrodef>
+        <macrodef name="profile">
+            <attribute default="${main.class}" name="classname"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property environment="env"/>
+                <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
+                <java classname="@{classname}" dir="${profiler.info.dir}" fork="true" jvm="${profiler.info.jvm}">
+                    <jvmarg value="${profiler.info.jvmargs.agent}"/>
+                    <jvmarg line="${profiler.info.jvmargs}"/>
+                    <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+                    <arg line="${application.args}"/>
+                    <classpath>
+                        <path path="${run.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" name="-profile-init-check">
+        <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
+        <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="name"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <attribute default="" name="stopclassname"/>
+            <sequential>
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </nbjpdastart>
+            </sequential>
+        </macrodef>
+        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${build.classes.dir}" name="dir"/>
+            <sequential>
+                <nbjpdareload>
+                    <fileset dir="@{dir}" includes="${fix.classes}">
+                        <include name="${fix.includes}*.class"/>
+                    </fileset>
+                </nbjpdareload>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-debug-args">
+        <property name="version-output" value="java version "${ant.java.version}"/>
+        <condition property="have-jdk-older-than-1.4">
+            <or>
+                <contains string="${version-output}" substring="java version "1.0"/>
+                <contains string="${version-output}" substring="java version "1.1"/>
+                <contains string="${version-output}" substring="java version "1.2"/>
+                <contains string="${version-output}" substring="java version "1.3"/>
+            </or>
+        </condition>
+        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+            <istrue value="${have-jdk-older-than-1.4}"/>
+        </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-debug">
+        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-java">
+        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${run.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-copylibs">
+        <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${manifest.file}" name="manifest"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+                <pathconvert property="run.classpath.without.build.classes.dir">
+                    <path path="${run.classpath}"/>
+                    <map from="${build.classes.dir.resolved}" to=""/>
+                </pathconvert>
+                <pathconvert pathsep=" " property="jar.classpath">
+                    <path path="${run.classpath.without.build.classes.dir}"/>
+                    <chainedmapper>
+                        <flattenmapper/>
+                        <globmapper from="*" to="lib/*"/>
+                    </chainedmapper>
+                </pathconvert>
+                <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+                <copylibs compress="${jar.compress}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+                    <fileset dir="${build.classes.dir}"/>
+                    <manifest>
+                        <attribute name="Class-Path" value="${jar.classpath}"/>
+                        <customize/>
+                    </manifest>
+                </copylibs>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-presetdef-jar">
+        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
+                <j2seproject1:fileset dir="${build.classes.dir}"/>
+            </jar>
+        </presetdef>
+    </target>
+    <target name="-init-ap-cmdline-properties">
+        <property name="annotation.processing.enabled" value="true"/>
+        <property name="annotation.processing.processors.list" value=""/>
+        <property name="annotation.processing.processor.options" value=""/>
+        <property name="annotation.processing.run.all.processors" value="true"/>
+        <property name="javac.processorpath" value="${javac.classpath}"/>
+        <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+        <condition property="ap.supported.internal" value="true">
+            <not>
+                <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
+        <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+            <isfalse value="${annotation.processing.run.all.processors}"/>
+        </condition>
+        <condition else="" property="ap.proc.none.internal" value="-proc:none">
+            <isfalse value="${annotation.processing.enabled}"/>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+        <property name="ap.cmd.line.internal" value=""/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+    <!--
+                ===================
+                COMPILATION SECTION
+                ===================
+            -->
+    <target name="-deps-jar-init" unless="built-jar.properties">
+        <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+        <delete file="${built-jar.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+        <echo level="warn" message="Cycle detected: SequenceEditor was already built"/>
+    </target>
+    <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-jar.properties}" verbose="false"/>
+        <property file="${built-jar.properties}" prefix="already.built.jar."/>
+        <antcall target="-warn-already-built-jar"/>
+        <propertyfile file="${built-jar.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+    <target depends="init" name="-check-automatic-build">
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+    </target>
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+        <antcall target="clean"/>
+    </target>
+    <target depends="init,deps-jar" name="-pre-pre-compile">
+        <mkdir dir="${build.classes.dir}"/>
+    </target>
+    <target name="-pre-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-depend">
+        <pathconvert property="build.generated.subdirs">
+            <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="*"/>
+            </dirset>
+        </pathconvert>
+        <j2seproject3:depend srcdir="${src.hs.dir}:${src.dir}:${src.resources.dir}:${build.generated.subdirs}"/>
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
+        <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.classes.dir}">
+            <fileset dir="${src.hs.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+            <fileset dir="${src.resources.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target if="has.persistence.xml" name="-copy-persistence-xml">
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy todir="${build.classes.dir}/META-INF">
+            <fileset dir="${meta.inf.dir}" includes="persistence.xml"/>
+        </copy>
+    </target>
+    <target name="-post-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+    <target name="-pre-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile/>
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.hs.dir}:${src.dir}:${src.resources.dir}"/>
+    </target>
+    <target name="-post-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+    <!--
+                ====================
+                JAR BUILDING SECTION
+                ====================
+            -->
+    <target depends="init" name="-pre-pre-jar">
+        <dirname file="${dist.jar}" property="dist.jar.dir"/>
+        <mkdir dir="${dist.jar.dir}"/>
+    </target>
+    <target name="-pre-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive" name="-do-jar-without-manifest" unless="manifest.available-mkdist.available">
+        <j2seproject1:jar/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class-mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}"/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}">
+            <j2seproject1:manifest>
+                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
+            </j2seproject1:manifest>
+        </j2seproject1:jar>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <pathconvert property="run.classpath.with.dist.jar">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+        </pathconvert>
+        <echo level="info">java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
+    </target>
+    <target depends="init" if="do.archive" name="-do-jar-with-libraries-create-manifest" unless="manifest.available">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <touch file="${tmp.manifest.file}" verbose="false"/>
+    </target>
+    <target depends="init" if="do.archive+manifest.available" name="-do-jar-with-libraries-copy-manifest">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <copy file="${manifest.file}" tofile="${tmp.manifest.file}"/>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+main.class.available" name="-do-jar-with-libraries-set-main">
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="Main-Class" value="${main.class}"/>
+        </manifest>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-with-libraries-set-splashscreen">
+        <basename file="${application.splash}" property="splashscreen.basename"/>
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+        </manifest>
+    </target>
+    <target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen" if="do.mkdist" name="-do-jar-with-libraries-pack">
+        <j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo level="info">java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target depends="-do-jar-with-libraries-pack" if="do.archive" name="-do-jar-with-libraries-delete-manifest">
+        <delete>
+            <fileset file="${tmp.manifest.file}"/>
+        </delete>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen,-do-jar-with-libraries-pack,-do-jar-with-libraries-delete-manifest" name="-do-jar-with-libraries"/>
+    <target name="-post-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
+    <!--
+                =================
+                EXECUTION SECTION
+                =================
+            -->
+    <target depends="init,compile" description="Run a main class." name="run">
+        <j2seproject1:java>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <target name="-do-not-recompile">
+        <property name="javac.includes.binary" value=""/>
+    </target>
+    <target depends="init,compile-single" name="run-single">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}"/>
+    </target>
+    <target depends="init,compile-test-single" name="run-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
+    </target>
+    <!--
+                =================
+                DEBUGGING SECTION
+                =================
+            -->
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
+        <j2seproject1:nbjpdastart name="${debug.class}"/>
+    </target>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
+    </target>
+    <target depends="init,compile" name="-debug-start-debuggee">
+        <j2seproject3:debug>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
+        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
+    </target>
+    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}"/>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+    <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+    <target depends="init" name="-pre-debug-fix">
+        <fail unless="fix.includes">Must set fix.includes</fail>
+        <property name="javac.includes" value="${fix.includes}.java"/>
+    </target>
+    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+        <j2seproject1:nbjpdareload/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+    <!--
+                =================
+                PROFILING SECTION
+                =================
+            -->
+    <target depends="profile-init,compile" description="Profile a project in the IDE." if="netbeans.home" name="profile">
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile/>
+    </target>
+    <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="netbeans.home" name="profile-single">
+        <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="${profile.class}"/>
+    </target>
+    <!--
+                =========================
+                APPLET PROFILING  SECTION
+                =========================
+            -->
+    <target depends="profile-init,compile-single" if="netbeans.home" name="profile-applet">
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </profile>
+    </target>
+    <!--
+                =========================
+                TESTS PROFILING  SECTION
+                =========================
+            -->
+    <target depends="profile-init,compile-test-single" if="netbeans.home" name="profile-test-single">
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
+            <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+            <jvmarg value="${profiler.info.jvmargs.agent}"/>
+            <jvmarg line="${profiler.info.jvmargs}"/>
+            <test name="${profile.class}"/>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+            <syspropertyset>
+                <propertyref prefix="test-sys-prop."/>
+                <mapper from="test-sys-prop.*" to="*" type="glob"/>
+            </syspropertyset>
+            <formatter type="brief" usefile="false"/>
+            <formatter type="xml"/>
+        </junit>
+    </target>
+    <!--
+                ===============
+                JAVADOC SECTION
+                ===============
+            -->
+    <target depends="init" if="have.sources" name="-javadoc-build">
+        <mkdir dir="${dist.javadoc.dir}"/>
+        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+            <classpath>
+                <path path="${javac.classpath}"/>
+            </classpath>
+            <fileset dir="${src.hs.dir}" excludes="*.java,${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${src.dir}" excludes="*.java,${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${src.resources.dir}" excludes="*.java,${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/*.java"/>
+                <exclude name="*.java"/>
+            </fileset>
+        </javadoc>
+        <copy todir="${dist.javadoc.dir}">
+            <fileset dir="${src.hs.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
+            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
+            <fileset dir="${src.resources.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/doc-files/**"/>
+            </fileset>
+        </copy>
+    </target>
+    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+    </target>
+    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+    <!--
+                =========================
+                JUNIT COMPILATION SECTION
+                =========================
+            -->
+    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+        <mkdir dir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-pre-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-test-depend">
+        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+    <target name="-pre-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+    <!--
+                =======================
+                JUNIT EXECUTION SECTION
+                =======================
+            -->
+    <target depends="init" if="have.tests" name="-pre-test-run">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
+        <j2seproject3:junit testincludes="**/*Test.java"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init" if="have.tests" name="test-report"/>
+    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+    <target depends="init" if="have.tests" name="-pre-test-run-single">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <j2seproject3:junit excludes="" includes="${test.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+    <!--
+                =======================
+                JUNIT DEBUGGING SECTION
+                =======================
+            -->
+    <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
+        <delete file="${test.report.file}"/>
+        <mkdir dir="${build.test.results.dir}"/>
+        <j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
+            <customize>
+                <syspropertyset>
+                    <propertyref prefix="test-sys-prop."/>
+                    <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                </syspropertyset>
+                <arg value="${test.class}"/>
+                <arg value="showoutput=true"/>
+                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
+                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+    <!--
+                =========================
+                APPLET EXECUTION SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" name="run-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject1:java classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <!--
+                =========================
+                APPLET DEBUGGING  SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject3:debug classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
+    <!--
+                ===============
+                CLEANUP SECTION
+                ===============
+            -->
+    <target name="-deps-clean-init" unless="built-clean.properties">
+        <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+        <delete file="${built-clean.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+        <echo level="warn" message="Cycle detected: SequenceEditor was already built"/>
+    </target>
+    <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-clean.properties}" verbose="false"/>
+        <property file="${built-clean.properties}" prefix="already.built.clean."/>
+        <antcall target="-warn-already-built-clean"/>
+        <propertyfile file="${built-clean.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init" name="-do-clean">
+        <delete dir="${build.dir}"/>
+        <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+    </target>
+    <target name="-post-clean">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+    <target name="-check-call-dep">
+        <property file="${call.built.properties}" prefix="already.built."/>
+        <condition property="should.call.dep">
+            <not>
+                <isset property="already.built.${call.subproject}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+        <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+            <propertyset>
+                <propertyref prefix="transfer."/>
+                <mapper from="transfer.*" to="*" type="glob"/>
+            </propertyset>
+        </ant>
+    </target>
+</project>
diff --git a/nbproject/build-impl.xml~ b/nbproject/build-impl.xml~
new file mode 100644
index 0000000..a72fce9
--- /dev/null
+++ b/nbproject/build-impl.xml~
@@ -0,0 +1,709 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+  - initialization
+  - compilation
+  - jar
+  - execution
+  - debugging
+  - javadoc
+  - junit compilation
+  - junit execution
+  - junit debugging
+  - applet
+  - cleanup
+
+        -->
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="SequenceEditor-impl">
+    <fail message="Please build using Ant 1.7.1 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.7.1"/>
+            </not>
+        </condition>
+    </fail>
+    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+    <!-- 
+                ======================
+                INITIALIZATION SECTION 
+                ======================
+            -->
+    <target name="-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init" name="-init-private">
+        <property file="nbproject/private/config.properties"/>
+        <property file="nbproject/private/configs/${config}.properties"/>
+        <property file="nbproject/private/private.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private" name="-init-user">
+        <property file="${user.properties.file}"/>
+        <!-- The two properties below are usually overridden -->
+        <!-- by the active platform. Just a fallback. -->
+        <property name="default.javac.source" value="1.4"/>
+        <property name="default.javac.target" value="1.4"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
+        <property file="nbproject/configs/${config}.properties"/>
+        <property file="nbproject/project.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+        <available file="${manifest.file}" property="manifest.available"/>
+        <condition property="manifest.available+main.class">
+            <and>
+                <isset property="manifest.available"/>
+                <isset property="main.class"/>
+                <not>
+                    <equals arg1="${main.class}" arg2="" trim="true"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class+mkdist.available">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="libs.CopyLibs.classpath"/>
+            </and>
+        </condition>
+        <condition property="have.tests">
+            <or>
+                <available file="${test.src.dir}"/>
+            </or>
+        </condition>
+        <condition property="have.sources">
+            <or>
+                <available file="${src.dir}"/>
+                <available file="${src.resources.dir}"/>
+            </or>
+        </condition>
+        <condition property="netbeans.home+have.tests">
+            <and>
+                <isset property="netbeans.home"/>
+                <isset property="have.tests"/>
+            </and>
+        </condition>
+        <condition property="no.javadoc.preview">
+            <and>
+                <isset property="javadoc.preview"/>
+                <isfalse value="${javadoc.preview}"/>
+            </and>
+        </condition>
+        <property name="run.jvmargs" value=""/>
+        <property name="javac.compilerargs" value=""/>
+        <property name="work.dir" value="${basedir}"/>
+        <condition property="no.deps">
+            <and>
+                <istrue value="${no.dependencies}"/>
+            </and>
+        </condition>
+        <property name="javac.debug" value="true"/>
+        <property name="javadoc.preview" value="true"/>
+        <property name="application.args" value=""/>
+        <property name="source.encoding" value="${file.encoding}"/>
+        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+            <and>
+                <isset property="javadoc.encoding"/>
+                <not>
+                    <equals arg1="${javadoc.encoding}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <property name="javadoc.encoding.used" value="${source.encoding}"/>
+        <property name="includes" value="**"/>
+        <property name="excludes" value=""/>
+        <property name="do.depend" value="false"/>
+        <condition property="do.depend.true">
+            <istrue value="${do.depend}"/>
+        </condition>
+        <condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
+            <and>
+                <isset property="jaxws.endorsed.dir"/>
+                <available file="nbproject/jaxws-build.xml"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+        <fail unless="src.dir">Must set src.dir</fail>
+        <fail unless="src.resources.dir">Must set src.resources.dir</fail>
+        <fail unless="test.src.dir">Must set test.src.dir</fail>
+        <fail unless="build.dir">Must set build.dir</fail>
+        <fail unless="dist.dir">Must set dist.dir</fail>
+        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+        <fail unless="dist.jar">Must set dist.jar</fail>
+    </target>
+    <target name="-init-macrodef-property">
+        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${@{value}}"/>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-javac">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}:${src.resources.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}:${src.resources.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <sequential>
+                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </depend>
+            </sequential>
+        </macrodef>
+        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <sequential>
+                <fail unless="javac.includes">Must set javac.includes</fail>
+                <pathconvert pathsep="," property="javac.includes.binary">
+                    <path>
+                        <filelist dir="@{destdir}" files="${javac.includes}"/>
+                    </path>
+                    <globmapper from="*.java" to="*.class"/>
+                </pathconvert>
+                <delete>
+                    <files includes="${javac.includes.binary}"/>
+                </delete>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-junit">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <sequential>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <classpath>
+                        <path path="${run.test.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="name"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <attribute default="" name="stopclassname"/>
+            <sequential>
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </nbjpdastart>
+            </sequential>
+        </macrodef>
+        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${build.classes.dir}" name="dir"/>
+            <sequential>
+                <nbjpdareload>
+                    <fileset dir="@{dir}" includes="${fix.classes}">
+                        <include name="${fix.includes}*.class"/>
+                    </fileset>
+                </nbjpdareload>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-debug-args">
+        <property name="version-output" value="java version "${ant.java.version}"/>
+        <condition property="have-jdk-older-than-1.4">
+            <or>
+                <contains string="${version-output}" substring="java version "1.0"/>
+                <contains string="${version-output}" substring="java version "1.1"/>
+                <contains string="${version-output}" substring="java version "1.2"/>
+                <contains string="${version-output}" substring="java version "1.3"/>
+            </or>
+        </condition>
+        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+            <istrue value="${have-jdk-older-than-1.4}"/>
+        </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-debug">
+        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <jvmarg value="-Dfile.encoding=${source.encoding}"/>
+                    <redirector errorencoding="${source.encoding}" inputencoding="${source.encoding}" outputencoding="${source.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-java">
+        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${run.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg value="-Dfile.encoding=${source.encoding}"/>
+                    <redirector errorencoding="${source.encoding}" inputencoding="${source.encoding}" outputencoding="${source.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-presetdef-jar">
+        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <jar compress="${jar.compress}" jarfile="${dist.jar}">
+                <j2seproject1:fileset dir="${build.classes.dir}"/>
+            </jar>
+        </presetdef>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
+    <!--
+                ===================
+                COMPILATION SECTION
+                ===================
+            -->
+    <target depends="init" name="deps-jar" unless="no.deps"/>
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+    <target depends="init" name="-check-automatic-build">
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+    </target>
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+        <antcall target="clean"/>
+    </target>
+    <target depends="init,deps-jar" name="-pre-pre-compile">
+        <mkdir dir="${build.classes.dir}"/>
+    </target>
+    <target name="-pre-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-depend">
+        <pathconvert property="build.generated.subdirs">
+            <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="*"/>
+            </dirset>
+        </pathconvert>
+        <j2seproject3:depend srcdir="${src.dir}:${src.resources.dir}:${build.generated.subdirs}"/>
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
+        <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.classes.dir}">
+            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+            <fileset dir="${src.resources.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+    <target name="-pre-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile/>
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}:${src.resources.dir}"/>
+    </target>
+    <target name="-post-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+    <!--
+                ====================
+                JAR BUILDING SECTION
+                ====================
+            -->
+    <target depends="init" name="-pre-pre-jar">
+        <dirname file="${dist.jar}" property="dist.jar.dir"/>
+        <mkdir dir="${dist.jar.dir}"/>
+    </target>
+    <target name="-pre-jar">
+        <propertyfile file="${src.dir}\version.properties">
+            <entry  key="BUILD" value="1" type="int" operation="+"/>
+        </propertyfile>
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
+        <j2seproject1:jar/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
+        <j2seproject1:jar manifest="${manifest.file}"/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}">
+            <j2seproject1:manifest>
+                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
+            </j2seproject1:manifest>
+        </j2seproject1:jar>
+        <echo>To run this application from the command line without Ant, try:</echo>
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <pathconvert property="run.classpath.with.dist.jar">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+        </pathconvert>
+        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <pathconvert property="run.classpath.without.build.classes.dir">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to=""/>
+        </pathconvert>
+        <pathconvert pathsep=" " property="jar.classpath">
+            <path path="${run.classpath.without.build.classes.dir}"/>
+            <chainedmapper>
+                <flattenmapper/>
+                <globmapper from="*" to="lib/*"/>
+            </chainedmapper>
+        </pathconvert>
+        <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+        <copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+            <fileset dir="${build.classes.dir}"/>
+            <manifest>
+                <attribute name="Main-Class" value="${main.class}"/>
+                <attribute name="Class-Path" value="${jar.classpath}"/>
+            </manifest>
+        </copylibs>
+        <echo>To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo>java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="libs.CopyLibs.classpath" name="-do-jar-with-libraries-without-manifest" unless="manifest.available+main.class">
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <pathconvert property="run.classpath.without.build.classes.dir">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to=""/>
+        </pathconvert>
+        <pathconvert pathsep=" " property="jar.classpath">
+            <path path="${run.classpath.without.build.classes.dir}"/>
+            <chainedmapper>
+                <flattenmapper/>
+                <globmapper from="*" to="lib/*"/>
+            </chainedmapper>
+        </pathconvert>
+        <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+        <copylibs compress="${jar.compress}" jarfile="${dist.jar}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+            <fileset dir="${build.classes.dir}"/>
+        </copylibs>
+    </target>
+    <target name="-post-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-do-jar-with-libraries-without-manifest,-post-jar" description="Build JAR." name="jar"/>
+    <!--
+                =================
+                EXECUTION SECTION
+                =================
+            -->
+    <target depends="init,compile" description="Run a main class." name="run">
+        <j2seproject1:java>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <target name="-do-not-recompile">
+        <property name="javac.includes.binary" value=""/>
+    </target>
+    <target depends="init,-do-not-recompile,compile-single" name="run-single">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}"/>
+    </target>
+    <target depends="init,-do-not-recompile,compile-test-single" name="run-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
+    </target>
+    <!--
+                =================
+                DEBUGGING SECTION
+                =================
+            -->
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
+        <j2seproject1:nbjpdastart name="${debug.class}"/>
+    </target>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
+    </target>
+    <target depends="init,compile" name="-debug-start-debuggee">
+        <j2seproject3:debug>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
+        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
+    </target>
+    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}"/>
+    </target>
+    <target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+    <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
+    </target>
+    <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+    <target depends="init" name="-pre-debug-fix">
+        <fail unless="fix.includes">Must set fix.includes</fail>
+        <property name="javac.includes" value="${fix.includes}.java"/>
+    </target>
+    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+        <j2seproject1:nbjpdareload/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+    <!--
+                ===============
+                JAVADOC SECTION
+                ===============
+            -->
+    <target depends="init" name="-javadoc-build">
+        <mkdir dir="${dist.javadoc.dir}"/>
+        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+            <classpath>
+                <path path="${javac.classpath}"/>
+            </classpath>
+            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${src.resources.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/*.java"/>
+            </fileset>
+        </javadoc>
+    </target>
+    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+    </target>
+    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+    <!--
+                =========================
+                JUNIT COMPILATION SECTION
+                =========================
+            -->
+    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+        <mkdir dir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-pre-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-test-depend">
+        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+    <target name="-pre-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
+        <j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+    <!--
+                =======================
+                JUNIT EXECUTION SECTION
+                =======================
+            -->
+    <target depends="init" if="have.tests" name="-pre-test-run">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
+        <j2seproject3:junit testincludes="**/*Test.java"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init" if="have.tests" name="test-report"/>
+    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+    <target depends="init" if="have.tests" name="-pre-test-run-single">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <j2seproject3:junit excludes="" includes="${test.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+    <!--
+                =======================
+                JUNIT DEBUGGING SECTION
+                =======================
+            -->
+    <target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
+        <delete file="${test.report.file}"/>
+        <mkdir dir="${build.test.results.dir}"/>
+        <j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
+            <customize>
+                <syspropertyset>
+                    <propertyref prefix="test-sys-prop."/>
+                    <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                </syspropertyset>
+                <arg value="${test.class}"/>
+                <arg value="showoutput=true"/>
+                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
+                <arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
+    </target>
+    <target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+    <!--
+                =========================
+                APPLET EXECUTION SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" name="run-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject1:java classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <!--
+                =========================
+                APPLET DEBUGGING  SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject3:debug classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
+    <!--
+                ===============
+                CLEANUP SECTION
+                ===============
+            -->
+    <target depends="init" name="deps-clean" unless="no.deps"/>
+    <target depends="init" name="-do-clean">
+        <delete dir="${build.dir}"/>
+        <delete dir="${dist.dir}"/>
+    </target>
+    <target name="-post-clean">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+</project>
diff --git a/nbproject/configs/JDK_1.5.properties b/nbproject/configs/JDK_1.5.properties
new file mode 100644
index 0000000..e69de29
diff --git a/nbproject/genfiles.properties b/nbproject/genfiles.properties
new file mode 100644
index 0000000..bab4b39
--- /dev/null
+++ b/nbproject/genfiles.properties
@@ -0,0 +1,11 @@
+build.xml.data.CRC32=f055a0ce
+build.xml.script.CRC32=bc06ad9c
+build.xml.stylesheet.CRC32=28e38971 at 1.41.0.45
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=f055a0ce
+nbproject/build-impl.xml.script.CRC32=2d6f9d95
+nbproject/build-impl.xml.stylesheet.CRC32=0ae3a408 at 1.44.1.45
+nbproject/profiler-build-impl.xml.data.CRC32=661ebeae
+nbproject/profiler-build-impl.xml.script.CRC32=abda56ed
+nbproject/profiler-build-impl.xml.stylesheet.CRC32=42cb6bcf
diff --git a/nbproject/private/config.properties b/nbproject/private/config.properties
new file mode 100644
index 0000000..e69de29
diff --git a/nbproject/private/private.properties b/nbproject/private/private.properties
new file mode 100644
index 0000000..50ea637
--- /dev/null
+++ b/nbproject/private/private.properties
@@ -0,0 +1,7 @@
+compile.on.save=false
+do.depend=false
+do.jar=true
+javac.debug=true
+javadoc.preview=true
+jaxbwiz.endorsed.dirs=/usr/local/netbeans-6.8/ide12/modules/ext/jaxb/api
+user.properties.file=/home/dabrowskiw/.netbeans/7.0/build.properties
diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml
new file mode 100644
index 0000000..c1f155a
--- /dev/null
+++ b/nbproject/private/private.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
+    <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/>
+</project-private>
diff --git a/nbproject/private/profiler/attach.xml b/nbproject/private/profiler/attach.xml
new file mode 100644
index 0000000..e3f9af5
--- /dev/null
+++ b/nbproject/private/profiler/attach.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+<comment/>
+<entry key="profiler.attach.remote">false</entry>
+<entry key="profiler.attach.server.type">Java Applet</entry>
+<entry key="profiler.attach.host.os">Linux</entry>
+<entry key="profiler.attach.dynamic.jdk16">false</entry>
+<entry key="profiler.attach.direct">true</entry>
+<entry key="profiler.attach.target.type">Applet</entry>
+<entry key="profiler.attach.host"/>
+</properties>
diff --git a/nbproject/private/profiler/configurations.xml b/nbproject/private/profiler/configurations.xml
new file mode 100644
index 0000000..2b984cb
--- /dev/null
+++ b/nbproject/private/profiler/configurations.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
+<properties>
+<entry key="2_profiler.settings.code.region.cpu.res.buf.size">1000</entry>
+<entry key="2_profiler.settings.sort.results.by.thread.cpu.time">false</entry>
+<entry key="0_profiler.settings.instrumentation.filter.selectedprofiler.filter.type">profiler.simple.filter</entry>
+<entry key="0_profiler.settings.instrument.empty.methods">false</entry>
+<entry key="0_profiler.settings.instrumentation.filter.selectedprofiler.simple.filter.name"/>
+<entry key="1_profiler.settings.profiling.type">16</entry>
+<entry key="0_profiler.settings.cpu.exclude.wait.time">true</entry>
+<entry key="0_profiler.settings.override.working.dir"/>
+<entry key="1_profiler.settings.thread.cpu.timer.on">false</entry>
+<entry key="1_profiler.settings.instrumentation.root.methods.size">1</entry>
+<entry key="2_profiler.settings.override">false</entry>
+<entry key="1_profiler.settings.threads.sampling.enabled">true</entry>
+<entry key="profiler.settings.lastselected">0</entry>
+<entry key="2_profiler.settings.instrument.spawned.threads">false</entry>
+<entry key="0_profiler.settings.threads.monitoring.enabled">false</entry>
+<entry key="0_profiler.settings.istrument.getter.setter.methods">false</entry>
+<entry key="2_profiler.settings.instrumentation.filter.selectedprofiler.filter.type">profiler.simple.filter</entry>
+<entry key="2_profiler.settings.n.profiled.threads.limit">32</entry>
+<entry key="1_profiler.settings.sort.results.by.thread.cpu.time">false</entry>
+<entry key="2_profiler.settings.instr.scheme">1</entry>
+<entry key="1_profiler.settings.instrument.method.invoke">true</entry>
+<entry key="1_profiler.settings.instr.scheme">1</entry>
+<entry key="2_profiler.settings.sampling.interval">10</entry>
+<entry key="0_profiler.settings.instr.scheme">1</entry>
+<entry key="1_profiler.settings.run.gc.on.get.results.in.memory.profiling">true</entry>
+<entry key="2_profiler.settings.settings.name">Analyze Memory</entry>
+<entry key="0_profiler.settings.sort.results.by.thread.cpu.time">false</entry>
+<entry key="0_profiler.settings.profiling.type">1</entry>
+<entry key="1_profiler.settings.cpu.exclude.wait.time">true</entry>
+<entry key="2_profiler.settings.obj.alloc.stack.sampling.interval">10</entry>
+<entry key="1_profiler.settings.obj.alloc.stack.sampling.depth">0</entry>
+<entry key="1_profiler.settings.cpu.quick.filterprofiler.filter.type">profiler.simple.filter</entry>
+<entry key="1_profiler.settings.instrumentation.marker.methods.size">0</entry>
+<entry key="2_profiler.settings.thread.cpu.timer.on">false</entry>
+<entry key="0_profiler.settigns.ispreset">true</entry>
+<entry key="0_profiler.settings.instrumentation.filter.selectedprofiler.simple.filter.value"/>
+<entry key="2_profiler.settings.override.working.dir"/>
+<entry key="0_profiler.settings.cpu.quick.filterprofiler.simple.filter.type">1</entry>
+<entry key="0_profiler.settings.threads.sampling.enabled">true</entry>
+<entry key="2_profiler.settings.cpu.quick.filterprofiler.simple.filter.value"/>
+<entry key="2_profiler.settings.override.jvm.args"/>
+<entry key="0_profiler.settings.profile.underlying.framework">false</entry>
+<entry key="2_profiler.settings.profile.underlying.framework">false</entry>
+<entry key="2_profiler.settings.cpu.exclude.wait.time">true</entry>
+<entry key="2_profiler.settings.threads.monitoring.enabled">false</entry>
+<entry key="1_profiler.settings.instrument.spawned.threads">false</entry>
+<entry key="1_profiler.settings.n.profiled.threads.limit">32</entry>
+<entry key="0_profiler.settings.cpu.quick.filterprofiler.simple.filter.name">Quick filter...</entry>
+<entry key="2_profiler.settings.instrumentation.root.methods.size">0</entry>
+<entry key="2_profiler.settings.instrument.empty.methods">false</entry>
+<entry key="2_profiler.settings.instrumentation.filter.selectedprofiler.simple.filter.type">0</entry>
+<entry key="1_profiler.settings.instrumentation.filter.selectedprofiler.simple.filter.value">{$project.classes.only}</entry>
+<entry key="1_profiler.settings.sampling.interval">10</entry>
+<entry key="2_profiler.settings.cpu.profiling.type">0</entry>
+<entry key="0_profiler.settings.run.gc.on.get.results.in.memory.profiling">true</entry>
+<entry key="1_profiler.settigns.ispreset">true</entry>
+<entry key="2_profiler.settings.instrumentation.filter.selectedprofiler.simple.filter.name"/>
+<entry key="0_profiler.settings.instrument.method.invoke">true</entry>
+<entry key="0_profiler.settings.obj.alloc.stack.sampling.interval">10</entry>
+<entry key="1_profiler.settings.cpu.quick.filterprofiler.simple.filter.value"/>
+<entry key="1_profiler.settings.code.region.cpu.res.buf.size">1000</entry>
+<entry key="0_profiler.settings.instrumentation.marker.methods.size">0</entry>
+<entry key="1_profiler.settings.instrumentation.filter.selectedprofiler.filter.type">profiler.simple.filter</entry>
+<entry key="0_profiler.settings.override">false</entry>
+<entry key="1_profiler.settings.settings.name">Analyze Performance</entry>
+<entry key="2_profiler.settings.instrumentation.filter.selectedprofiler.simple.filter.value"/>
+<entry key="1_profiler.settings.cpu.quick.filterprofiler.simple.filter.type">1</entry>
+<entry key="1_profiler.settings.cpu.profiling.type">0</entry>
+<entry key="1_profiler.settings.istrumentation.root.methods-0">org.rki.sequenceeditor.view.EditorApp,loadFile,(Z)V</entry>
+<entry key="1_profiler.settings.override.jvm.args"/>
+<entry key="2_profiler.settings.obj.alloc.stack.sampling.depth">-10</entry>
+<entry key="1_profiler.settings.instrument.empty.methods">false</entry>
+<entry key="0_profiler.settings.cpu.quick.filterprofiler.filter.type">profiler.simple.filter</entry>
+<entry key="1_profiler.settings.cpu.quick.filterprofiler.simple.filter.name">Quick filter...</entry>
+<entry key="2_profiler.settigns.ispreset">true</entry>
+<entry key="1_profiler.settings.threads.monitoring.enabled">false</entry>
+<entry key="0_profiler.settings.instrumentation.root.methods.size">0</entry>
+<entry key="2_profiler.settings.threads.sampling.enabled">true</entry>
+<entry key="1_profiler.settings.override.working.dir"/>
+<entry key="1_profiler.settings.instrumentation.filter.selectedprofiler.simple.filter.type">2</entry>
+<entry key="0_profiler.settings.n.profiled.threads.limit">32</entry>
+<entry key="0_profiler.settings.cpu.quick.filterprofiler.simple.filter.value"/>
+<entry key="0_profiler.settings.cpu.profiling.type">0</entry>
+<entry key="0_profiler.settings.instrument.spawned.threads">false</entry>
+<entry key="1_profiler.settings.instrumentation.filter.selectedprofiler.simple.filter.name">Profile only project classes</entry>
+<entry key="2_profiler.settings.instrumentation.marker.methods.size">0</entry>
+<entry key="0_profiler.settings.obj.alloc.stack.sampling.depth">0</entry>
+<entry key="2_profiler.settings.cpu.quick.filterprofiler.filter.type">profiler.simple.filter</entry>
+<entry key="0_profiler.settings.profilingpoints.enabled">true</entry>
+<entry key="2_profiler.settings.cpu.quick.filterprofiler.simple.filter.type">1</entry>
+<entry key="1_profiler.settings.override">false</entry>
+<entry key="1_profiler.settings.obj.alloc.stack.sampling.interval">10</entry>
+<entry key="2_profiler.settings.istrument.getter.setter.methods">false</entry>
+<entry key="0_profiler.settings.sampling.interval">10</entry>
+<entry key="1_profiler.settings.profile.underlying.framework">false</entry>
+<entry key="2_profiler.settings.instrument.method.invoke">true</entry>
+<entry key="1_profiler.settings.profilingpoints.enabled">false</entry>
+<entry key="1_profiler.settings.istrument.getter.setter.methods">false</entry>
+<entry key="2_profiler.settings.cpu.quick.filterprofiler.simple.filter.name">Quick filter...</entry>
+<entry key="0_profiler.settings.instrumentation.filter.selectedprofiler.simple.filter.type">0</entry>
+<entry key="0_profiler.settings.thread.cpu.timer.on">false</entry>
+<entry key="0_profiler.settings.override.jvm.args"/>
+<entry key="2_profiler.settings.profiling.type">2</entry>
+<entry key="0_profiler.settings.settings.name">Monitor Application</entry>
+<entry key="0_profiler.settings.code.region.cpu.res.buf.size">1000</entry>
+<entry key="2_profiler.settings.profilingpoints.enabled">true</entry>
+<entry key="2_profiler.settings.run.gc.on.get.results.in.memory.profiling">true</entry>
+</properties>
diff --git a/nbproject/private/profiler/snapshot-1264676579774.nps b/nbproject/private/profiler/snapshot-1264676579774.nps
new file mode 100644
index 0000000..7a913be
Binary files /dev/null and b/nbproject/private/profiler/snapshot-1264676579774.nps differ
diff --git a/nbproject/private/profiler/snapshot-1264680472982.nps b/nbproject/private/profiler/snapshot-1264680472982.nps
new file mode 100644
index 0000000..19db48e
Binary files /dev/null and b/nbproject/private/profiler/snapshot-1264680472982.nps differ
diff --git a/nbproject/private/profiler/snapshot-1264680536100.nps b/nbproject/private/profiler/snapshot-1264680536100.nps
new file mode 100644
index 0000000..bb0fedb
Binary files /dev/null and b/nbproject/private/profiler/snapshot-1264680536100.nps differ
diff --git a/nbproject/project.properties b/nbproject/project.properties
new file mode 100644
index 0000000..1ecd555
--- /dev/null
+++ b/nbproject/project.properties
@@ -0,0 +1,91 @@
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.run.all.processors=true
+application.title=SequenceEditor
+application.vendor=dabrowskiw
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+debug.classpath=\
+    ${run.classpath}
+debug.test.classpath=\
+    ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/SequenceEditor.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+endorsed.classpath=
+excludes=
+file.reference.hsviewer.jar=RKIToolsDoc/output/javahelp/hsviewer.jar
+file.reference.jh.jar=RKIToolsDoc/output/javahelp/jh.jar
+file.reference.RKIToolsDoc.jar=RKIToolsDoc/output/javahelp/RKIToolsDoc.jar
+includes=**
+jar.compress=false
+javac.classpath=\
+    ${libs.absolutelayout.classpath}:\
+    ${libs.beans-binding.classpath}:\
+    ${file.reference.hsviewer.jar}:\
+    ${file.reference.jh.jar}:\
+    ${file.reference.RKIToolsDoc.jar}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+    ${javac.classpath}
+javac.source=1.6
+javac.target=1.6
+javac.test.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}:\
+    ${libs.junit.classpath}:\
+    ${libs.junit_4.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api"
+jnlp.applet.class=org.rki.sequenceeditor.view.Editor
+jnlp.applet.height=300
+jnlp.applet.width=300
+jnlp.codebase.type=local
+jnlp.codebase.url=file:/home/dabrowskiw/NetBeansProjects/SequenceEditor/dist/
+jnlp.descriptor=application
+jnlp.enabled=false
+jnlp.offline-allowed=false
+jnlp.signed=false
+# Property libs.absolutelayout.classpath is set here just to make sharing of project simpler.
+# The library definition has always preference over this property.
+libs.absolutelayout.classpath=../../Dtools/netbeans-6.0.1/java1/modules/ext/AbsoluteLayout.jar
+main.class=org.rki.sequenceeditor.view.Main
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+platform.active=default_platform
+run.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project
+# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
+# or test-sys-prop.name=value to set system properties for unit tests):
+run.jvmargs=-Djava.security.policy=applet.policy
+run.test.classpath=\
+    ${javac.test.classpath}:\
+    ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+src.hs.dir=helpSetMaker/hs
+src.resources.dir=resources
+test.src.dir=test
diff --git a/nbproject/project.xml b/nbproject/project.xml
new file mode 100644
index 0000000..8122a87
--- /dev/null
+++ b/nbproject/project.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.java.j2seproject</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
+            <name>SequenceEditor</name>
+            <minimum-ant-version>1.6.5</minimum-ant-version>
+            <source-roots>
+                <root id="src.hs.dir"/>
+                <root id="src.dir"/>
+                <root id="src.resources.dir"/>
+            </source-roots>
+            <test-roots>
+                <root id="test.src.dir"/>
+            </test-roots>
+        </data>
+    </configuration>
+</project>
diff --git a/resources/EditorName.png b/resources/EditorName.png
new file mode 100644
index 0000000..1113366
Binary files /dev/null and b/resources/EditorName.png differ
diff --git a/resources/RKILogo.png b/resources/RKILogo.png
new file mode 100644
index 0000000..9f8c598
Binary files /dev/null and b/resources/RKILogo.png differ
diff --git a/resources/editor.ico b/resources/editor.ico
new file mode 100644
index 0000000..eadbb64
Binary files /dev/null and b/resources/editor.ico differ
diff --git a/resources/icons/IUB.png b/resources/icons/IUB.png
new file mode 100644
index 0000000..c0ada73
Binary files /dev/null and b/resources/icons/IUB.png differ
diff --git a/resources/icons/help.png b/resources/icons/help.png
new file mode 100644
index 0000000..5c87017
Binary files /dev/null and b/resources/icons/help.png differ
diff --git a/resources/icons/no_sequence_name.png b/resources/icons/no_sequence_name.png
new file mode 100644
index 0000000..bb8650e
Binary files /dev/null and b/resources/icons/no_sequence_name.png differ
diff --git a/resources/icons/non-IUB.png b/resources/icons/non-IUB.png
new file mode 100644
index 0000000..365ce7d
Binary files /dev/null and b/resources/icons/non-IUB.png differ
diff --git a/resources/icons/primer_display.png b/resources/icons/primer_display.png
new file mode 100644
index 0000000..a3d6f51
Binary files /dev/null and b/resources/icons/primer_display.png differ
diff --git a/resources/icons/primer_length_display.png b/resources/icons/primer_length_display.png
new file mode 100644
index 0000000..1b2aa10
Binary files /dev/null and b/resources/icons/primer_length_display.png differ
diff --git a/resources/icons/primer_no_length_display.png b/resources/icons/primer_no_length_display.png
new file mode 100644
index 0000000..1415386
Binary files /dev/null and b/resources/icons/primer_no_length_display.png differ
diff --git a/resources/icons/primer_no_temperature_display.png b/resources/icons/primer_no_temperature_display.png
new file mode 100644
index 0000000..9b64316
Binary files /dev/null and b/resources/icons/primer_no_temperature_display.png differ
diff --git a/resources/icons/primer_sequence_display.png b/resources/icons/primer_sequence_display.png
new file mode 100644
index 0000000..87b3333
Binary files /dev/null and b/resources/icons/primer_sequence_display.png differ
diff --git a/resources/icons/primer_temperature_display.png b/resources/icons/primer_temperature_display.png
new file mode 100644
index 0000000..4843c8e
Binary files /dev/null and b/resources/icons/primer_temperature_display.png differ
diff --git a/resources/icons/sequence_name.png b/resources/icons/sequence_name.png
new file mode 100644
index 0000000..11761c3
Binary files /dev/null and b/resources/icons/sequence_name.png differ
diff --git a/src/org/json/CDL.java b/src/org/json/CDL.java
new file mode 100644
index 0000000..67736eb
--- /dev/null
+++ b/src/org/json/CDL.java
@@ -0,0 +1,261 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * This provides static methods to convert comma delimited text into a
+ * JSONArray, and to covert a JSONArray into comma delimited text. Comma
+ * delimited text is a very popular format for data interchange. It is
+ * understood by most database, spreadsheet, and organizer programs.
+ * <p>
+ * Each row of text represents a row in a table or a data record. Each row
+ * ends with a NEWLINE character. Each row contains one or more values.
+ * Values are separated by commas. A value can contain any character except
+ * for comma, unless is is wrapped in single quotes or double quotes.
+ * <p>
+ * The first row usually contains the names of the columns.
+ * <p>
+ * A comma delimited list can be converted into a JSONArray of JSONObjects.
+ * The names for the elements in the JSONObjects can be taken from the names
+ * in the first row.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class CDL {
+
+    /**
+     * Get the next value. The value can be wrapped in quotes. The value can
+     * be empty.
+     * @param x A JSONTokener of the source text.
+     * @return The value string, or null if empty.
+     * @throws JSONException if the quoted string is badly formed.
+     */
+    private static String getValue(JSONTokener x) throws JSONException {
+        char c;
+        do {
+            c = x.next();
+        } while (c == ' ' || c == '\t');
+        switch (c) {
+        case 0:
+            return null;
+        case '"':
+        case '\'':
+            return x.nextString(c);
+        case ',':
+            x.back();
+            return "";
+        default:
+            x.back();
+            return x.nextTo(',');
+        }
+    }
+
+    /**
+     * Produce a JSONArray of strings from a row of comma delimited values.
+     * @param x A JSONTokener of the source text.
+     * @return A JSONArray of strings.
+     * @throws JSONException
+     */
+    public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
+        JSONArray ja = new JSONArray();
+        for (;;) {
+            String value = getValue(x);
+            if (value == null || (ja.length() == 0 && value.length() == 0)) {
+                return null;
+            }
+            ja.put(value);
+            for (;;) {
+                char c = x.next();
+                if (c == ',') {
+                    break;
+                }
+                if (c != ' ') {
+                    if (c == '\n' || c == '\r' || c == 0) {
+                        return ja;
+                    }
+                    throw x.syntaxError("Bad character '" + c + "' (" +
+                            (int)c + ").");
+                }
+            }
+        }
+    }
+
+    /**
+     * Produce a JSONObject from a row of comma delimited text, using a
+     * parallel JSONArray of strings to provides the names of the elements.
+     * @param names A JSONArray of names. This is commonly obtained from the
+     *  first row of a comma delimited text file using the rowToJSONArray
+     *  method.
+     * @param x A JSONTokener of the source text.
+     * @return A JSONObject combining the names and values.
+     * @throws JSONException
+     */
+    public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
+            throws JSONException {
+        JSONArray ja = rowToJSONArray(x);
+        return ja != null ? ja.toJSONObject(names) :  null;
+    }
+
+    /**
+     * Produce a JSONArray of JSONObjects from a comma delimited text string,
+     * using the first row as a source of names.
+     * @param string The comma delimited text.
+     * @return A JSONArray of JSONObjects.
+     * @throws JSONException
+     */
+    public static JSONArray toJSONArray(String string) throws JSONException {
+        return toJSONArray(new JSONTokener(string));
+    }
+
+    /**
+     * Produce a JSONArray of JSONObjects from a comma delimited text string,
+     * using the first row as a source of names.
+     * @param x The JSONTokener containing the comma delimited text.
+     * @return A JSONArray of JSONObjects.
+     * @throws JSONException
+     */
+    public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
+        return toJSONArray(rowToJSONArray(x), x);
+    }
+
+    /**
+     * Produce a JSONArray of JSONObjects from a comma delimited text string
+     * using a supplied JSONArray as the source of element names.
+     * @param names A JSONArray of strings.
+     * @param string The comma delimited text.
+     * @return A JSONArray of JSONObjects.
+     * @throws JSONException
+     */
+    public static JSONArray toJSONArray(JSONArray names, String string)
+            throws JSONException {
+        return toJSONArray(names, new JSONTokener(string));
+    }
+
+    /**
+     * Produce a JSONArray of JSONObjects from a comma delimited text string
+     * using a supplied JSONArray as the source of element names.
+     * @param names A JSONArray of strings.
+     * @param x A JSONTokener of the source text.
+     * @return A JSONArray of JSONObjects.
+     * @throws JSONException
+     */
+    public static JSONArray toJSONArray(JSONArray names, JSONTokener x)
+            throws JSONException {
+        if (names == null || names.length() == 0) {
+            return null;
+        }
+        JSONArray ja = new JSONArray();
+        for (;;) {
+            JSONObject jo = rowToJSONObject(names, x);
+            if (jo == null) {
+                break;
+            }
+            ja.put(jo);
+        }
+        if (ja.length() == 0) {
+            return null;
+        }
+        return ja;
+    }
+
+
+    /**
+     * Produce a comma delimited text row from a JSONArray. Values containing
+     * the comma character will be quoted.
+     * @param ja A JSONArray of strings.
+     * @return A string ending in NEWLINE.
+     */
+    public static String rowToString(JSONArray ja) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < ja.length(); i += 1) {
+            if (i > 0) {
+                sb.append(',');
+            }
+            Object o = ja.opt(i);
+            if (o != null) {
+                String s = o.toString();
+                if (s.indexOf(',') >= 0) {
+                    if (s.indexOf('"') >= 0) {
+                        sb.append('\'');
+                        sb.append(s);
+                        sb.append('\'');
+                    } else {
+                        sb.append('"');
+                        sb.append(s);
+                        sb.append('"');
+                    }
+                } else {
+                    sb.append(s);
+                }
+            }
+        }
+        sb.append('\n');
+        return sb.toString();
+
+    }
+
+    /**
+     * Produce a comma delimited text from a JSONArray of JSONObjects. The
+     * first row will be a list of names obtained by inspecting the first
+     * JSONObject.
+     * @param ja A JSONArray of JSONObjects.
+     * @return A comma delimited text.
+     * @throws JSONException
+     */
+    public static String toString(JSONArray ja) throws JSONException {
+        JSONObject jo = ja.optJSONObject(0);
+        if (jo != null) {
+            JSONArray names = jo.names();
+            if (names != null) {
+                return rowToString(names) + toString(names, ja);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Produce a comma delimited text from a JSONArray of JSONObjects using
+     * a provided list of names. The list of names is not included in the
+     * output.
+     * @param names A JSONArray of strings.
+     * @param ja A JSONArray of JSONObjects.
+     * @return A comma delimited text.
+     * @throws JSONException
+     */
+    public static String toString(JSONArray names, JSONArray ja)
+            throws JSONException {
+        if (names == null || names.length() == 0) {
+            return null;
+        }
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < ja.length(); i += 1) {
+            JSONObject jo = ja.optJSONObject(i);
+            if (jo != null) {
+                sb.append(rowToString(jo.toJSONArray(names)));
+            }
+        }
+        return sb.toString();
+    }
+}
diff --git a/src/org/json/Cookie.java b/src/org/json/Cookie.java
new file mode 100644
index 0000000..52a1d1a
--- /dev/null
+++ b/src/org/json/Cookie.java
@@ -0,0 +1,169 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * Convert a web browser cookie specification to a JSONObject and back.
+ * JSON and Cookies are both notations for name/value pairs.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class Cookie {
+
+    /**
+     * Produce a copy of a string in which the characters '+', '%', '=', ';'
+     * and control characters are replaced with "%hh". This is a gentle form
+     * of URL encoding, attempting to cause as little distortion to the
+     * string as possible. The characters '=' and ';' are meta characters in
+     * cookies. By convention, they are escaped using the URL-encoding. This is
+     * only a convention, not a standard. Often, cookies are expected to have
+     * encoded values. We encode '=' and ';' because we must. We encode '%' and
+     * '+' because they are meta characters in URL encoding.
+     * @param string The source string.
+     * @return       The escaped result.
+     */
+    public static String escape(String string) {
+        char         c;
+        String       s = string.trim();
+        StringBuffer sb = new StringBuffer();
+        int          len = s.length();
+        for (int i = 0; i < len; i += 1) {
+            c = s.charAt(i);
+            if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') {
+                sb.append('%');
+                sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16));
+                sb.append(Character.forDigit((char)(c & 0x0f), 16));
+            } else {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+
+
+    /**
+     * Convert a cookie specification string into a JSONObject. The string
+     * will contain a name value pair separated by '='. The name and the value
+     * will be unescaped, possibly converting '+' and '%' sequences. The
+     * cookie properties may follow, separated by ';', also represented as
+     * name=value (except the secure property, which does not have a value).
+     * The name will be stored under the key "name", and the value will be
+     * stored under the key "value". This method does not do checking or
+     * validation of the parameters. It only converts the cookie string into
+     * a JSONObject.
+     * @param string The cookie specification string.
+     * @return A JSONObject containing "name", "value", and possibly other
+     *  members.
+     * @throws JSONException
+     */
+    public static JSONObject toJSONObject(String string) throws JSONException {
+        String         n;
+        JSONObject     o = new JSONObject();
+        Object         v;
+        JSONTokener x = new JSONTokener(string);
+        o.put("name", x.nextTo('='));
+        x.next('=');
+        o.put("value", x.nextTo(';'));
+        x.next();
+        while (x.more()) {
+            n = unescape(x.nextTo("=;"));
+            if (x.next() != '=') {
+                if (n.equals("secure")) {
+                    v = Boolean.TRUE;
+                } else {
+                    throw x.syntaxError("Missing '=' in cookie parameter.");
+                }
+            } else {
+                v = unescape(x.nextTo(';'));
+                x.next();
+            }
+            o.put(n, v);
+        }
+        return o;
+    }
+
+
+    /**
+     * Convert a JSONObject into a cookie specification string. The JSONObject
+     * must contain "name" and "value" members.
+     * If the JSONObject contains "expires", "domain", "path", or "secure"
+     * members, they will be appended to the cookie specification string.
+     * All other members are ignored.
+     * @param o A JSONObject
+     * @return A cookie specification string
+     * @throws JSONException
+     */
+    public static String toString(JSONObject o) throws JSONException {
+        StringBuffer sb = new StringBuffer();
+
+        sb.append(escape(o.getString("name")));
+        sb.append("=");
+        sb.append(escape(o.getString("value")));
+        if (o.has("expires")) {
+            sb.append(";expires=");
+            sb.append(o.getString("expires"));
+        }
+        if (o.has("domain")) {
+            sb.append(";domain=");
+            sb.append(escape(o.getString("domain")));
+        }
+        if (o.has("path")) {
+            sb.append(";path=");
+            sb.append(escape(o.getString("path")));
+        }
+        if (o.optBoolean("secure")) {
+            sb.append(";secure");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Convert <code>%</code><i>hh</i> sequences to single characters, and
+     * convert plus to space.
+     * @param s A string that may contain
+     *      <code>+</code> <small>(plus)</small> and
+     *      <code>%</code><i>hh</i> sequences.
+     * @return The unescaped string.
+     */
+    public static String unescape(String s) {
+        int len = s.length();
+        StringBuffer b = new StringBuffer();
+        for (int i = 0; i < len; ++i) {
+            char c = s.charAt(i);
+            if (c == '+') {
+                c = ' ';
+            } else if (c == '%' && i + 2 < len) {
+                int d = JSONTokener.dehexchar(s.charAt(i + 1));
+                int e = JSONTokener.dehexchar(s.charAt(i + 2));
+                if (d >= 0 && e >= 0) {
+                    c = (char)(d * 16 + e);
+                    i += 2;
+                }
+            }
+            b.append(c);
+        }
+        return b.toString();
+    }
+}
diff --git a/src/org/json/CookieList.java b/src/org/json/CookieList.java
new file mode 100644
index 0000000..3219ede
--- /dev/null
+++ b/src/org/json/CookieList.java
@@ -0,0 +1,90 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.util.Iterator;
+
+/**
+ * Convert a web browser cookie list string to a JSONObject and back.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class CookieList {
+
+    /**
+     * Convert a cookie list into a JSONObject. A cookie list is a sequence
+     * of name/value pairs. The names are separated from the values by '='.
+     * The pairs are separated by ';'. The names and the values
+     * will be unescaped, possibly converting '+' and '%' sequences.
+     *
+     * To add a cookie to a cooklist,
+     * cookielistJSONObject.put(cookieJSONObject.getString("name"),
+     *     cookieJSONObject.getString("value"));
+     * @param string  A cookie list string
+     * @return A JSONObject
+     * @throws JSONException
+     */
+    public static JSONObject toJSONObject(String string) throws JSONException {
+        JSONObject o = new JSONObject();
+        JSONTokener x = new JSONTokener(string);
+        while (x.more()) {
+            String name = Cookie.unescape(x.nextTo('='));
+            x.next('=');
+            o.put(name, Cookie.unescape(x.nextTo(';')));
+            x.next();
+        }
+        return o;
+    }
+
+
+    /**
+     * Convert a JSONObject into a cookie list. A cookie list is a sequence
+     * of name/value pairs. The names are separated from the values by '='.
+     * The pairs are separated by ';'. The characters '%', '+', '=', and ';'
+     * in the names and values are replaced by "%hh".
+     * @param o A JSONObject
+     * @return A cookie list string
+     * @throws JSONException
+     */
+    public static String toString(JSONObject o) throws JSONException {
+        boolean      b = false;
+        Iterator     keys = o.keys();
+        String       s;
+        StringBuffer sb = new StringBuffer();
+        while (keys.hasNext()) {
+            s = keys.next().toString();
+            if (!o.isNull(s)) {
+                if (b) {
+                    sb.append(';');
+                }
+                sb.append(Cookie.escape(s));
+                sb.append("=");
+                sb.append(Cookie.escape(o.getString(s)));
+                b = true;
+            }
+        }
+        return sb.toString();
+    }
+}
diff --git a/src/org/json/HTTP.java b/src/org/json/HTTP.java
new file mode 100644
index 0000000..e4f301c
--- /dev/null
+++ b/src/org/json/HTTP.java
@@ -0,0 +1,163 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.util.Iterator;
+
+/**
+ * Convert an HTTP header to a JSONObject and back.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class HTTP {
+
+    /** Carriage return/line feed. */
+    public static final String CRLF = "\r\n";
+
+    /**
+     * Convert an HTTP header string into a JSONObject. It can be a request
+     * header or a response header. A request header will contain
+     * <pre>{
+     *    Method: "POST" (for example),
+     *    "Request-URI": "/" (for example),
+     *    "HTTP-Version": "HTTP/1.1" (for example)
+     * }</pre>
+     * A response header will contain
+     * <pre>{
+     *    "HTTP-Version": "HTTP/1.1" (for example),
+     *    "Status-Code": "200" (for example),
+     *    "Reason-Phrase": "OK" (for example)
+     * }</pre>
+     * In addition, the other parameters in the header will be captured, using
+     * the HTTP field names as JSON names, so that <pre>
+     *    Date: Sun, 26 May 2002 18:06:04 GMT
+     *    Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
+     *    Cache-Control: no-cache</pre>
+     * become
+     * <pre>{...
+     *    Date: "Sun, 26 May 2002 18:06:04 GMT",
+     *    Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
+     *    "Cache-Control": "no-cache",
+     * ...}</pre>
+     * It does no further checking or conversion. It does not parse dates.
+     * It does not do '%' transforms on URLs.
+     * @param string An HTTP header string.
+     * @return A JSONObject containing the elements and attributes
+     * of the XML string.
+     * @throws JSONException
+     */
+    public static JSONObject toJSONObject(String string) throws JSONException {
+        JSONObject     o = new JSONObject();
+        HTTPTokener    x = new HTTPTokener(string);
+        String         t;
+
+        t = x.nextToken();
+        if (t.toUpperCase().startsWith("HTTP")) {
+
+// Response
+
+            o.put("HTTP-Version", t);
+            o.put("Status-Code", x.nextToken());
+            o.put("Reason-Phrase", x.nextTo('\0'));
+            x.next();
+
+        } else {
+
+// Request
+
+            o.put("Method", t);
+            o.put("Request-URI", x.nextToken());
+            o.put("HTTP-Version", x.nextToken());
+        }
+
+// Fields
+
+        while (x.more()) {
+            String name = x.nextTo(':');
+            x.next(':');
+            o.put(name, x.nextTo('\0'));
+            x.next();
+        }
+        return o;
+    }
+
+
+    /**
+     * Convert a JSONObject into an HTTP header. A request header must contain
+     * <pre>{
+     *    Method: "POST" (for example),
+     *    "Request-URI": "/" (for example),
+     *    "HTTP-Version": "HTTP/1.1" (for example)
+     * }</pre>
+     * A response header must contain
+     * <pre>{
+     *    "HTTP-Version": "HTTP/1.1" (for example),
+     *    "Status-Code": "200" (for example),
+     *    "Reason-Phrase": "OK" (for example)
+     * }</pre>
+     * Any other members of the JSONObject will be output as HTTP fields.
+     * The result will end with two CRLF pairs.
+     * @param o A JSONObject
+     * @return An HTTP header string.
+     * @throws JSONException if the object does not contain enough
+     *  information.
+     */
+    public static String toString(JSONObject o) throws JSONException {
+        Iterator     keys = o.keys();
+        String       s;
+        StringBuffer sb = new StringBuffer();
+        if (o.has("Status-Code") && o.has("Reason-Phrase")) {
+            sb.append(o.getString("HTTP-Version"));
+            sb.append(' ');
+            sb.append(o.getString("Status-Code"));
+            sb.append(' ');
+            sb.append(o.getString("Reason-Phrase"));
+        } else if (o.has("Method") && o.has("Request-URI")) {
+            sb.append(o.getString("Method"));
+            sb.append(' ');
+            sb.append('"');
+            sb.append(o.getString("Request-URI"));
+            sb.append('"');
+            sb.append(' ');
+            sb.append(o.getString("HTTP-Version"));
+        } else {
+            throw new JSONException("Not enough material for an HTTP header.");
+        }
+        sb.append(CRLF);
+        while (keys.hasNext()) {
+            s = keys.next().toString();
+            if (!s.equals("HTTP-Version")      && !s.equals("Status-Code") &&
+                    !s.equals("Reason-Phrase") && !s.equals("Method") &&
+                    !s.equals("Request-URI")   && !o.isNull(s)) {
+                sb.append(s);
+                sb.append(": ");
+                sb.append(o.getString(s));
+                sb.append(CRLF);
+            }
+        }
+        sb.append(CRLF);
+        return sb.toString();
+    }
+}
diff --git a/src/org/json/HTTPTokener.java b/src/org/json/HTTPTokener.java
new file mode 100644
index 0000000..b33a5b6
--- /dev/null
+++ b/src/org/json/HTTPTokener.java
@@ -0,0 +1,77 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * The HTTPTokener extends the JSONTokener to provide additional methods
+ * for the parsing of HTTP headers.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class HTTPTokener extends JSONTokener {
+
+    /**
+     * Construct an XMLTokener from a string.
+     * @param s A source string.
+     */
+    public HTTPTokener(String s) {
+        super(s);
+    }
+
+
+    /**
+     * Get the next token or string. This is used in parsing HTTP headers.
+     * @throws JSONException
+     * @return A String.
+     */
+    public String nextToken() throws JSONException {
+        char c;
+        char q;
+        StringBuffer sb = new StringBuffer();
+        do {
+            c = next();
+        } while (Character.isWhitespace(c));
+        if (c == '"' || c == '\'') {
+            q = c;
+            for (;;) {
+                c = next();
+                if (c < ' ') {
+                    throw syntaxError("Unterminated string.");
+                }
+                if (c == q) {
+                    return sb.toString();
+                }
+                sb.append(c);
+            }
+        } 
+        for (;;) {
+            if (c == 0 || Character.isWhitespace(c)) {
+                return sb.toString();
+            }
+            sb.append(c);
+            c = next();
+        }
+    }
+}
diff --git a/src/org/json/JSONArray.java b/src/org/json/JSONArray.java
new file mode 100644
index 0000000..d52c2ed
--- /dev/null
+++ b/src/org/json/JSONArray.java
@@ -0,0 +1,934 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A JSONArray is an ordered sequence of values. Its external text form is a
+ * string wrapped in square brackets with commas separating the values. The
+ * internal form is an object having <code>get</code> and <code>opt</code>
+ * methods for accessing the values by index, and <code>put</code> methods for
+ * adding or replacing values. The values can be any of these types:
+ * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
+ * <code>Number</code>, <code>String</code>, or the
+ * <code>JSONObject.NULL object</code>.
+ * <p>
+ * The constructor can convert a JSON text into a Java object. The
+ * <code>toString</code> method converts to JSON text.
+ * <p>
+ * A <code>get</code> method returns a value if one can be found, and throws an
+ * exception if one cannot be found. An <code>opt</code> method returns a
+ * default value instead of throwing an exception, and so is useful for
+ * obtaining optional values.
+ * <p>
+ * The generic <code>get()</code> and <code>opt()</code> methods return an
+ * object which you can cast or query for type. There are also typed
+ * <code>get</code> and <code>opt</code> methods that do type checking and type
+ * coercion for you.
+ * <p>
+ * The texts produced by the <code>toString</code> methods strictly conform to
+ * JSON syntax rules. The constructors are more forgiving in the texts they will
+ * accept:
+ * <ul>
+ * <li>An extra <code>,</code> <small>(comma)</small> may appear just
+ *     before the closing bracket.</li>
+ * <li>The <code>null</code> value will be inserted when there
+ *     is <code>,</code> <small>(comma)</small> elision.</li>
+ * <li>Strings may be quoted with <code>'</code> <small>(single
+ *     quote)</small>.</li>
+ * <li>Strings do not need to be quoted at all if they do not begin with a quote
+ *     or single quote, and if they do not contain leading or trailing spaces,
+ *     and if they do not contain any of these characters:
+ *     <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers
+ *     and if they are not the reserved words <code>true</code>,
+ *     <code>false</code>, or <code>null</code>.</li>
+ * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
+ *     well as by <code>,</code> <small>(comma)</small>.</li>
+ * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
+ *     <code>0x-</code> <small>(hex)</small> prefix.</li>
+ * </ul>
+
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class JSONArray {
+
+
+    /**
+     * The arrayList where the JSONArray's properties are kept.
+     */
+    private ArrayList myArrayList;
+
+
+    /**
+     * Construct an empty JSONArray.
+     */
+    public JSONArray() {
+        this.myArrayList = new ArrayList();
+    }
+
+    /**
+     * Construct a JSONArray from a JSONTokener.
+     * @param x A JSONTokener
+     * @throws JSONException If there is a syntax error.
+     */
+    public JSONArray(JSONTokener x) throws JSONException {
+        this();
+        char c = x.nextClean();
+        char q;
+        if (c == '[') {
+            q = ']';
+        } else if (c == '(') {
+            q = ')';
+        } else {
+            throw x.syntaxError("A JSONArray text must start with '['");
+        }
+        if (x.nextClean() == ']') {
+            return;
+        }
+        x.back();
+        for (;;) {
+            if (x.nextClean() == ',') {
+                x.back();
+                this.myArrayList.add(null);
+            } else {
+                x.back();
+                this.myArrayList.add(x.nextValue());
+            }
+            c = x.nextClean();
+            switch (c) {
+            case ';':
+            case ',':
+                if (x.nextClean() == ']') {
+                    return;
+                }
+                x.back();
+                break;
+            case ']':
+            case ')':
+                if (q != c) {
+                    throw x.syntaxError("Expected a '" + new Character(q) + "'");
+                }
+                return;
+            default:
+                throw x.syntaxError("Expected a ',' or ']'");
+            }
+        }
+    }
+
+
+    /**
+     * Construct a JSONArray from a source JSON text.
+     * @param source     A string that begins with
+     * <code>[</code> <small>(left bracket)</small>
+     *  and ends with <code>]</code> <small>(right bracket)</small>.
+     *  @throws JSONException If there is a syntax error.
+     */
+    public JSONArray(String source) throws JSONException {
+        this(new JSONTokener(source));
+    }
+
+
+    /**
+     * Construct a JSONArray from a Collection.
+     * @param collection     A Collection.
+     */
+    public JSONArray(Collection collection) {
+        this.myArrayList = (collection == null) ?
+            new ArrayList() :
+            new ArrayList(collection);
+    }
+
+    /**
+     * Construct a JSONArray from a collection of beans.
+     * The collection should have Java Beans.
+     * 
+     * @throws JSONException If not an array.
+     */
+
+    public JSONArray(Collection collection,boolean includeSuperClass) {
+		this.myArrayList = new ArrayList();
+		if(collection != null) {
+			for (Iterator iter = collection.iterator(); iter.hasNext();) {
+				this.myArrayList.add(new JSONObject(iter.next(),includeSuperClass));	
+			}
+		}
+    }
+
+    
+    /**
+     * Construct a JSONArray from an array
+     * @throws JSONException If not an array.
+     */
+    public JSONArray(Object array) throws JSONException {
+        this();
+        if (array.getClass().isArray()) {
+            int length = Array.getLength(array);
+            for (int i = 0; i < length; i += 1) {
+                this.put(Array.get(array, i));
+            }
+        } else {
+            throw new JSONException("JSONArray initial value should be a string or collection or array.");
+        }
+    }
+
+    /**
+     * Construct a JSONArray from an array with a bean.
+     * The array should have Java Beans.
+     * 
+     * @throws JSONException If not an array.
+     */
+    public JSONArray(Object array,boolean includeSuperClass) throws JSONException {
+        this();
+        if (array.getClass().isArray()) {
+            int length = Array.getLength(array);
+            for (int i = 0; i < length; i += 1) {
+                this.put(new JSONObject(Array.get(array, i),includeSuperClass));
+            }
+        } else {
+            throw new JSONException("JSONArray initial value should be a string or collection or array.");
+        }
+    }
+
+    
+    
+    /**
+     * Get the object value associated with an index.
+     * @param index
+     *  The index must be between 0 and length() - 1.
+     * @return An object value.
+     * @throws JSONException If there is no value for the index.
+     */
+    public Object get(int index) throws JSONException {
+        Object o = opt(index);
+        if (o == null) {
+            throw new JSONException("JSONArray[" + index + "] not found.");
+        }
+        return o;
+    }
+
+
+    /**
+     * Get the boolean value associated with an index.
+     * The string values "true" and "false" are converted to boolean.
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @return      The truth.
+     * @throws JSONException If there is no value for the index or if the
+     *  value is not convertable to boolean.
+     */
+    public boolean getBoolean(int index) throws JSONException {
+        Object o = get(index);
+        if (o.equals(Boolean.FALSE) ||
+                (o instanceof String &&
+                ((String)o).equalsIgnoreCase("false"))) {
+            return false;
+        } else if (o.equals(Boolean.TRUE) ||
+                (o instanceof String &&
+                ((String)o).equalsIgnoreCase("true"))) {
+            return true;
+        }
+        throw new JSONException("JSONArray[" + index + "] is not a Boolean.");
+    }
+
+
+    /**
+     * Get the double value associated with an index.
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @return      The value.
+     * @throws   JSONException If the key is not found or if the value cannot
+     *  be converted to a number.
+     */
+    public double getDouble(int index) throws JSONException {
+        Object o = get(index);
+        try {
+            return o instanceof Number ?
+                ((Number)o).doubleValue() :
+                Double.valueOf((String)o).doubleValue();
+        } catch (Exception e) {
+            throw new JSONException("JSONArray[" + index +
+                "] is not a number.");
+        }
+    }
+
+
+    /**
+     * Get the int value associated with an index.
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @return      The value.
+     * @throws   JSONException If the key is not found or if the value cannot
+     *  be converted to a number.
+     *  if the value cannot be converted to a number.
+     */
+    public int getInt(int index) throws JSONException {
+        Object o = get(index);
+        return o instanceof Number ?
+                ((Number)o).intValue() : (int)getDouble(index);
+    }
+
+
+    /**
+     * Get the JSONArray associated with an index.
+     * @param index The index must be between 0 and length() - 1.
+     * @return      A JSONArray value.
+     * @throws JSONException If there is no value for the index. or if the
+     * value is not a JSONArray
+     */
+    public JSONArray getJSONArray(int index) throws JSONException {
+        Object o = get(index);
+        if (o instanceof JSONArray) {
+            return (JSONArray)o;
+        }
+        throw new JSONException("JSONArray[" + index +
+                "] is not a JSONArray.");
+    }
+
+
+    /**
+     * Get the JSONObject associated with an index.
+     * @param index subscript
+     * @return      A JSONObject value.
+     * @throws JSONException If there is no value for the index or if the
+     * value is not a JSONObject
+     */
+    public JSONObject getJSONObject(int index) throws JSONException {
+        Object o = get(index);
+        if (o instanceof JSONObject) {
+            return (JSONObject)o;
+        }
+        throw new JSONException("JSONArray[" + index +
+            "] is not a JSONObject.");
+    }
+
+
+    /**
+     * Get the long value associated with an index.
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @return      The value.
+     * @throws   JSONException If the key is not found or if the value cannot
+     *  be converted to a number.
+     */
+    public long getLong(int index) throws JSONException {
+        Object o = get(index);
+        return o instanceof Number ?
+                ((Number)o).longValue() : (long)getDouble(index);
+    }
+
+
+    /**
+     * Get the string associated with an index.
+     * @param index The index must be between 0 and length() - 1.
+     * @return      A string value.
+     * @throws JSONException If there is no value for the index.
+     */
+    public String getString(int index) throws JSONException {
+        return get(index).toString();
+    }
+
+
+    /**
+     * Determine if the value is null.
+     * @param index The index must be between 0 and length() - 1.
+     * @return true if the value at the index is null, or if there is no value.
+     */
+    public boolean isNull(int index) {
+        return JSONObject.NULL.equals(opt(index));
+    }
+
+
+    /**
+     * Make a string from the contents of this JSONArray. The
+     * <code>separator</code> string is inserted between each element.
+     * Warning: This method assumes that the data structure is acyclical.
+     * @param separator A string that will be inserted between the elements.
+     * @return a string.
+     * @throws JSONException If the array contains an invalid number.
+     */
+    public String join(String separator) throws JSONException {
+        int len = length();
+        StringBuffer sb = new StringBuffer();
+
+        for (int i = 0; i < len; i += 1) {
+            if (i > 0) {
+                sb.append(separator);
+            }
+            sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
+        }
+        return sb.toString();
+    }
+
+
+    /**
+     * Get the number of elements in the JSONArray, included nulls.
+     *
+     * @return The length (or size).
+     */
+    public int length() {
+        return this.myArrayList.size();
+    }
+
+
+    /**
+     * Get the optional object value associated with an index.
+     * @param index The index must be between 0 and length() - 1.
+     * @return      An object value, or null if there is no
+     *              object at that index.
+     */
+    public Object opt(int index) {
+        return (index < 0 || index >= length()) ?
+            null : this.myArrayList.get(index);
+    }
+
+
+    /**
+     * Get the optional boolean value associated with an index.
+     * It returns false if there is no value at that index,
+     * or if the value is not Boolean.TRUE or the String "true".
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @return      The truth.
+     */
+    public boolean optBoolean(int index)  {
+        return optBoolean(index, false);
+    }
+
+
+    /**
+     * Get the optional boolean value associated with an index.
+     * It returns the defaultValue if there is no value at that index or if
+     * it is not a Boolean or the String "true" or "false" (case insensitive).
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @param defaultValue     A boolean default.
+     * @return      The truth.
+     */
+    public boolean optBoolean(int index, boolean defaultValue)  {
+        try {
+            return getBoolean(index);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+
+    /**
+     * Get the optional double value associated with an index.
+     * NaN is returned if there is no value for the index,
+     * or if the value is not a number and cannot be converted to a number.
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @return      The value.
+     */
+    public double optDouble(int index) {
+        return optDouble(index, Double.NaN);
+    }
+
+
+    /**
+     * Get the optional double value associated with an index.
+     * The defaultValue is returned if there is no value for the index,
+     * or if the value is not a number and cannot be converted to a number.
+     *
+     * @param index subscript
+     * @param defaultValue     The default value.
+     * @return      The value.
+     */
+    public double optDouble(int index, double defaultValue) {
+        try {
+            return getDouble(index);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+
+    /**
+     * Get the optional int value associated with an index.
+     * Zero is returned if there is no value for the index,
+     * or if the value is not a number and cannot be converted to a number.
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @return      The value.
+     */
+    public int optInt(int index) {
+        return optInt(index, 0);
+    }
+
+
+    /**
+     * Get the optional int value associated with an index.
+     * The defaultValue is returned if there is no value for the index,
+     * or if the value is not a number and cannot be converted to a number.
+     * @param index The index must be between 0 and length() - 1.
+     * @param defaultValue     The default value.
+     * @return      The value.
+     */
+    public int optInt(int index, int defaultValue) {
+        try {
+            return getInt(index);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+
+    /**
+     * Get the optional JSONArray associated with an index.
+     * @param index subscript
+     * @return      A JSONArray value, or null if the index has no value,
+     * or if the value is not a JSONArray.
+     */
+    public JSONArray optJSONArray(int index) {
+        Object o = opt(index);
+        return o instanceof JSONArray ? (JSONArray)o : null;
+    }
+
+
+    /**
+     * Get the optional JSONObject associated with an index.
+     * Null is returned if the key is not found, or null if the index has
+     * no value, or if the value is not a JSONObject.
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @return      A JSONObject value.
+     */
+    public JSONObject optJSONObject(int index) {
+        Object o = opt(index);
+        return o instanceof JSONObject ? (JSONObject)o : null;
+    }
+
+
+    /**
+     * Get the optional long value associated with an index.
+     * Zero is returned if there is no value for the index,
+     * or if the value is not a number and cannot be converted to a number.
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @return      The value.
+     */
+    public long optLong(int index) {
+        return optLong(index, 0);
+    }
+
+
+    /**
+     * Get the optional long value associated with an index.
+     * The defaultValue is returned if there is no value for the index,
+     * or if the value is not a number and cannot be converted to a number.
+     * @param index The index must be between 0 and length() - 1.
+     * @param defaultValue     The default value.
+     * @return      The value.
+     */
+    public long optLong(int index, long defaultValue) {
+        try {
+            return getLong(index);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+
+    /**
+     * Get the optional string value associated with an index. It returns an
+     * empty string if there is no value at that index. If the value
+     * is not a string and is not null, then it is coverted to a string.
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @return      A String value.
+     */
+    public String optString(int index) {
+        return optString(index, "");
+    }
+
+
+    /**
+     * Get the optional string associated with an index.
+     * The defaultValue is returned if the key is not found.
+     *
+     * @param index The index must be between 0 and length() - 1.
+     * @param defaultValue     The default value.
+     * @return      A String value.
+     */
+    public String optString(int index, String defaultValue) {
+        Object o = opt(index);
+        return o != null ? o.toString() : defaultValue;
+    }
+
+
+    /**
+     * Append a boolean value. This increases the array's length by one.
+     *
+     * @param value A boolean value.
+     * @return this.
+     */
+    public JSONArray put(boolean value) {
+        put(value ? Boolean.TRUE : Boolean.FALSE);
+        return this;
+    }
+
+
+    /**
+     * Put a value in the JSONArray, where the value will be a
+     * JSONArray which is produced from a Collection.
+     * @param value A Collection value.
+     * @return      this.
+     */
+    public JSONArray put(Collection value) {
+        put(new JSONArray(value));
+        return this;
+    }
+
+
+    /**
+     * Append a double value. This increases the array's length by one.
+     *
+     * @param value A double value.
+     * @throws JSONException if the value is not finite.
+     * @return this.
+     */
+    public JSONArray put(double value) throws JSONException {
+        Double d = new Double(value);
+        JSONObject.testValidity(d);
+        put(d);
+        return this;
+    }
+
+
+    /**
+     * Append an int value. This increases the array's length by one.
+     *
+     * @param value An int value.
+     * @return this.
+     */
+    public JSONArray put(int value) {
+        put(new Integer(value));
+        return this;
+    }
+
+
+    /**
+     * Append an long value. This increases the array's length by one.
+     *
+     * @param value A long value.
+     * @return this.
+     */
+    public JSONArray put(long value) {
+        put(new Long(value));
+        return this;
+    }
+
+
+    /**
+     * Put a value in the JSONArray, where the value will be a
+     * JSONObject which is produced from a Map.
+     * @param value A Map value.
+     * @return      this.
+     */
+    public JSONArray put(Map value) {
+        put(new JSONObject(value));
+        return this;
+    }
+
+
+    /**
+     * Append an object value. This increases the array's length by one.
+     * @param value An object value.  The value should be a
+     *  Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
+     *  JSONObject.NULL object.
+     * @return this.
+     */
+    public JSONArray put(Object value) {
+        this.myArrayList.add(value);
+        return this;
+    }
+
+
+    /**
+     * Put or replace a boolean value in the JSONArray. If the index is greater
+     * than the length of the JSONArray, then null elements will be added as
+     * necessary to pad it out.
+     * @param index The subscript.
+     * @param value A boolean value.
+     * @return this.
+     * @throws JSONException If the index is negative.
+     */
+    public JSONArray put(int index, boolean value) throws JSONException {
+        put(index, value ? Boolean.TRUE : Boolean.FALSE);
+        return this;
+    }
+
+
+    /**
+     * Put a value in the JSONArray, where the value will be a
+     * JSONArray which is produced from a Collection.
+     * @param index The subscript.
+     * @param value A Collection value.
+     * @return      this.
+     * @throws JSONException If the index is negative or if the value is
+     * not finite.
+     */
+    public JSONArray put(int index, Collection value) throws JSONException {
+        put(index, new JSONArray(value));
+        return this;
+    }
+
+
+    /**
+     * Put or replace a double value. If the index is greater than the length of
+     *  the JSONArray, then null elements will be added as necessary to pad
+     *  it out.
+     * @param index The subscript.
+     * @param value A double value.
+     * @return this.
+     * @throws JSONException If the index is negative or if the value is
+     * not finite.
+     */
+    public JSONArray put(int index, double value) throws JSONException {
+        put(index, new Double(value));
+        return this;
+    }
+
+
+    /**
+     * Put or replace an int value. If the index is greater than the length of
+     *  the JSONArray, then null elements will be added as necessary to pad
+     *  it out.
+     * @param index The subscript.
+     * @param value An int value.
+     * @return this.
+     * @throws JSONException If the index is negative.
+     */
+    public JSONArray put(int index, int value) throws JSONException {
+        put(index, new Integer(value));
+        return this;
+    }
+
+
+    /**
+     * Put or replace a long value. If the index is greater than the length of
+     *  the JSONArray, then null elements will be added as necessary to pad
+     *  it out.
+     * @param index The subscript.
+     * @param value A long value.
+     * @return this.
+     * @throws JSONException If the index is negative.
+     */
+    public JSONArray put(int index, long value) throws JSONException {
+        put(index, new Long(value));
+        return this;
+    }
+
+
+    /**
+     * Put a value in the JSONArray, where the value will be a
+     * JSONObject which is produced from a Map.
+     * @param index The subscript.
+     * @param value The Map value.
+     * @return      this.
+     * @throws JSONException If the index is negative or if the the value is
+     *  an invalid number.
+     */
+    public JSONArray put(int index, Map value) throws JSONException {
+        put(index, new JSONObject(value));
+        return this;
+    }
+
+
+    /**
+     * Put or replace an object value in the JSONArray. If the index is greater
+     *  than the length of the JSONArray, then null elements will be added as
+     *  necessary to pad it out.
+     * @param index The subscript.
+     * @param value The value to put into the array. The value should be a
+     *  Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
+     *  JSONObject.NULL object.
+     * @return this.
+     * @throws JSONException If the index is negative or if the the value is
+     *  an invalid number.
+     */
+    public JSONArray put(int index, Object value) throws JSONException {
+        JSONObject.testValidity(value);
+        if (index < 0) {
+            throw new JSONException("JSONArray[" + index + "] not found.");
+        }
+        if (index < length()) {
+            this.myArrayList.set(index, value);
+        } else {
+            while (index != length()) {
+                put(JSONObject.NULL);
+            }
+            put(value);
+        }
+        return this;
+    }
+
+
+    /**
+     * Produce a JSONObject by combining a JSONArray of names with the values
+     * of this JSONArray.
+     * @param names A JSONArray containing a list of key strings. These will be
+     * paired with the values.
+     * @return A JSONObject, or null if there are no names or if this JSONArray
+     * has no values.
+     * @throws JSONException If any of the names are null.
+     */
+    public JSONObject toJSONObject(JSONArray names) throws JSONException {
+        if (names == null || names.length() == 0 || length() == 0) {
+            return null;
+        }
+        JSONObject jo = new JSONObject();
+        for (int i = 0; i < names.length(); i += 1) {
+            jo.put(names.getString(i), this.opt(i));
+        }
+        return jo;
+    }
+
+
+    /**
+     * Make a JSON text of this JSONArray. For compactness, no
+     * unnecessary whitespace is added. If it is not possible to produce a
+     * syntactically correct JSON text then null will be returned instead. This
+     * could occur if the array contains an invalid number.
+     * <p>
+     * Warning: This method assumes that the data structure is acyclical.
+     *
+     * @return a printable, displayable, transmittable
+     *  representation of the array.
+     */
+    public String toString() {
+        try {
+            return '[' + join(",") + ']';
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+
+    /**
+     * Make a prettyprinted JSON text of this JSONArray.
+     * Warning: This method assumes that the data structure is acyclical.
+     * @param indentFactor The number of spaces to add to each level of
+     *  indentation.
+     * @return a printable, displayable, transmittable
+     *  representation of the object, beginning
+     *  with <code>[</code> <small>(left bracket)</small> and ending
+     *  with <code>]</code> <small>(right bracket)</small>.
+     * @throws JSONException
+     */
+    public String toString(int indentFactor) throws JSONException {
+        return toString(indentFactor, 0);
+    }
+
+
+    /**
+     * Make a prettyprinted JSON text of this JSONArray.
+     * Warning: This method assumes that the data structure is acyclical.
+     * @param indentFactor The number of spaces to add to each level of
+     *  indentation.
+     * @param indent The indention of the top level.
+     * @return a printable, displayable, transmittable
+     *  representation of the array.
+     * @throws JSONException
+     */
+    String toString(int indentFactor, int indent) throws JSONException {
+        int len = length();
+        if (len == 0) {
+            return "[]";
+        }
+        int i;
+        StringBuffer sb = new StringBuffer("[");
+        if (len == 1) {
+            sb.append(JSONObject.valueToString(this.myArrayList.get(0),
+                    indentFactor, indent));
+        } else {
+            int newindent = indent + indentFactor;
+            sb.append('\n');
+            for (i = 0; i < len; i += 1) {
+                if (i > 0) {
+                    sb.append(",\n");
+                }
+                for (int j = 0; j < newindent; j += 1) {
+                    sb.append(' ');
+                }
+                sb.append(JSONObject.valueToString(this.myArrayList.get(i),
+                        indentFactor, newindent));
+            }
+            sb.append('\n');
+            for (i = 0; i < indent; i += 1) {
+                sb.append(' ');
+            }
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+
+
+    /**
+     * Write the contents of the JSONArray as JSON text to a writer.
+     * For compactness, no whitespace is added.
+     * <p>
+     * Warning: This method assumes that the data structure is acyclical.
+     *
+     * @return The writer.
+     * @throws JSONException
+     */
+    public Writer write(Writer writer) throws JSONException {
+        try {
+            boolean b = false;
+            int     len = length();
+
+            writer.write('[');
+
+            for (int i = 0; i < len; i += 1) {
+                if (b) {
+                    writer.write(',');
+                }
+                Object v = this.myArrayList.get(i);
+                if (v instanceof JSONObject) {
+                    ((JSONObject)v).write(writer);
+                } else if (v instanceof JSONArray) {
+                    ((JSONArray)v).write(writer);
+                } else {
+                    writer.write(JSONObject.valueToString(v));
+                }
+                b = true;
+            }
+            writer.write(']');
+            return writer;
+        } catch (IOException e) {
+           throw new JSONException(e);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/org/json/JSONException.java b/src/org/json/JSONException.java
new file mode 100644
index 0000000..64b7817
--- /dev/null
+++ b/src/org/json/JSONException.java
@@ -0,0 +1,27 @@
+package org.json;
+
+/**
+ * The JSONException is thrown by the JSON.org classes then things are amiss.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class JSONException extends Exception {
+    private Throwable cause;
+
+    /**
+     * Constructs a JSONException with an explanatory message.
+     * @param message Detail about the reason for the exception.
+     */
+    public JSONException(String message) {
+        super(message);
+    }
+
+    public JSONException(Throwable t) {
+        super(t.getMessage());
+        this.cause = t;
+    }
+
+    public Throwable getCause() {
+        return this.cause;
+    }
+}
diff --git a/src/org/json/JSONML.java b/src/org/json/JSONML.java
new file mode 100644
index 0000000..7feee44
--- /dev/null
+++ b/src/org/json/JSONML.java
@@ -0,0 +1,455 @@
+package org.json;
+
+/*
+Copyright (c) 2008 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.util.Iterator;
+
+
+/**
+ * This provides static methods to convert an XML text into a JSONArray or 
+ * JSONObject, and to covert a JSONArray or JSONObject into an XML text using 
+ * the JsonML transform.
+ * @author JSON.org
+ * @version 2008-11-20
+ */
+public class JSONML {
+		
+    /**
+     * Parse XML values and store them in a JSONArray.
+     * @param x       The XMLTokener containing the source string.
+     * @param arrayForm true if array form, false if object form.
+     * @param ja      The JSONArray that is containing the current tag or null
+     *     if we are at the outermost level.
+     * @return A JSONArray if the value is the outermost tag, otherwise null.
+     * @throws JSONException
+     */
+    private static Object parse(XMLTokener x, boolean arrayForm, 
+    		JSONArray ja) throws JSONException {
+        String     attribute;
+        char       c;
+        String	   closeTag = null;
+        int        i;
+        JSONArray  newja = null;
+        JSONObject newjo = null;
+        Object     token;
+        String	   tagName = null;
+        
+// Test for and skip past these forms:
+//      <!-- ... -->
+//      <![  ... ]]>
+//      <!   ...   >
+//      <?   ...  ?>
+        
+        while (true) {
+        	token = x.nextContent();
+    		if (token == XML.LT) {
+    			token = x.nextToken();
+    			if (token instanceof Character) {
+			        if (token == XML.SLASH) {
+
+// Close tag </
+
+			        	token = x.nextToken();
+			        	if (!(token instanceof String)) {
+			        		throw new JSONException(
+			        				"Expected a closing name instead of '" + 
+			        				token + "'.");
+			        	}
+			            if (x.nextToken() != XML.GT) {
+			                throw x.syntaxError("Misshaped close tag");
+			            }
+			            return token;
+			        } else if (token == XML.BANG) {
+        		
+// <!
+        	
+			            c = x.next();
+			            if (c == '-') {
+			                if (x.next() == '-') {
+			                    x.skipPast("-->");
+			                }
+			                x.back();
+			            } else if (c == '[') {
+			                token = x.nextToken();
+			                if (token.equals("CDATA") && x.next() == '[') {
+			                	if (ja != null) {
+			                		ja.put(x.nextCDATA());
+			                	}
+			                } else {
+			                	throw x.syntaxError("Expected 'CDATA['");
+			                }
+			            } else {
+				            i = 1;
+				            do {
+				                token = x.nextMeta();
+				                if (token == null) {
+				                    throw x.syntaxError("Missing '>' after '<!'.");
+				                } else if (token == XML.LT) {
+				                    i += 1;
+				                } else if (token == XML.GT) {
+				                    i -= 1;
+				                }
+				            } while (i > 0);
+			            }
+			        } else if (token == XML.QUEST) {
+
+// <?
+
+			        	x.skipPast("?>");
+			        } else {
+			            throw x.syntaxError("Misshaped tag");
+			        }
+
+// Open tag <
+
+		        } else {
+		        	if (!(token instanceof String)) {
+			            throw x.syntaxError("Bad tagName '" + token + "'.");		        		
+		        	}
+		        	tagName = (String)token;
+		            newja = new JSONArray();		
+		            newjo = new JSONObject();
+		        	if (arrayForm) {
+			            newja.put(tagName);
+			            if (ja != null) {
+			            	ja.put(newja);
+			            }
+			        } else {
+		        		newjo.put("tagName", tagName);
+		        		if (ja != null) {
+			            	ja.put(newjo);
+			            }
+			        }
+		            token = null;
+		            for (;;) {
+		                if (token == null) {
+		                    token = x.nextToken();
+		                }
+		                if (token == null) {
+		                	throw x.syntaxError("Misshaped tag");
+		                }
+		                if (!(token instanceof String)) {
+		                	break;
+		                }
+
+//		              attribute = value
+
+	                    attribute = (String)token;
+			        	if (!arrayForm && (attribute == "tagName" || attribute == "childNode")) {
+                            throw x.syntaxError("Reserved attribute.");			        		
+			        	}
+	                    token = x.nextToken();
+	                    if (token == XML.EQ) {
+	                        token = x.nextToken();
+	                        if (!(token instanceof String)) {
+	                            throw x.syntaxError("Missing value");
+	                        }
+	                        newjo.accumulate(attribute, JSONObject.stringToValue((String)token));
+	                        token = null;
+	                    } else {
+	                    	newjo.accumulate(attribute, "");
+	                    }
+		            }
+                    if (arrayForm && newjo.length() > 0) {
+                    	newja.put(newjo);
+                    }
+
+// Empty tag <.../>
+
+	                if (token == XML.SLASH) {
+	                    if (x.nextToken() != XML.GT) {
+	                        throw x.syntaxError("Misshaped tag");
+	                    }
+	                    if (ja == null) {
+	                    	if (arrayForm) {
+	                    		return newja;
+	                    	} else {
+	                    		return newjo;
+	                    	}
+	                    }
+
+// Content, between <...> and </...>
+
+	                } else {
+	                	if (token != XML.GT) {
+	                		throw x.syntaxError("Misshaped tag");
+	                	}
+	                	closeTag = (String)parse(x, arrayForm, newja);
+	                	if (closeTag != null) {
+		                	if (!closeTag.equals(tagName)) {
+		                		throw x.syntaxError("Mismatched '" + tagName + 
+		                				"' and '" + closeTag + "'");
+					        }
+		                	tagName = null;
+		            		if (!arrayForm && newja.length() > 0) {
+		            			newjo.put("childNodes", newja);
+		            		}
+		                	if (ja == null) {
+		                    	if (arrayForm) {
+		                    		return newja;
+		                    	} else {
+		                    		return newjo;
+		                    	}
+		                	}
+	                	}
+                	}
+	            }
+		    } else {
+		    	if (ja != null) {
+		    		ja.put(token instanceof String ? 
+		    				JSONObject.stringToValue((String)token) : token);
+		    	}
+		    }
+        }
+    }
+
+
+    /**
+     * Convert a well-formed (but not necessarily valid) XML string into a
+     * JSONArray using the JsonML transform. Each XML tag is represented as
+     * a JSONArray in which the first element is the tag name. If the tag has
+     * attributes, then the second element will be JSONObject containing the
+     * name/value pairs. If the tag contains children, then strings and
+     * JSONArrays will represent the child tags.
+     * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
+     * @param string The source string.
+     * @return A JSONArray containing the structured data from the XML string.
+     * @throws JSONException
+     */
+    public static JSONArray toJSONArray(String string) throws JSONException {
+    	return toJSONArray(new XMLTokener(string));
+    }
+
+
+    /**
+     * Convert a well-formed (but not necessarily valid) XML string into a
+     * JSONArray using the JsonML transform. Each XML tag is represented as
+     * a JSONArray in which the first element is the tag name. If the tag has
+     * attributes, then the second element will be JSONObject containing the
+     * name/value pairs. If the tag contains children, then strings and
+     * JSONArrays will represent the child content and tags.
+     * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
+     * @param x An XMLTokener.
+     * @return A JSONArray containing the structured data from the XML string.
+     * @throws JSONException
+     */
+    public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
+    	return (JSONArray)parse(x, true, null);
+    }
+
+
+    
+    /**
+     * Convert a well-formed (but not necessarily valid) XML string into a
+     * JSONObject using the JsonML transform. Each XML tag is represented as
+     * a JSONObject with a "tagName" property. If the tag has attributes, then 
+     * the attributes will be in the JSONObject as properties. If the tag 
+     * contains children, the object will have a "childNodes" property which 
+     * will be an array of strings and JsonML JSONObjects.
+
+     * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
+     * @param x An XMLTokener of the XML source text.
+     * @return A JSONObject containing the structured data from the XML string.
+     * @throws JSONException
+     */
+    public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
+       	return (JSONObject)parse(x, false, null);
+    }
+    /**
+     * Convert a well-formed (but not necessarily valid) XML string into a
+     * JSONObject using the JsonML transform. Each XML tag is represented as
+     * a JSONObject with a "tagName" property. If the tag has attributes, then 
+     * the attributes will be in the JSONObject as properties. If the tag 
+     * contains children, the object will have a "childNodes" property which 
+     * will be an array of strings and JsonML JSONObjects.
+
+     * Comments, prologs, DTDs, and <code><[ [ ]]></code> are ignored.
+     * @param string The XML source text.
+     * @return A JSONObject containing the structured data from the XML string.
+     * @throws JSONException
+     */
+    public static JSONObject toJSONObject(String string) throws JSONException {
+    	return toJSONObject(new XMLTokener(string));
+    }
+
+
+    /**
+     * Reverse the JSONML transformation, making an XML text from a JSONArray.
+     * @param ja A JSONArray.
+     * @return An XML string.
+     * @throws JSONException
+     */
+    public static String toString(JSONArray ja) throws JSONException {
+    	Object		 e;
+    	int			 i;
+    	JSONObject   jo;
+    	String       k;
+	    Iterator     keys;
+	    int			 length;
+    	StringBuffer sb = new StringBuffer();
+	    String       tagName;
+	    String       v;
+	    
+// Emit <tagName	    
+    	
+    	tagName = ja.getString(0);
+		XML.noSpace(tagName);
+		tagName = XML.escape(tagName);
+		sb.append('<');
+		sb.append(tagName);
+		
+		e = ja.opt(1);
+		if (e instanceof JSONObject) {
+			i = 2;
+			jo = (JSONObject)e;
+			
+// Emit the attributes
+			
+	        keys = jo.keys();
+	        while (keys.hasNext()) {
+	            k = keys.next().toString();
+            	XML.noSpace(k);
+	            v = jo.optString(k);
+	            if (v != null) {
+		            sb.append(' ');
+		            sb.append(XML.escape(k));
+		            sb.append('=');
+		            sb.append('"');
+		            sb.append(XML.escape(v));
+		            sb.append('"');
+	            }
+	        }  
+		} else {
+			i = 1;
+		}
+	     	
+//Emit content in body
+	    	
+		length = ja.length();
+		if (i >= length) {
+	        sb.append('/');
+	        sb.append('>');
+		} else {
+	        sb.append('>');
+			do {
+			    e = ja.get(i);
+			    i += 1;
+			    if (e != null) {
+			    	if (e instanceof String) {
+			    		sb.append(XML.escape(e.toString()));
+					} else if (e instanceof JSONObject) {
+						sb.append(toString((JSONObject)e));
+					} else if (e instanceof JSONArray) {
+						sb.append(toString((JSONArray)e));
+					}
+			    }
+			} while (i < length);
+			sb.append('<');
+	        sb.append('/');
+			sb.append(tagName);
+	        sb.append('>');
+	    }
+        return sb.toString();
+    }
+    
+    /**
+     * Reverse the JSONML transformation, making an XML text from a JSONObject.
+     * The JSONObject must contain a "tagName" property. If it has children, 
+     * then it must have a "childNodes" property containing an array of objects. 
+     * The other properties are attributes with string values.
+     * @param jo A JSONObject.
+     * @return An XML string.
+     * @throws JSONException
+     */
+	public static String toString(JSONObject jo) throws JSONException {
+	    StringBuffer sb = new StringBuffer();
+	    Object		 e;
+	    int          i;
+	    JSONArray    ja;
+	    String       k;
+	    Iterator     keys;
+	    int          len;
+	    String       tagName;
+	    String       v;
+	
+//Emit <tagName
+	
+		tagName = jo.optString("tagName");
+		if (tagName == null) {
+			return XML.escape(jo.toString());
+		}
+		XML.noSpace(tagName);
+		tagName = XML.escape(tagName);
+		sb.append('<');
+		sb.append(tagName);
+	
+//Emit the attributes
+	
+        keys = jo.keys();
+        while (keys.hasNext()) {
+            k = keys.next().toString();
+            if (!k.equals("tagName") && !k.equals("childNodes")) {
+            	XML.noSpace(k);
+	            v = jo.optString(k);
+	            if (v != null) {
+		            sb.append(' ');
+		            sb.append(XML.escape(k));
+		            sb.append('=');
+		            sb.append('"');
+		            sb.append(XML.escape(v));
+		            sb.append('"');
+	            }
+            }
+        }    
+		     	
+//Emit content in body
+	
+		ja = jo.optJSONArray("childNodes");
+		if (ja == null) {
+	        sb.append('/');
+	        sb.append('>');
+		} else {
+	        sb.append('>');
+			len = ja.length();
+			for (i = 0; i < len; i += 1) {
+			    e = ja.get(i);
+			    if (e != null) {
+			    	if (e instanceof String) {
+			    		sb.append(XML.escape(e.toString()));
+					} else if (e instanceof JSONObject) {
+						sb.append(toString((JSONObject)e));
+					} else if (e instanceof JSONArray) {
+						sb.append(toString((JSONArray)e));
+					}
+			    }
+			}
+			sb.append('<');
+	        sb.append('/');
+			sb.append(tagName);
+	        sb.append('>');
+	    }
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/src/org/json/JSONObject.java b/src/org/json/JSONObject.java
new file mode 100644
index 0000000..d606810
--- /dev/null
+++ b/src/org/json/JSONObject.java
@@ -0,0 +1,1550 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeSet;
+
+/**
+ * A JSONObject is an unordered collection of name/value pairs. Its
+ * external form is a string wrapped in curly braces with colons between the
+ * names and values, and commas between the values and names. The internal form
+ * is an object having <code>get</code> and <code>opt</code> methods for
+ * accessing the values by name, and <code>put</code> methods for adding or
+ * replacing values by name. The values can be any of these types:
+ * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
+ * <code>Number</code>, <code>String</code>, or the <code>JSONObject.NULL</code>
+ * object. A JSONObject constructor can be used to convert an external form
+ * JSON text into an internal form whose values can be retrieved with the
+ * <code>get</code> and <code>opt</code> methods, or to convert values into a
+ * JSON text using the <code>put</code> and <code>toString</code> methods.
+ * A <code>get</code> method returns a value if one can be found, and throws an
+ * exception if one cannot be found. An <code>opt</code> method returns a
+ * default value instead of throwing an exception, and so is useful for
+ * obtaining optional values.
+ * <p>
+ * The generic <code>get()</code> and <code>opt()</code> methods return an
+ * object, which you can cast or query for type. There are also typed
+ * <code>get</code> and <code>opt</code> methods that do type checking and type
+ * coercion for you.
+ * <p>
+ * The <code>put</code> methods adds values to an object. For example, <pre>
+ *     myString = new JSONObject().put("JSON", "Hello, World!").toString();</pre>
+ * produces the string <code>{"JSON": "Hello, World"}</code>.
+ * <p>
+ * The texts produced by the <code>toString</code> methods strictly conform to
+ * the JSON syntax rules.
+ * The constructors are more forgiving in the texts they will accept:
+ * <ul>
+ * <li>An extra <code>,</code> <small>(comma)</small> may appear just
+ *     before the closing brace.</li>
+ * <li>Strings may be quoted with <code>'</code> <small>(single
+ *     quote)</small>.</li>
+ * <li>Strings do not need to be quoted at all if they do not begin with a quote
+ *     or single quote, and if they do not contain leading or trailing spaces,
+ *     and if they do not contain any of these characters:
+ *     <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers
+ *     and if they are not the reserved words <code>true</code>,
+ *     <code>false</code>, or <code>null</code>.</li>
+ * <li>Keys can be followed by <code>=</code> or <code>=></code> as well as
+ *     by <code>:</code>.</li>
+ * <li>Values can be followed by <code>;</code> <small>(semicolon)</small> as
+ *     well as by <code>,</code> <small>(comma)</small>.</li>
+ * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
+ *     <code>0x-</code> <small>(hex)</small> prefix.</li>
+ * </ul>
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class JSONObject {
+
+    /**
+     * JSONObject.NULL is equivalent to the value that JavaScript calls null,
+     * whilst Java's null is equivalent to the value that JavaScript calls
+     * undefined.
+     */
+     private static final class Null {
+
+        /**
+         * There is only intended to be a single instance of the NULL object,
+         * so the clone method returns itself.
+         * @return     NULL.
+         */
+        protected final Object clone() {
+            return this;
+        }
+
+
+        /**
+         * A Null object is equal to the null value and to itself.
+         * @param object    An object to test for nullness.
+         * @return true if the object parameter is the JSONObject.NULL object
+         *  or null.
+         */
+        public boolean equals(Object object) {
+            return object == null || object == this;
+        }
+
+
+        /**
+         * Get the "null" string value.
+         * @return The string "null".
+         */
+        public String toString() {
+            return "null";
+        }
+    }
+
+
+    /**
+     * The map where the JSONObject's properties are kept.
+     */
+    private Map map;
+
+
+    /**
+     * It is sometimes more convenient and less ambiguous to have a
+     * <code>NULL</code> object than to use Java's <code>null</code> value.
+     * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
+     * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
+     */
+    public static final Object NULL = new Null();
+
+
+    /**
+     * Construct an empty JSONObject.
+     */
+    public JSONObject() {
+        this.map = new HashMap();
+    }
+
+
+    /**
+     * Construct a JSONObject from a subset of another JSONObject.
+     * An array of strings is used to identify the keys that should be copied.
+     * Missing keys are ignored. 
+     * @param jo A JSONObject.
+     * @param names An array of strings.
+     * @exception JSONException If a value is a non-finite number or if a name is duplicated.
+     */
+    public JSONObject(JSONObject jo, String[] names) throws JSONException {
+        this();
+        for (int i = 0; i < names.length; i += 1) {
+            putOnce(names[i], jo.opt(names[i]));
+        }
+    }
+
+
+    /**
+     * Construct a JSONObject from a JSONTokener.
+     * @param x A JSONTokener object containing the source string.
+     * @throws JSONException If there is a syntax error in the source string 
+     *  or a duplicated key.
+     */
+    public JSONObject(JSONTokener x) throws JSONException {
+        this();
+        char c;
+        String key;
+
+        if (x.nextClean() != '{') {
+            throw x.syntaxError("A JSONObject text must begin with '{'");
+        }
+        for (;;) {
+            c = x.nextClean();
+            switch (c) {
+            case 0:
+                throw x.syntaxError("A JSONObject text must end with '}'");
+            case '}':
+                return;
+            default:
+                x.back();
+                key = x.nextValue().toString();
+            }
+
+            /*
+             * The key is followed by ':'. We will also tolerate '=' or '=>'.
+             */
+
+            c = x.nextClean();
+            if (c == '=') {
+                if (x.next() != '>') {
+                    x.back();
+                }
+            } else if (c != ':') {
+                throw x.syntaxError("Expected a ':' after a key");
+            }
+            putOnce(key, x.nextValue());
+
+            /*
+             * Pairs are separated by ','. We will also tolerate ';'.
+             */
+
+            switch (x.nextClean()) {
+            case ';':
+            case ',':
+                if (x.nextClean() == '}') {
+                    return;
+                }
+                x.back();
+                break;
+            case '}':
+                return;
+            default:
+                throw x.syntaxError("Expected a ',' or '}'");
+            }
+        }
+    }
+
+
+    /**
+     * Construct a JSONObject from a Map.
+     * 
+     * @param map A map object that can be used to initialize the contents of
+     *  the JSONObject.
+     */
+    public JSONObject(Map map) {
+        this.map = (map == null) ? new HashMap() : map;
+    }
+
+    /**
+     * Construct a JSONObject from a Map.
+     * 
+     * Note: Use this constructor when the map contains <key,bean>.
+     * 
+     * @param map - A map with Key-Bean data.
+     * @param includeSuperClass - Tell whether to include the super class properties.
+     */
+    public JSONObject(Map map, boolean includeSuperClass) {
+       	this.map = new HashMap();
+       	if (map != null){
+            for (Iterator i = map.entrySet().iterator(); i.hasNext(); ) {
+                Map.Entry e = (Map.Entry)i.next();
+                this.map.put(e.getKey(), new JSONObject(e.getValue(), includeSuperClass));
+            }
+       	}
+    }
+
+    
+    /**
+     * Construct a JSONObject from an Object using bean getters.
+     * It reflects on all of the public methods of the object.
+     * For each of the methods with no parameters and a name starting
+     * with <code>"get"</code> or <code>"is"</code> followed by an uppercase letter,
+     * the method is invoked, and a key and the value returned from the getter method
+     * are put into the new JSONObject.
+     *
+     * The key is formed by removing the <code>"get"</code> or <code>"is"</code> prefix. If the second remaining
+     * character is not upper case, then the first
+     * character is converted to lower case.
+     *
+     * For example, if an object has a method named <code>"getName"</code>, and
+     * if the result of calling <code>object.getName()</code> is <code>"Larry Fine"</code>,
+     * then the JSONObject will contain <code>"name": "Larry Fine"</code>.
+     *
+     * @param bean An object that has getter methods that should be used
+     * to make a JSONObject.
+     */
+    public JSONObject(Object bean) {
+    	this();
+        populateInternalMap(bean, false);
+    }
+    
+    
+    /**
+     * Construct JSONObject from the given bean. This will also create JSONObject
+     * for all internal object (List, Map, Inner Objects) of the provided bean.
+     * 
+     * -- See Documentation of JSONObject(Object bean) also.
+     * 
+     * @param bean An object that has getter methods that should be used
+     * to make a JSONObject.
+     * @param includeSuperClass - Tell whether to include the super class properties.
+     */
+    public JSONObject(Object bean, boolean includeSuperClass) {
+    	this();
+        populateInternalMap(bean, includeSuperClass);
+    }
+    
+    private void populateInternalMap(Object bean, boolean includeSuperClass){
+    	Class klass = bean.getClass();
+    	
+        //If klass.getSuperClass is System class then includeSuperClass = false;
+    	
+    	if (klass.getClassLoader() == null) {
+    		includeSuperClass = false;
+    	}
+    	
+    	Method[] methods = (includeSuperClass) ? 
+    			klass.getMethods() : klass.getDeclaredMethods();
+        for (int i = 0; i < methods.length; i += 1) {
+            try {
+                Method method = methods[i];
+                String name = method.getName();
+                String key = "";
+                if (name.startsWith("get")) {
+                    key = name.substring(3);
+                } else if (name.startsWith("is")) {
+                    key = name.substring(2);
+                }
+                if (key.length() > 0 &&
+                        Character.isUpperCase(key.charAt(0)) &&
+                        method.getParameterTypes().length == 0) {
+                    if (key.length() == 1) {
+                        key = key.toLowerCase();
+                    } else if (!Character.isUpperCase(key.charAt(1))) {
+                        key = key.substring(0, 1).toLowerCase() +
+                            key.substring(1);
+                    }
+                    
+                    Object result = method.invoke(bean, (Object[])null);
+                    if (result == null){
+                    	map.put(key, NULL);
+                    }else if (result.getClass().isArray()) {
+                    	map.put(key, new JSONArray(result,includeSuperClass));
+                    }else if (result instanceof Collection) { //List or Set
+                    	map.put(key, new JSONArray((Collection)result,includeSuperClass));
+                    }else if (result instanceof Map) {
+                    	map.put(key, new JSONObject((Map)result,includeSuperClass));
+                    }else if (isStandardProperty(result.getClass())) { //Primitives, String and Wrapper
+                    	map.put(key, result);
+                    }else{
+                    	if (result.getClass().getPackage().getName().startsWith("java") || 
+                    			result.getClass().getClassLoader() == null) { 
+                    		map.put(key, result.toString());
+                    	} else { //User defined Objects
+                    		map.put(key, new JSONObject(result,includeSuperClass));
+                    	}
+                    }
+                }
+            } catch (Exception e) {
+            	throw new RuntimeException(e);
+            }
+        }
+    }
+    
+    private boolean isStandardProperty(Class clazz) {
+    	return clazz.isPrimitive()                  ||
+    		clazz.isAssignableFrom(Byte.class)      ||
+    		clazz.isAssignableFrom(Short.class)     ||
+    		clazz.isAssignableFrom(Integer.class)   ||
+    		clazz.isAssignableFrom(Long.class)      ||
+    		clazz.isAssignableFrom(Float.class)     ||
+    		clazz.isAssignableFrom(Double.class)    ||
+    		clazz.isAssignableFrom(Character.class) ||
+    		clazz.isAssignableFrom(String.class)    ||
+    		clazz.isAssignableFrom(Boolean.class);
+    }
+
+ 	/**
+     * Construct a JSONObject from an Object, using reflection to find the
+     * public members. The resulting JSONObject's keys will be the strings
+     * from the names array, and the values will be the field values associated
+     * with those keys in the object. If a key is not found or not visible,
+     * then it will not be copied into the new JSONObject.
+     * @param object An object that has fields that should be used to make a
+     * JSONObject.
+     * @param names An array of strings, the names of the fields to be obtained
+     * from the object.
+     */
+    public JSONObject(Object object, String names[]) {
+        this();
+        Class c = object.getClass();
+        for (int i = 0; i < names.length; i += 1) {
+            String name = names[i];
+        	try {
+                putOpt(name, c.getField(name).get(object));
+        	} catch (Exception e) {
+                /* forget about it */
+            }
+        }    
+    }
+
+
+    /**
+     * Construct a JSONObject from a source JSON text string.
+     * This is the most commonly used JSONObject constructor.
+     * @param source    A string beginning
+     *  with <code>{</code> <small>(left brace)</small> and ending
+     *  with <code>}</code> <small>(right brace)</small>.
+     * @exception JSONException If there is a syntax error in the source 
+     *  string or a duplicated key.
+     */
+    public JSONObject(String source) throws JSONException {
+        this(new JSONTokener(source));
+    }
+
+
+    /**
+     * Accumulate values under a key. It is similar to the put method except
+     * that if there is already an object stored under the key then a
+     * JSONArray is stored under the key to hold all of the accumulated values.
+     * If there is already a JSONArray, then the new value is appended to it.
+     * In contrast, the put method replaces the previous value.
+     * @param key   A key string.
+     * @param value An object to be accumulated under the key.
+     * @return this.
+     * @throws JSONException If the value is an invalid number
+     *  or if the key is null.
+     */
+    public JSONObject accumulate(String key, Object value)
+            throws JSONException {
+        testValidity(value);
+        Object o = opt(key);
+        if (o == null) {
+            put(key, value instanceof JSONArray ?
+                    new JSONArray().put(value) :
+                    value);
+        } else if (o instanceof JSONArray) {
+            ((JSONArray)o).put(value);
+        } else {
+            put(key, new JSONArray().put(o).put(value));
+        }
+        return this;
+    }
+
+
+    /**
+     * Append values to the array under a key. If the key does not exist in the
+     * JSONObject, then the key is put in the JSONObject with its value being a
+     * JSONArray containing the value parameter. If the key was already
+     * associated with a JSONArray, then the value parameter is appended to it.
+     * @param key   A key string.
+     * @param value An object to be accumulated under the key.
+     * @return this.
+     * @throws JSONException If the key is null or if the current value
+     *  associated with the key is not a JSONArray.
+     */
+    public JSONObject append(String key, Object value)
+            throws JSONException {
+        testValidity(value);
+        Object o = opt(key);
+        if (o == null) {
+            put(key, new JSONArray().put(value));
+        } else if (o instanceof JSONArray) {
+            put(key, ((JSONArray)o).put(value));
+        } else {
+            throw new JSONException("JSONObject[" + key +
+                    "] is not a JSONArray.");
+        }
+        return this;
+    }
+
+
+    /**
+     * Produce a string from a double. The string "null" will be returned if
+     * the number is not finite.
+     * @param  d A double.
+     * @return A String.
+     */
+    static public String doubleToString(double d) {
+        if (Double.isInfinite(d) || Double.isNaN(d)) {
+            return "null";
+        }
+
+// Shave off trailing zeros and decimal point, if possible.
+
+        String s = Double.toString(d);
+        if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) {
+            while (s.endsWith("0")) {
+                s = s.substring(0, s.length() - 1);
+            }
+            if (s.endsWith(".")) {
+                s = s.substring(0, s.length() - 1);
+            }
+        }
+        return s;
+    }
+
+
+    /**
+     * Get the value object associated with a key.
+     *
+     * @param key   A key string.
+     * @return      The object associated with the key.
+     * @throws   JSONException if the key is not found.
+     */
+    public Object get(String key) throws JSONException {
+        Object o = opt(key);
+        if (o == null) {
+            throw new JSONException("JSONObject[" + quote(key) +
+                    "] not found.");
+        }
+        return o;
+    }
+
+
+    /**
+     * Get the boolean value associated with a key.
+     *
+     * @param key   A key string.
+     * @return      The truth.
+     * @throws   JSONException
+     *  if the value is not a Boolean or the String "true" or "false".
+     */
+    public boolean getBoolean(String key) throws JSONException {
+        Object o = get(key);
+        if (o.equals(Boolean.FALSE) ||
+                (o instanceof String &&
+                ((String)o).equalsIgnoreCase("false"))) {
+            return false;
+        } else if (o.equals(Boolean.TRUE) ||
+                (o instanceof String &&
+                ((String)o).equalsIgnoreCase("true"))) {
+            return true;
+        }
+        throw new JSONException("JSONObject[" + quote(key) +
+                "] is not a Boolean.");
+    }
+
+
+    /**
+     * Get the double value associated with a key.
+     * @param key   A key string.
+     * @return      The numeric value.
+     * @throws JSONException if the key is not found or
+     *  if the value is not a Number object and cannot be converted to a number.
+     */
+    public double getDouble(String key) throws JSONException {
+        Object o = get(key);
+        try {
+            return o instanceof Number ?
+                ((Number)o).doubleValue() :
+                Double.valueOf((String)o).doubleValue();
+        } catch (Exception e) {
+            throw new JSONException("JSONObject[" + quote(key) +
+                "] is not a number.");
+        }
+    }
+
+
+    /**
+     * Get the int value associated with a key. If the number value is too
+     * large for an int, it will be clipped.
+     *
+     * @param key   A key string.
+     * @return      The integer value.
+     * @throws   JSONException if the key is not found or if the value cannot
+     *  be converted to an integer.
+     */
+    public int getInt(String key) throws JSONException {
+        Object o = get(key);
+        return o instanceof Number ?
+                ((Number)o).intValue() : (int)getDouble(key);
+    }
+
+
+    /**
+     * Get the JSONArray value associated with a key.
+     *
+     * @param key   A key string.
+     * @return      A JSONArray which is the value.
+     * @throws   JSONException if the key is not found or
+     *  if the value is not a JSONArray.
+     */
+    public JSONArray getJSONArray(String key) throws JSONException {
+        Object o = get(key);
+        if (o instanceof JSONArray) {
+            return (JSONArray)o;
+        }
+        throw new JSONException("JSONObject[" + quote(key) +
+                "] is not a JSONArray.");
+    }
+
+
+    /**
+     * Get the JSONObject value associated with a key.
+     *
+     * @param key   A key string.
+     * @return      A JSONObject which is the value.
+     * @throws   JSONException if the key is not found or
+     *  if the value is not a JSONObject.
+     */
+    public JSONObject getJSONObject(String key) throws JSONException {
+        Object o = get(key);
+        if (o instanceof JSONObject) {
+            return (JSONObject)o;
+        }
+        throw new JSONException("JSONObject[" + quote(key) +
+                "] is not a JSONObject.");
+    }
+
+
+    /**
+     * Get the long value associated with a key. If the number value is too
+     * long for a long, it will be clipped.
+     *
+     * @param key   A key string.
+     * @return      The long value.
+     * @throws   JSONException if the key is not found or if the value cannot
+     *  be converted to a long.
+     */
+    public long getLong(String key) throws JSONException {
+        Object o = get(key);
+        return o instanceof Number ?
+                ((Number)o).longValue() : (long)getDouble(key);
+    }
+
+
+    /**
+     * Get an array of field names from a JSONObject.
+     *
+     * @return An array of field names, or null if there are no names.
+     */
+    public static String[] getNames(JSONObject jo) {
+    	int length = jo.length();
+    	if (length == 0) {
+    		return null;
+    	}
+    	Iterator i = jo.keys();
+    	String[] names = new String[length];
+    	int j = 0;
+    	while (i.hasNext()) {
+    		names[j] = (String)i.next();
+    		j += 1;
+    	}
+        return names;
+    }
+
+
+    /**
+     * Get an array of field names from an Object.
+     *
+     * @return An array of field names, or null if there are no names.
+     */
+    public static String[] getNames(Object object) {
+    	if (object == null) {
+    		return null;
+    	}
+    	Class klass = object.getClass();
+    	Field[] fields = klass.getFields();
+    	int length = fields.length;
+    	if (length == 0) {
+    		return null;
+    	}
+    	String[] names = new String[length];
+    	for (int i = 0; i < length; i += 1) {
+    		names[i] = fields[i].getName();
+    	}
+        return names;
+    }
+
+
+    /**
+     * Get the string associated with a key.
+     *
+     * @param key   A key string.
+     * @return      A string which is the value.
+     * @throws   JSONException if the key is not found.
+     */
+    public String getString(String key) throws JSONException {
+        return get(key).toString();
+    }
+
+
+    /**
+     * Determine if the JSONObject contains a specific key.
+     * @param key   A key string.
+     * @return      true if the key exists in the JSONObject.
+     */
+    public boolean has(String key) {
+        return this.map.containsKey(key);
+    }
+
+
+    /**
+     * Determine if the value associated with the key is null or if there is
+     *  no value.
+     * @param key   A key string.
+     * @return      true if there is no value associated with the key or if
+     *  the value is the JSONObject.NULL object.
+     */
+    public boolean isNull(String key) {
+        return JSONObject.NULL.equals(opt(key));
+    }
+
+
+    /**
+     * Get an enumeration of the keys of the JSONObject.
+     *
+     * @return An iterator of the keys.
+     */
+    public Iterator keys() {
+        return this.map.keySet().iterator();
+    }
+
+
+    /**
+     * Get the number of keys stored in the JSONObject.
+     *
+     * @return The number of keys in the JSONObject.
+     */
+    public int length() {
+        return this.map.size();
+    }
+
+
+    /**
+     * Produce a JSONArray containing the names of the elements of this
+     * JSONObject.
+     * @return A JSONArray containing the key strings, or null if the JSONObject
+     * is empty.
+     */
+    public JSONArray names() {
+        JSONArray ja = new JSONArray();
+        Iterator  keys = keys();
+        while (keys.hasNext()) {
+            ja.put(keys.next());
+        }
+        return ja.length() == 0 ? null : ja;
+    }
+
+    /**
+     * Produce a string from a Number.
+     * @param  n A Number
+     * @return A String.
+     * @throws JSONException If n is a non-finite number.
+     */
+    static public String numberToString(Number n)
+            throws JSONException {
+        if (n == null) {
+            throw new JSONException("Null pointer");
+        }
+        testValidity(n);
+
+// Shave off trailing zeros and decimal point, if possible.
+
+        String s = n.toString();
+        if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) {
+            while (s.endsWith("0")) {
+                s = s.substring(0, s.length() - 1);
+            }
+            if (s.endsWith(".")) {
+                s = s.substring(0, s.length() - 1);
+            }
+        }
+        return s;
+    }
+
+
+    /**
+     * Get an optional value associated with a key.
+     * @param key   A key string.
+     * @return      An object which is the value, or null if there is no value.
+     */
+    public Object opt(String key) {
+        return key == null ? null : this.map.get(key);
+    }
+
+
+    /**
+     * Get an optional boolean associated with a key.
+     * It returns false if there is no such key, or if the value is not
+     * Boolean.TRUE or the String "true".
+     *
+     * @param key   A key string.
+     * @return      The truth.
+     */
+    public boolean optBoolean(String key) {
+        return optBoolean(key, false);
+    }
+
+
+    /**
+     * Get an optional boolean associated with a key.
+     * It returns the defaultValue if there is no such key, or if it is not
+     * a Boolean or the String "true" or "false" (case insensitive).
+     *
+     * @param key              A key string.
+     * @param defaultValue     The default.
+     * @return      The truth.
+     */
+    public boolean optBoolean(String key, boolean defaultValue) {
+        try {
+            return getBoolean(key);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+
+    /**
+     * Put a key/value pair in the JSONObject, where the value will be a
+     * JSONArray which is produced from a Collection.
+     * @param key   A key string.
+     * @param value A Collection value.
+     * @return      this.
+     * @throws JSONException
+     */
+    public JSONObject put(String key, Collection value) throws JSONException {
+        put(key, new JSONArray(value));
+        return this;
+    }
+
+
+    /**
+     * Get an optional double associated with a key,
+     * or NaN if there is no such key or if its value is not a number.
+     * If the value is a string, an attempt will be made to evaluate it as
+     * a number.
+     *
+     * @param key   A string which is the key.
+     * @return      An object which is the value.
+     */
+    public double optDouble(String key) {
+        return optDouble(key, Double.NaN);
+    }
+
+
+    /**
+     * Get an optional double associated with a key, or the
+     * defaultValue if there is no such key or if its value is not a number.
+     * If the value is a string, an attempt will be made to evaluate it as
+     * a number.
+     *
+     * @param key   A key string.
+     * @param defaultValue     The default.
+     * @return      An object which is the value.
+     */
+    public double optDouble(String key, double defaultValue) {
+        try {
+            Object o = opt(key);
+            return o instanceof Number ? ((Number)o).doubleValue() :
+                new Double((String)o).doubleValue();
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+
+    /**
+     * Get an optional int value associated with a key,
+     * or zero if there is no such key or if the value is not a number.
+     * If the value is a string, an attempt will be made to evaluate it as
+     * a number.
+     *
+     * @param key   A key string.
+     * @return      An object which is the value.
+     */
+    public int optInt(String key) {
+        return optInt(key, 0);
+    }
+
+
+    /**
+     * Get an optional int value associated with a key,
+     * or the default if there is no such key or if the value is not a number.
+     * If the value is a string, an attempt will be made to evaluate it as
+     * a number.
+     *
+     * @param key   A key string.
+     * @param defaultValue     The default.
+     * @return      An object which is the value.
+     */
+    public int optInt(String key, int defaultValue) {
+        try {
+            return getInt(key);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+
+    /**
+     * Get an optional JSONArray associated with a key.
+     * It returns null if there is no such key, or if its value is not a
+     * JSONArray.
+     *
+     * @param key   A key string.
+     * @return      A JSONArray which is the value.
+     */
+    public JSONArray optJSONArray(String key) {
+        Object o = opt(key);
+        return o instanceof JSONArray ? (JSONArray)o : null;
+    }
+
+
+    /**
+     * Get an optional JSONObject associated with a key.
+     * It returns null if there is no such key, or if its value is not a
+     * JSONObject.
+     *
+     * @param key   A key string.
+     * @return      A JSONObject which is the value.
+     */
+    public JSONObject optJSONObject(String key) {
+        Object o = opt(key);
+        return o instanceof JSONObject ? (JSONObject)o : null;
+    }
+
+
+    /**
+     * Get an optional long value associated with a key,
+     * or zero if there is no such key or if the value is not a number.
+     * If the value is a string, an attempt will be made to evaluate it as
+     * a number.
+     *
+     * @param key   A key string.
+     * @return      An object which is the value.
+     */
+    public long optLong(String key) {
+        return optLong(key, 0);
+    }
+
+
+    /**
+     * Get an optional long value associated with a key,
+     * or the default if there is no such key or if the value is not a number.
+     * If the value is a string, an attempt will be made to evaluate it as
+     * a number.
+     *
+     * @param key   A key string.
+     * @param defaultValue     The default.
+     * @return      An object which is the value.
+     */
+    public long optLong(String key, long defaultValue) {
+        try {
+            return getLong(key);
+        } catch (Exception e) {
+            return defaultValue;
+        }
+    }
+
+
+    /**
+     * Get an optional string associated with a key.
+     * It returns an empty string if there is no such key. If the value is not
+     * a string and is not null, then it is coverted to a string.
+     *
+     * @param key   A key string.
+     * @return      A string which is the value.
+     */
+    public String optString(String key) {
+        return optString(key, "");
+    }
+
+
+    /**
+     * Get an optional string associated with a key.
+     * It returns the defaultValue if there is no such key.
+     *
+     * @param key   A key string.
+     * @param defaultValue     The default.
+     * @return      A string which is the value.
+     */
+    public String optString(String key, String defaultValue) {
+        Object o = opt(key);
+        return o != null ? o.toString() : defaultValue;
+    }
+
+
+    /**
+     * Put a key/boolean pair in the JSONObject.
+     *
+     * @param key   A key string.
+     * @param value A boolean which is the value.
+     * @return this.
+     * @throws JSONException If the key is null.
+     */
+    public JSONObject put(String key, boolean value) throws JSONException {
+        put(key, value ? Boolean.TRUE : Boolean.FALSE);
+        return this;
+    }
+
+
+    /**
+     * Put a key/double pair in the JSONObject.
+     *
+     * @param key   A key string.
+     * @param value A double which is the value.
+     * @return this.
+     * @throws JSONException If the key is null or if the number is invalid.
+     */
+    public JSONObject put(String key, double value) throws JSONException {
+        put(key, new Double(value));
+        return this;
+    }
+
+
+    /**
+     * Put a key/int pair in the JSONObject.
+     *
+     * @param key   A key string.
+     * @param value An int which is the value.
+     * @return this.
+     * @throws JSONException If the key is null.
+     */
+    public JSONObject put(String key, int value) throws JSONException {
+        put(key, new Integer(value));
+        return this;
+    }
+
+
+    /**
+     * Put a key/long pair in the JSONObject.
+     *
+     * @param key   A key string.
+     * @param value A long which is the value.
+     * @return this.
+     * @throws JSONException If the key is null.
+     */
+    public JSONObject put(String key, long value) throws JSONException {
+        put(key, new Long(value));
+        return this;
+    }
+
+
+    /**
+     * Put a key/value pair in the JSONObject, where the value will be a
+     * JSONObject which is produced from a Map.
+     * @param key   A key string.
+     * @param value A Map value.
+     * @return      this.
+     * @throws JSONException
+     */
+    public JSONObject put(String key, Map value) throws JSONException {
+        put(key, new JSONObject(value));
+        return this;
+    }
+
+
+    /**
+     * Put a key/value pair in the JSONObject. If the value is null,
+     * then the key will be removed from the JSONObject if it is present.
+     * @param key   A key string.
+     * @param value An object which is the value. It should be of one of these
+     *  types: Boolean, Double, Integer, JSONArray, JSONObject, Long, String,
+     *  or the JSONObject.NULL object.
+     * @return this.
+     * @throws JSONException If the value is non-finite number
+     *  or if the key is null.
+     */
+    public JSONObject put(String key, Object value) throws JSONException {
+        if (key == null) {
+            throw new JSONException("Null key.");
+        }
+        if (value != null) {
+            testValidity(value);
+            this.map.put(key, value);
+        } else {
+            remove(key);
+        }
+        return this;
+    }
+
+
+    /**
+     * Put a key/value pair in the JSONObject, but only if the key and the 
+     * value are both non-null, and only if there is not already a member 
+     * with that name.
+     * @param key
+     * @param value
+     * @return his.
+     * @throws JSONException if the key is a duplicate
+     */
+    public JSONObject putOnce(String key, Object value) throws JSONException {
+        if (key != null && value != null) {
+        	if (opt(key) != null) {
+                throw new JSONException("Duplicate key \"" + key + "\"");
+        	}
+            put(key, value);
+        }
+        return this;
+    }
+
+
+    /**
+     * Put a key/value pair in the JSONObject, but only if the
+     * key and the value are both non-null.
+     * @param key   A key string.
+     * @param value An object which is the value. It should be of one of these
+     *  types: Boolean, Double, Integer, JSONArray, JSONObject, Long, String,
+     *  or the JSONObject.NULL object.
+     * @return this.
+     * @throws JSONException If the value is a non-finite number.
+     */
+    public JSONObject putOpt(String key, Object value) throws JSONException {
+        if (key != null && value != null) {
+            put(key, value);
+        }
+        return this;
+    }
+    
+    
+    /**
+     * Produce a string in double quotes with backslash sequences in all the
+     * right places. A backslash will be inserted within </, allowing JSON
+     * text to be delivered in HTML. In JSON text, a string cannot contain a
+     * control character or an unescaped quote or backslash.
+     * @param string A String
+     * @return  A String correctly formatted for insertion in a JSON text.
+     */
+    public static String quote(String string) {
+        if (string == null || string.length() == 0) {
+            return "\"\"";
+        }
+
+        char         b;
+        char         c = 0;
+        int          i;
+        int          len = string.length();
+        StringBuffer sb = new StringBuffer(len + 4);
+        String       t;
+
+        sb.append('"');
+        for (i = 0; i < len; i += 1) {
+            b = c;
+            c = string.charAt(i);
+            switch (c) {
+            case '\\':
+            case '"':
+                sb.append('\\');
+                sb.append(c);
+                break;
+            case '/':
+                if (b == '<') {
+                    sb.append('\\');
+                }
+                sb.append(c);
+                break;
+            case '\b':
+                sb.append("\\b");
+                break;
+            case '\t':
+                sb.append("\\t");
+                break;
+            case '\n':
+                sb.append("\\n");
+                break;
+            case '\f':
+                sb.append("\\f");
+                break;
+            case '\r':
+                sb.append("\\r");
+                break;
+            default:
+                if (c < ' ' || (c >= '\u0080' && c < '\u00a0') ||
+                               (c >= '\u2000' && c < '\u2100')) {
+                    t = "000" + Integer.toHexString(c);
+                    sb.append("\\u" + t.substring(t.length() - 4));
+                } else {
+                    sb.append(c);
+                }
+            }
+        }
+        sb.append('"');
+        return sb.toString();
+    }
+
+    /**
+     * Remove a name and its value, if present.
+     * @param key The name to be removed.
+     * @return The value that was associated with the name,
+     * or null if there was no value.
+     */
+    public Object remove(String key) {
+        return this.map.remove(key);
+    }
+   
+    /**
+     * Get an enumeration of the keys of the JSONObject.
+     * The keys will be sorted alphabetically.
+     *
+     * @return An iterator of the keys.
+     */
+    public Iterator sortedKeys() {
+      return new TreeSet(this.map.keySet()).iterator();
+    }
+
+    /**
+     * Try to convert a string into a number, boolean, or null. If the string
+     * can't be converted, return the string.
+     * @param s A String.
+     * @return A simple JSON value.
+     */
+    static public Object stringToValue(String s) {
+        if (s.equals("")) {
+            return s;
+        }
+        if (s.equalsIgnoreCase("true")) {
+            return Boolean.TRUE;
+        }
+        if (s.equalsIgnoreCase("false")) {
+            return Boolean.FALSE;
+        }
+        if (s.equalsIgnoreCase("null")) {
+            return JSONObject.NULL;
+        }
+
+        /*
+         * If it might be a number, try converting it. We support the 0- and 0x-
+         * conventions. If a number cannot be produced, then the value will just
+         * be a string. Note that the 0-, 0x-, plus, and implied string
+         * conventions are non-standard. A JSON parser is free to accept
+         * non-JSON forms as long as it accepts all correct JSON forms.
+         */
+
+        char b = s.charAt(0);
+        if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') {
+            if (b == '0') {
+                if (s.length() > 2 &&
+                        (s.charAt(1) == 'x' || s.charAt(1) == 'X')) {
+                    try {
+                        return new Integer(Integer.parseInt(s.substring(2),
+                                16));
+                    } catch (Exception e) {
+                        /* Ignore the error */
+                    }
+                } else {
+                    try {
+                        return new Integer(Integer.parseInt(s, 8));
+                    } catch (Exception e) {
+                        /* Ignore the error */
+                    }
+                }
+            }
+            try {
+                return new Integer(s);
+            } catch (Exception e) {
+                try {
+                    return new Long(s);
+                } catch (Exception f) {
+                    try {
+                        return new Double(s);
+                    }  catch (Exception g) {
+                    	/* Ignore the error */
+                    }
+                }
+            }
+        }
+        return s;
+    }
+    
+    
+    /**
+     * Throw an exception if the object is an NaN or infinite number.
+     * @param o The object to test.
+     * @throws JSONException If o is a non-finite number.
+     */
+    static void testValidity(Object o) throws JSONException {
+        if (o != null) {
+            if (o instanceof Double) {
+                if (((Double)o).isInfinite() || ((Double)o).isNaN()) {
+                    throw new JSONException(
+                        "JSON does not allow non-finite numbers.");
+                }
+            } else if (o instanceof Float) {
+                if (((Float)o).isInfinite() || ((Float)o).isNaN()) {
+                    throw new JSONException(
+                        "JSON does not allow non-finite numbers.");
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Produce a JSONArray containing the values of the members of this
+     * JSONObject.
+     * @param names A JSONArray containing a list of key strings. This
+     * determines the sequence of the values in the result.
+     * @return A JSONArray of values.
+     * @throws JSONException If any of the values are non-finite numbers.
+     */
+    public JSONArray toJSONArray(JSONArray names) throws JSONException {
+        if (names == null || names.length() == 0) {
+            return null;
+        }
+        JSONArray ja = new JSONArray();
+        for (int i = 0; i < names.length(); i += 1) {
+            ja.put(this.opt(names.getString(i)));
+        }
+        return ja;
+    }
+
+    /**
+     * Make a JSON text of this JSONObject. For compactness, no whitespace
+     * is added. If this would not result in a syntactically correct JSON text,
+     * then null will be returned instead.
+     * <p>
+     * Warning: This method assumes that the data structure is acyclical.
+     *
+     * @return a printable, displayable, portable, transmittable
+     *  representation of the object, beginning
+     *  with <code>{</code> <small>(left brace)</small> and ending
+     *  with <code>}</code> <small>(right brace)</small>.
+     */
+    public String toString() {
+        try {
+            Iterator     keys = keys();
+            StringBuffer sb = new StringBuffer("{");
+
+            while (keys.hasNext()) {
+                if (sb.length() > 1) {
+                    sb.append(',');
+                }
+                Object o = keys.next();
+                sb.append(quote(o.toString()));
+                sb.append(':');
+                sb.append(valueToString(this.map.get(o)));
+            }
+            sb.append('}');
+            return sb.toString();
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+
+    /**
+     * Make a prettyprinted JSON text of this JSONObject.
+     * <p>
+     * Warning: This method assumes that the data structure is acyclical.
+     * @param indentFactor The number of spaces to add to each level of
+     *  indentation.
+     * @return a printable, displayable, portable, transmittable
+     *  representation of the object, beginning
+     *  with <code>{</code> <small>(left brace)</small> and ending
+     *  with <code>}</code> <small>(right brace)</small>.
+     * @throws JSONException If the object contains an invalid number.
+     */
+    public String toString(int indentFactor) throws JSONException {
+        return toString(indentFactor, 0);
+    }
+
+
+    /**
+     * Make a prettyprinted JSON text of this JSONObject.
+     * <p>
+     * Warning: This method assumes that the data structure is acyclical.
+     * @param indentFactor The number of spaces to add to each level of
+     *  indentation.
+     * @param indent The indentation of the top level.
+     * @return a printable, displayable, transmittable
+     *  representation of the object, beginning
+     *  with <code>{</code> <small>(left brace)</small> and ending
+     *  with <code>}</code> <small>(right brace)</small>.
+     * @throws JSONException If the object contains an invalid number.
+     */
+    String toString(int indentFactor, int indent) throws JSONException {
+        int j;
+        int n = length();
+        if (n == 0) {
+            return "{}";
+        }
+        Iterator     keys = sortedKeys();
+        StringBuffer sb = new StringBuffer("{");
+        int          newindent = indent + indentFactor;
+        Object       o;
+        if (n == 1) {
+            o = keys.next();
+            sb.append(quote(o.toString()));
+            sb.append(": ");
+            sb.append(valueToString(this.map.get(o), indentFactor,
+                    indent));
+        } else {
+            while (keys.hasNext()) {
+                o = keys.next();
+                if (sb.length() > 1) {
+                    sb.append(",\n");
+                } else {
+                    sb.append('\n');
+                }
+                for (j = 0; j < newindent; j += 1) {
+                    sb.append(' ');
+                }
+                sb.append(quote(o.toString()));
+                sb.append(": ");
+                sb.append(valueToString(this.map.get(o), indentFactor,
+                        newindent));
+            }
+            if (sb.length() > 1) {
+                sb.append('\n');
+                for (j = 0; j < indent; j += 1) {
+                    sb.append(' ');
+                }
+            }
+        }
+        sb.append('}');
+        return sb.toString();
+    }
+
+
+    /**
+     * Make a JSON text of an Object value. If the object has an
+     * value.toJSONString() method, then that method will be used to produce
+     * the JSON text. The method is required to produce a strictly
+     * conforming text. If the object does not contain a toJSONString
+     * method (which is the most common case), then a text will be
+     * produced by other means. If the value is an array or Collection,
+     * then a JSONArray will be made from it and its toJSONString method
+     * will be called. If the value is a MAP, then a JSONObject will be made
+     * from it and its toJSONString method will be called. Otherwise, the
+     * value's toString method will be called, and the result will be quoted.
+     *
+     * <p>
+     * Warning: This method assumes that the data structure is acyclical.
+     * @param value The value to be serialized.
+     * @return a printable, displayable, transmittable
+     *  representation of the object, beginning
+     *  with <code>{</code> <small>(left brace)</small> and ending
+     *  with <code>}</code> <small>(right brace)</small>.
+     * @throws JSONException If the value is or contains an invalid number.
+     */
+    static String valueToString(Object value) throws JSONException {
+        if (value == null || value.equals(null)) {
+            return "null";
+        }
+        if (value instanceof JSONString) {
+            Object o;
+            try {
+                o = ((JSONString)value).toJSONString();
+            } catch (Exception e) {
+                throw new JSONException(e);
+            }
+            if (o instanceof String) {
+                return (String)o;
+            }
+            throw new JSONException("Bad value from toJSONString: " + o);
+        }
+        if (value instanceof Number) {
+            return numberToString((Number) value);
+        }
+        if (value instanceof Boolean || value instanceof JSONObject ||
+                value instanceof JSONArray) {
+            return value.toString();
+        }
+        if (value instanceof Map) {
+            return new JSONObject((Map)value).toString();
+        }
+        if (value instanceof Collection) {
+            return new JSONArray((Collection)value).toString();
+        }
+        if (value.getClass().isArray()) {
+            return new JSONArray(value).toString();
+        }
+        return quote(value.toString());
+    }
+
+
+    /**
+     * Make a prettyprinted JSON text of an object value.
+     * <p>
+     * Warning: This method assumes that the data structure is acyclical.
+     * @param value The value to be serialized.
+     * @param indentFactor The number of spaces to add to each level of
+     *  indentation.
+     * @param indent The indentation of the top level.
+     * @return a printable, displayable, transmittable
+     *  representation of the object, beginning
+     *  with <code>{</code> <small>(left brace)</small> and ending
+     *  with <code>}</code> <small>(right brace)</small>.
+     * @throws JSONException If the object contains an invalid number.
+     */
+     static String valueToString(Object value, int indentFactor, int indent)
+            throws JSONException {
+        if (value == null || value.equals(null)) {
+            return "null";
+        }
+        try {
+            if (value instanceof JSONString) {
+                Object o = ((JSONString)value).toJSONString();
+                if (o instanceof String) {
+                    return (String)o;
+                }
+            }
+        } catch (Exception e) {
+            /* forget about it */
+        }
+        if (value instanceof Number) {
+            return numberToString((Number) value);
+        }
+        if (value instanceof Boolean) {
+            return value.toString();
+        }
+        if (value instanceof JSONObject) {
+            return ((JSONObject)value).toString(indentFactor, indent);
+        }
+        if (value instanceof JSONArray) {
+            return ((JSONArray)value).toString(indentFactor, indent);
+        }
+        if (value instanceof Map) {
+            return new JSONObject((Map)value).toString(indentFactor, indent);
+        }
+        if (value instanceof Collection) {
+            return new JSONArray((Collection)value).toString(indentFactor, indent);
+        }
+        if (value.getClass().isArray()) {
+            return new JSONArray(value).toString(indentFactor, indent);
+        }
+        return quote(value.toString());
+    }
+
+
+     /**
+      * Write the contents of the JSONObject as JSON text to a writer.
+      * For compactness, no whitespace is added.
+      * <p>
+      * Warning: This method assumes that the data structure is acyclical.
+      *
+      * @return The writer.
+      * @throws JSONException
+      */
+     public Writer write(Writer writer) throws JSONException {
+        try {
+            boolean  b = false;
+            Iterator keys = keys();
+            writer.write('{');
+
+            while (keys.hasNext()) {
+                if (b) {
+                    writer.write(',');
+                }
+                Object k = keys.next();
+                writer.write(quote(k.toString()));
+                writer.write(':');
+                Object v = this.map.get(k);
+                if (v instanceof JSONObject) {
+                    ((JSONObject)v).write(writer);
+                } else if (v instanceof JSONArray) {
+                    ((JSONArray)v).write(writer);
+                } else {
+                    writer.write(valueToString(v));
+                }
+                b = true;
+            }
+            writer.write('}');
+            return writer;
+        } catch (IOException e) {
+            throw new JSONException(e);
+        }
+     }
+}
\ No newline at end of file
diff --git a/src/org/json/JSONString.java b/src/org/json/JSONString.java
new file mode 100644
index 0000000..7f4f65b
--- /dev/null
+++ b/src/org/json/JSONString.java
@@ -0,0 +1,18 @@
+package org.json;
+/**
+ * The <code>JSONString</code> interface allows a <code>toJSONString()</code> 
+ * method so that a class can change the behavior of 
+ * <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
+ * and <code>JSONWriter.value(</code>Object<code>)</code>. The 
+ * <code>toJSONString</code> method will be used instead of the default behavior 
+ * of using the Object's <code>toString()</code> method and quoting the result.
+ */
+public interface JSONString {
+	/**
+	 * The <code>toJSONString</code> method allows a class to produce its own JSON 
+	 * serialization. 
+	 * 
+	 * @return A strictly syntactically correct JSON text.
+	 */
+	public String toJSONString();
+}
diff --git a/src/org/json/JSONStringer.java b/src/org/json/JSONStringer.java
new file mode 100644
index 0000000..32c9f7f
--- /dev/null
+++ b/src/org/json/JSONStringer.java
@@ -0,0 +1,78 @@
+package org.json;
+
+/*
+Copyright (c) 2006 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.io.StringWriter;
+
+/**
+ * JSONStringer provides a quick and convenient way of producing JSON text.
+ * The texts produced strictly conform to JSON syntax rules. No whitespace is
+ * added, so the results are ready for transmission or storage. Each instance of
+ * JSONStringer can produce one JSON text.
+ * <p>
+ * A JSONStringer instance provides a <code>value</code> method for appending
+ * values to the
+ * text, and a <code>key</code>
+ * method for adding keys before values in objects. There are <code>array</code>
+ * and <code>endArray</code> methods that make and bound array values, and
+ * <code>object</code> and <code>endObject</code> methods which make and bound
+ * object values. All of these methods return the JSONWriter instance,
+ * permitting cascade style. For example, <pre>
+ * myString = new JSONStringer()
+ *     .object()
+ *         .key("JSON")
+ *         .value("Hello, World!")
+ *     .endObject()
+ *     .toString();</pre> which produces the string <pre>
+ * {"JSON":"Hello, World!"}</pre>
+ * <p>
+ * The first method called must be <code>array</code> or <code>object</code>.
+ * There are no methods for adding commas or colons. JSONStringer adds them for
+ * you. Objects and arrays can be nested up to 20 levels deep.
+ * <p>
+ * This can sometimes be easier than using a JSONObject to build a string.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class JSONStringer extends JSONWriter {
+    /**
+     * Make a fresh JSONStringer. It can be used to build one JSON text.
+     */
+    public JSONStringer() {
+        super(new StringWriter());
+    }
+
+    /**
+     * Return the JSON text. This method is used to obtain the product of the
+     * JSONStringer instance. It will return <code>null</code> if there was a
+     * problem in the construction of the JSON text (such as the calls to
+     * <code>array</code> were not properly balanced with calls to
+     * <code>endArray</code>).
+     * @return The JSON text.
+     */
+    public String toString() {
+        return this.mode == 'd' ? this.writer.toString() : null;
+    }
+}
diff --git a/src/org/json/JSONTokener.java b/src/org/json/JSONTokener.java
new file mode 100644
index 0000000..f7b8488
--- /dev/null
+++ b/src/org/json/JSONTokener.java
@@ -0,0 +1,422 @@
+package org.json;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * A JSONTokener takes a source string and extracts characters and tokens from
+ * it. It is used by the JSONObject and JSONArray constructors to parse
+ * JSON source strings.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class JSONTokener {
+
+    private int index;
+    private Reader reader;
+    private char lastChar;
+    private boolean useLastChar;
+
+
+    /**
+     * Construct a JSONTokener from a string.
+     *
+     * @param reader     A reader.
+     */
+    public JSONTokener(Reader reader) {
+        this.reader = reader.markSupported() ? 
+        		reader : new BufferedReader(reader);
+        this.useLastChar = false;
+        this.index = 0;
+    }
+
+
+    /**
+     * Construct a JSONTokener from a string.
+     *
+     * @param s     A source string.
+     */
+    public JSONTokener(String s) {
+        this(new StringReader(s));
+    }
+
+
+    /**
+     * Back up one character. This provides a sort of lookahead capability,
+     * so that you can test for a digit or letter before attempting to parse
+     * the next number or identifier.
+     */
+    public void back() throws JSONException {
+        if (useLastChar || index <= 0) {
+            throw new JSONException("Stepping back two steps is not supported");
+        }
+        index -= 1;
+        useLastChar = true;
+    }
+
+
+
+    /**
+     * Get the hex value of a character (base16).
+     * @param c A character between '0' and '9' or between 'A' and 'F' or
+     * between 'a' and 'f'.
+     * @return  An int between 0 and 15, or -1 if c was not a hex digit.
+     */
+    public static int dehexchar(char c) {
+        if (c >= '0' && c <= '9') {
+            return c - '0';
+        }
+        if (c >= 'A' && c <= 'F') {
+            return c - ('A' - 10);
+        }
+        if (c >= 'a' && c <= 'f') {
+            return c - ('a' - 10);
+        }
+        return -1;
+    }
+
+
+    /**
+     * Determine if the source string still contains characters that next()
+     * can consume.
+     * @return true if not yet at the end of the source.
+     */
+    public boolean more() throws JSONException {
+        char nextChar = next();
+        if (nextChar == 0) {
+            return false;
+        } 
+        back();
+        return true;
+    }
+
+
+    /**
+     * Get the next character in the source string.
+     *
+     * @return The next character, or 0 if past the end of the source string.
+     */
+    public char next() throws JSONException {
+        if (this.useLastChar) {
+        	this.useLastChar = false;
+            if (this.lastChar != 0) {
+            	this.index += 1;
+            }
+            return this.lastChar;
+        } 
+        int c;
+        try {
+            c = this.reader.read();
+        } catch (IOException exc) {
+            throw new JSONException(exc);
+        }
+
+        if (c <= 0) { // End of stream
+        	this.lastChar = 0;
+            return 0;
+        } 
+    	this.index += 1;
+    	this.lastChar = (char) c;
+        return this.lastChar;
+    }
+
+
+    /**
+     * Consume the next character, and check that it matches a specified
+     * character.
+     * @param c The character to match.
+     * @return The character.
+     * @throws JSONException if the character does not match.
+     */
+    public char next(char c) throws JSONException {
+        char n = next();
+        if (n != c) {
+            throw syntaxError("Expected '" + c + "' and instead saw '" +
+                    n + "'");
+        }
+        return n;
+    }
+
+
+    /**
+     * Get the next n characters.
+     *
+     * @param n     The number of characters to take.
+     * @return      A string of n characters.
+     * @throws JSONException
+     *   Substring bounds error if there are not
+     *   n characters remaining in the source string.
+     */
+     public String next(int n) throws JSONException {
+         if (n == 0) {
+             return "";
+         }
+
+         char[] buffer = new char[n];
+         int pos = 0;
+
+         if (this.useLastChar) {
+        	 this.useLastChar = false;
+             buffer[0] = this.lastChar;
+             pos = 1;
+         }
+
+         try {
+             int len;
+             while ((pos < n) && ((len = reader.read(buffer, pos, n - pos)) != -1)) {
+                 pos += len;
+             }
+         } catch (IOException exc) {
+             throw new JSONException(exc);
+         }
+         this.index += pos;
+
+         if (pos < n) {
+             throw syntaxError("Substring bounds error");
+         }
+
+         this.lastChar = buffer[n - 1];
+         return new String(buffer);
+     }
+
+
+    /**
+     * Get the next char in the string, skipping whitespace.
+     * @throws JSONException
+     * @return  A character, or 0 if there are no more characters.
+     */
+    public char nextClean() throws JSONException {
+        for (;;) {
+            char c = next();
+            if (c == 0 || c > ' ') {
+                return c;
+            }
+        }
+    }
+
+
+    /**
+     * Return the characters up to the next close quote character.
+     * Backslash processing is done. The formal JSON format does not
+     * allow strings in single quotes, but an implementation is allowed to
+     * accept them.
+     * @param quote The quoting character, either
+     *      <code>"</code> <small>(double quote)</small> or
+     *      <code>'</code> <small>(single quote)</small>.
+     * @return      A String.
+     * @throws JSONException Unterminated string.
+     */
+    public String nextString(char quote) throws JSONException {
+        char c;
+        StringBuffer sb = new StringBuffer();
+        for (;;) {
+            c = next();
+            switch (c) {
+            case 0:
+            case '\n':
+            case '\r':
+                throw syntaxError("Unterminated string");
+            case '\\':
+                c = next();
+                switch (c) {
+                case 'b':
+                    sb.append('\b');
+                    break;
+                case 't':
+                    sb.append('\t');
+                    break;
+                case 'n':
+                    sb.append('\n');
+                    break;
+                case 'f':
+                    sb.append('\f');
+                    break;
+                case 'r':
+                    sb.append('\r');
+                    break;
+                case 'u':
+                    sb.append((char)Integer.parseInt(next(4), 16));
+                    break;
+                case 'x' :
+                    sb.append((char) Integer.parseInt(next(2), 16));
+                    break;
+                default:
+                    sb.append(c);
+                }
+                break;
+            default:
+                if (c == quote) {
+                    return sb.toString();
+                }
+                sb.append(c);
+            }
+        }
+    }
+
+
+    /**
+     * Get the text up but not including the specified character or the
+     * end of line, whichever comes first.
+     * @param  d A delimiter character.
+     * @return   A string.
+     */
+    public String nextTo(char d) throws JSONException {
+        StringBuffer sb = new StringBuffer();
+        for (;;) {
+            char c = next();
+            if (c == d || c == 0 || c == '\n' || c == '\r') {
+                if (c != 0) {
+                    back();
+                }
+                return sb.toString().trim();
+            }
+            sb.append(c);
+        }
+    }
+
+
+    /**
+     * Get the text up but not including one of the specified delimiter
+     * characters or the end of line, whichever comes first.
+     * @param delimiters A set of delimiter characters.
+     * @return A string, trimmed.
+     */
+    public String nextTo(String delimiters) throws JSONException {
+        char c;
+        StringBuffer sb = new StringBuffer();
+        for (;;) {
+            c = next();
+            if (delimiters.indexOf(c) >= 0 || c == 0 ||
+                    c == '\n' || c == '\r') {
+                if (c != 0) {
+                    back();
+                }
+                return sb.toString().trim();
+            }
+            sb.append(c);
+        }
+    }
+
+
+    /**
+     * Get the next value. The value can be a Boolean, Double, Integer,
+     * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
+     * @throws JSONException If syntax error.
+     *
+     * @return An object.
+     */
+    public Object nextValue() throws JSONException {
+        char c = nextClean();
+        String s;
+
+        switch (c) {
+            case '"':
+            case '\'':
+                return nextString(c);
+            case '{':
+                back();
+                return new JSONObject(this);
+            case '[':
+            case '(':
+                back();
+                return new JSONArray(this);
+        }
+
+        /*
+         * Handle unquoted text. This could be the values true, false, or
+         * null, or it can be a number. An implementation (such as this one)
+         * is allowed to also accept non-standard forms.
+         *
+         * Accumulate characters until we reach the end of the text or a
+         * formatting character.
+         */
+
+        StringBuffer sb = new StringBuffer();
+        while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
+            sb.append(c);
+            c = next();
+        }
+        back();
+
+        s = sb.toString().trim();
+        if (s.equals("")) {
+            throw syntaxError("Missing value");
+        }
+        return JSONObject.stringToValue(s);
+    }
+
+
+    /**
+     * Skip characters until the next character is the requested character.
+     * If the requested character is not found, no characters are skipped.
+     * @param to A character to skip to.
+     * @return The requested character, or zero if the requested character
+     * is not found.
+     */
+    public char skipTo(char to) throws JSONException {
+        char c;
+        try {
+            int startIndex = this.index;
+            reader.mark(Integer.MAX_VALUE);
+            do {
+                c = next();
+                if (c == 0) {
+                    reader.reset();
+                    this.index = startIndex;
+                    return c;
+                }
+            } while (c != to);
+        } catch (IOException exc) {
+            throw new JSONException(exc);
+        }
+
+        back();
+        return c;
+    }
+
+    /**
+     * Make a JSONException to signal a syntax error.
+     *
+     * @param message The error message.
+     * @return  A JSONException object, suitable for throwing
+     */
+    public JSONException syntaxError(String message) {
+        return new JSONException(message + toString());
+    }
+
+
+    /**
+     * Make a printable string of this JSONTokener.
+     *
+     * @return " at character [this.index]"
+     */
+    public String toString() {
+        return " at character " + index;
+    }
+}
\ No newline at end of file
diff --git a/src/org/json/JSONWriter.java b/src/org/json/JSONWriter.java
new file mode 100644
index 0000000..888eb39
--- /dev/null
+++ b/src/org/json/JSONWriter.java
@@ -0,0 +1,323 @@
+package org.json;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/*
+Copyright (c) 2006 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * JSONWriter provides a quick and convenient way of producing JSON text.
+ * The texts produced strictly conform to JSON syntax rules. No whitespace is
+ * added, so the results are ready for transmission or storage. Each instance of
+ * JSONWriter can produce one JSON text.
+ * <p>
+ * A JSONWriter instance provides a <code>value</code> method for appending
+ * values to the
+ * text, and a <code>key</code>
+ * method for adding keys before values in objects. There are <code>array</code>
+ * and <code>endArray</code> methods that make and bound array values, and
+ * <code>object</code> and <code>endObject</code> methods which make and bound
+ * object values. All of these methods return the JSONWriter instance,
+ * permitting a cascade style. For example, <pre>
+ * new JSONWriter(myWriter)
+ *     .object()
+ *         .key("JSON")
+ *         .value("Hello, World!")
+ *     .endObject();</pre> which writes <pre>
+ * {"JSON":"Hello, World!"}</pre>
+ * <p>
+ * The first method called must be <code>array</code> or <code>object</code>.
+ * There are no methods for adding commas or colons. JSONWriter adds them for
+ * you. Objects and arrays can be nested up to 20 levels deep.
+ * <p>
+ * This can sometimes be easier than using a JSONObject to build a string.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class JSONWriter {
+    private static final int maxdepth = 20;
+
+    /**
+     * The comma flag determines if a comma should be output before the next
+     * value.
+     */
+    private boolean comma;
+
+    /**
+     * The current mode. Values:
+     * 'a' (array),
+     * 'd' (done),
+     * 'i' (initial),
+     * 'k' (key),
+     * 'o' (object).
+     */
+    protected char mode;
+
+    /**
+     * The object/array stack.
+     */
+    private JSONObject stack[];
+
+    /**
+     * The stack top index. A value of 0 indicates that the stack is empty.
+     */
+    private int top;
+
+    /**
+     * The writer that will receive the output.
+     */
+    protected Writer writer;
+
+    /**
+     * Make a fresh JSONWriter. It can be used to build one JSON text.
+     */
+    public JSONWriter(Writer w) {
+        this.comma = false;
+        this.mode = 'i';
+        this.stack = new JSONObject[maxdepth];
+        this.top = 0;
+        this.writer = w;
+    }
+
+    /**
+     * Append a value.
+     * @param s A string value.
+     * @return this
+     * @throws JSONException If the value is out of sequence.
+     */
+    private JSONWriter append(String s) throws JSONException {
+        if (s == null) {
+            throw new JSONException("Null pointer");
+        }
+        if (this.mode == 'o' || this.mode == 'a') {
+            try {
+                if (this.comma && this.mode == 'a') {
+                    this.writer.write(',');
+                }
+                this.writer.write(s);
+            } catch (IOException e) {
+                throw new JSONException(e);
+            }
+            if (this.mode == 'o') {
+                this.mode = 'k';
+            }
+            this.comma = true;
+            return this;
+        }
+        throw new JSONException("Value out of sequence.");
+    }
+
+    /**
+     * Begin appending a new array. All values until the balancing
+     * <code>endArray</code> will be appended to this array. The
+     * <code>endArray</code> method must be called to mark the array's end.
+     * @return this
+     * @throws JSONException If the nesting is too deep, or if the object is
+     * started in the wrong place (for example as a key or after the end of the
+     * outermost array or object).
+     */
+    public JSONWriter array() throws JSONException {
+        if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
+            this.push(null);
+            this.append("[");
+            this.comma = false;
+            return this;
+        }
+        throw new JSONException("Misplaced array.");
+    }
+
+    /**
+     * End something.
+     * @param m Mode
+     * @param c Closing character
+     * @return this
+     * @throws JSONException If unbalanced.
+     */
+    private JSONWriter end(char m, char c) throws JSONException {
+        if (this.mode != m) {
+            throw new JSONException(m == 'o' ? "Misplaced endObject." :
+                "Misplaced endArray.");
+        }
+        this.pop(m);
+        try {
+            this.writer.write(c);
+        } catch (IOException e) {
+            throw new JSONException(e);
+        }
+        this.comma = true;
+        return this;
+    }
+
+    /**
+     * End an array. This method most be called to balance calls to
+     * <code>array</code>.
+     * @return this
+     * @throws JSONException If incorrectly nested.
+     */
+    public JSONWriter endArray() throws JSONException {
+        return this.end('a', ']');
+    }
+
+    /**
+     * End an object. This method most be called to balance calls to
+     * <code>object</code>.
+     * @return this
+     * @throws JSONException If incorrectly nested.
+     */
+    public JSONWriter endObject() throws JSONException {
+        return this.end('k', '}');
+    }
+
+    /**
+     * Append a key. The key will be associated with the next value. In an
+     * object, every value must be preceded by a key.
+     * @param s A key string.
+     * @return this
+     * @throws JSONException If the key is out of place. For example, keys
+     *  do not belong in arrays or if the key is null.
+     */
+    public JSONWriter key(String s) throws JSONException {
+        if (s == null) {
+            throw new JSONException("Null key.");
+        }
+        if (this.mode == 'k') {
+            try {
+                if (this.comma) {
+                    this.writer.write(',');
+                }
+                stack[top - 1].putOnce(s, Boolean.TRUE);
+                this.writer.write(JSONObject.quote(s));
+                this.writer.write(':');
+                this.comma = false;
+                this.mode = 'o';
+                return this;
+            } catch (IOException e) {
+                throw new JSONException(e);
+            }
+        }
+        throw new JSONException("Misplaced key.");
+    }
+
+
+    /**
+     * Begin appending a new object. All keys and values until the balancing
+     * <code>endObject</code> will be appended to this object. The
+     * <code>endObject</code> method must be called to mark the object's end.
+     * @return this
+     * @throws JSONException If the nesting is too deep, or if the object is
+     * started in the wrong place (for example as a key or after the end of the
+     * outermost array or object).
+     */
+    public JSONWriter object() throws JSONException {
+        if (this.mode == 'i') {
+            this.mode = 'o';
+        }
+        if (this.mode == 'o' || this.mode == 'a') {
+            this.append("{");
+            this.push(new JSONObject());
+            this.comma = false;
+            return this;
+        }
+        throw new JSONException("Misplaced object.");
+
+    }
+
+
+    /**
+     * Pop an array or object scope.
+     * @param c The scope to close.
+     * @throws JSONException If nesting is wrong.
+     */
+    private void pop(char c) throws JSONException {
+        if (this.top <= 0) {
+            throw new JSONException("Nesting error.");
+        }
+        char m = this.stack[this.top - 1] == null ? 'a' : 'k';
+        if (m != c) {
+            throw new JSONException("Nesting error.");
+        }
+        this.top -= 1;
+        this.mode = this.top == 0 ? 'd' : this.stack[this.top - 1] == null ? 'a' : 'k';
+    }
+
+    /**
+     * Push an array or object scope.
+     * @param c The scope to open.
+     * @throws JSONException If nesting is too deep.
+     */
+    private void push(JSONObject jo) throws JSONException {
+        if (this.top >= maxdepth) {
+            throw new JSONException("Nesting too deep.");
+        }
+        this.stack[this.top] = jo;
+        this.mode = jo == null ? 'a' : 'k';
+        this.top += 1;
+    }
+
+
+    /**
+     * Append either the value <code>true</code> or the value
+     * <code>false</code>.
+     * @param b A boolean.
+     * @return this
+     * @throws JSONException
+     */
+    public JSONWriter value(boolean b) throws JSONException {
+        return this.append(b ? "true" : "false");
+    }
+
+    /**
+     * Append a double value.
+     * @param d A double.
+     * @return this
+     * @throws JSONException If the number is not finite.
+     */
+    public JSONWriter value(double d) throws JSONException {
+        return this.value(new Double(d));
+    }
+
+    /**
+     * Append a long value.
+     * @param l A long.
+     * @return this
+     * @throws JSONException
+     */
+    public JSONWriter value(long l) throws JSONException {
+        return this.append(Long.toString(l));
+    }
+
+
+    /**
+     * Append an object value.
+     * @param o The object to append. It can be null, or a Boolean, Number,
+     *   String, JSONObject, or JSONArray, or an object with a toJSONString()
+     *   method.
+     * @return this
+     * @throws JSONException If the value is out of sequence.
+     */
+    public JSONWriter value(Object o) throws JSONException {
+        return this.append(JSONObject.valueToString(o));
+    }
+}
diff --git a/src/org/json/Test.java b/src/org/json/Test.java
new file mode 100644
index 0000000..e1e44ee
--- /dev/null
+++ b/src/org/json/Test.java
@@ -0,0 +1,624 @@
+package org.json;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.io.StringWriter;
+
+/**
+ * Test class. This file is not formally a member of the org.json library.
+ * It is just a casual test tool.
+ */
+public class Test {
+
+    /**
+     * Entry point.
+     * @param args
+     */
+    public static void main(String args[]) {
+        Iterator it;
+        JSONArray a;
+        JSONObject j;
+        JSONStringer jj;
+        String s;
+        
+/** 
+ *  Obj is a typical class that implements JSONString. It also
+ *  provides some beanie methods that can be used to 
+ *  construct a JSONObject. It also demonstrates constructing
+ *  a JSONObject with an array of names.
+ */
+        class Obj implements JSONString {
+        	public String aString;
+        	public double aNumber;
+        	public boolean aBoolean;
+        	
+            public Obj(String string, double n, boolean b) {
+                this.aString = string;
+                this.aNumber = n;
+                this.aBoolean = b;
+            }
+            
+            public double getNumber() {
+            	return this.aNumber;
+            }
+            
+            public String getString() {
+            	return this.aString;
+            }
+            
+            public boolean isBoolean() {
+            	return this.aBoolean;
+            }
+            
+            public String getBENT() {
+            	return "All uppercase key";
+            }
+            
+            public String getX() {
+            	return "x";
+            }
+            
+            public String toJSONString() {
+            	return "{" + JSONObject.quote(this.aString) + ":" + 
+            	JSONObject.doubleToString(this.aNumber) + "}";
+            }            
+            public String toString() {
+            	return this.getString() + " " + this.getNumber() + " " + 
+            			this.isBoolean() + "." + this.getBENT() + " " + this.getX();
+            }
+        }      
+        
+    	Obj obj = new Obj("A beany object", 42, true);
+        
+        try {     
+            j = XML.toJSONObject("<![CDATA[This is a collection of test patterns and examples for org.json.]]>  Ignore the stuff past the end.  ");
+            System.out.println(j.toString());
+
+            s = "{     \"list of lists\" : [         [1, 2, 3],         [4, 5, 6],     ] }";
+            j = new JSONObject(s);
+            System.out.println(j.toString(4));
+            System.out.println(XML.toString(j));
+                    
+            s = "<recipe name=\"bread\" prep_time=\"5 mins\" cook_time=\"3 hours\"> <title>Basic bread</title> <ingredient amount=\"8\" unit=\"dL\">Flour</ingredient> <ingredient amount=\"10\" unit=\"grams\">Yeast</ingredient> <ingredient amount=\"4\" unit=\"dL\" state=\"warm\">Water</ingredient> <ingredient amount=\"1\" unit=\"teaspoon\">Salt</ingredient> <instructions> <step>Mix all ingredients together.</step> <step>Knead thoroughly.</step> <step>Cover with a cloth, and leave for one  [...]
+            j = XML.toJSONObject(s);
+            System.out.println(j.toString(4));
+            System.out.println();
+            
+            j = JSONML.toJSONObject(s);
+            System.out.println(j.toString());
+            System.out.println(JSONML.toString(j));
+            System.out.println();
+            
+            a = JSONML.toJSONArray(s);
+            System.out.println(a.toString(4));
+            System.out.println(JSONML.toString(a));
+            System.out.println();
+            
+            s = "<div id=\"demo\" class=\"JSONML\"><p>JSONML is a transformation between <b>JSON</b> and <b>XML</b> that preserves ordering of document features.</p><p>JSONML can work with JSON arrays or JSON objects.</p><p>Three<br/>little<br/>words</p></div>";
+            j = JSONML.toJSONObject(s);
+            System.out.println(j.toString(4));
+            System.out.println(JSONML.toString(j));
+            System.out.println();
+            
+            a = JSONML.toJSONArray(s);
+            System.out.println(a.toString(4));
+            System.out.println(JSONML.toString(a));
+            System.out.println();
+            
+            s = "<person created=\"2006-11-11T19:23\" modified=\"2006-12-31T23:59\">\n <firstName>Robert</firstName>\n <lastName>Smith</lastName>\n <address type=\"home\">\n <street>12345 Sixth Ave</street>\n <city>Anytown</city>\n <state>CA</state>\n <postalCode>98765-4321</postalCode>\n </address>\n </person>";
+            j = XML.toJSONObject(s);
+            System.out.println(j.toString(4));
+            
+            j = new JSONObject(obj);
+            System.out.println(j.toString());
+            
+            s = "{ \"entity\": { \"imageURL\": \"\", \"name\": \"IXXXXXXXXXXXXX\", \"id\": 12336, \"ratingCount\": null, \"averageRating\": null } }";
+            j = new JSONObject(s);
+            System.out.println(j.toString(2));
+
+            jj = new JSONStringer();
+            s = jj
+	            .object()
+	                .key("single")
+	                .value("MARIE HAA'S")
+	                .key("Johnny")
+	                .value("MARIE HAA\\'S")
+	                .key("foo")
+	                .value("bar")
+	                .key("baz")
+	                .array()
+	                    .object()
+	                        .key("quux")
+	                        .value("Thanks, Josh!")
+	                    .endObject()
+	                .endArray()
+	                .key("obj keys")
+	                .value(JSONObject.getNames(obj))
+	            .endObject()
+            .toString();
+            System.out.println(s);
+
+            System.out.println(new JSONStringer()
+                .object()
+                	.key("a")
+                	.array()
+                		.array()
+                			.array()
+                				.value("b")
+                            .endArray()
+                        .endArray()
+                    .endArray()
+                .endObject()
+                .toString());
+
+            jj = new JSONStringer();
+            jj.array();
+            jj.value(1);
+            jj.array();
+            jj.value(null);
+            jj.array();
+            jj.object();
+            jj.key("empty-array").array().endArray();
+            jj.key("answer").value(42);
+            jj.key("null").value(null);
+            jj.key("false").value(false);
+            jj.key("true").value(true);
+            jj.key("big").value(123456789e+88);
+            jj.key("small").value(123456789e-88);
+            jj.key("empty-object").object().endObject();
+            jj.key("long");
+            jj.value(9223372036854775807L);
+            jj.endObject();
+            jj.value("two");
+            jj.endArray();
+            jj.value(true);
+            jj.endArray();
+            jj.value(98.6);
+            jj.value(-100.0);
+            jj.object();
+            jj.endObject();
+            jj.object();
+            jj.key("one");
+            jj.value(1.00);
+            jj.endObject();
+            jj.value(obj);
+            jj.endArray();
+            System.out.println(jj.toString());
+
+            System.out.println(new JSONArray(jj.toString()).toString(4));
+
+        	int ar[] = {1, 2, 3};
+        	JSONArray ja = new JSONArray(ar);
+        	System.out.println(ja.toString());
+        	
+        	String sa[] = {"aString", "aNumber", "aBoolean"};            
+            j = new JSONObject(obj, sa);
+            j.put("Testing JSONString interface", obj);
+            System.out.println(j.toString(4));          
+            
+            j = new JSONObject("{slashes: '///', closetag: '</script>', backslash:'\\\\', ei: {quotes: '\"\\''},eo: {a: '\"quoted\"', b:\"don't\"}, quotes: [\"'\", '\"']}");
+            System.out.println(j.toString(2));
+            System.out.println(XML.toString(j));
+            System.out.println("");
+
+            j = new JSONObject(
+                "{foo: [true, false,9876543210,    0.0, 1.00000001,  1.000000000001, 1.00000000000000001," +
+                " .00000000000000001, 2.00, 0.1, 2e100, -32,[],{}, \"string\"], " +
+                "  to   : null, op : 'Good'," +
+                "ten:10} postfix comment");
+            j.put("String", "98.6");
+            j.put("JSONObject", new JSONObject());
+            j.put("JSONArray", new JSONArray());
+            j.put("int", 57);
+            j.put("double", 123456789012345678901234567890.);
+            j.put("true", true);
+            j.put("false", false);
+            j.put("null", JSONObject.NULL);
+            j.put("bool", "true");
+            j.put("zero", -0.0);
+            j.put("\\u2028", "\u2028");
+            j.put("\\u2029", "\u2029");
+            a = j.getJSONArray("foo");
+            a.put(666);
+            a.put(2001.99);
+            a.put("so \"fine\".");
+            a.put("so <fine>.");
+            a.put(true);
+            a.put(false);
+            a.put(new JSONArray());
+            a.put(new JSONObject());
+            j.put("keys", JSONObject.getNames(j));
+            System.out.println(j.toString(4));
+            System.out.println(XML.toString(j));
+
+            System.out.println("String: " + j.getDouble("String"));
+            System.out.println("  bool: " + j.getBoolean("bool"));
+            System.out.println("    to: " + j.getString("to"));
+            System.out.println("  true: " + j.getString("true"));
+            System.out.println("   foo: " + j.getJSONArray("foo"));
+            System.out.println("    op: " + j.getString("op"));
+            System.out.println("   ten: " + j.getInt("ten"));
+            System.out.println("  oops: " + j.optBoolean("oops"));
+
+            s = "<xml one = 1 two=' \"2\" '><five></five>First \u0009<content><five></five> This is \"content\". <three>  3  </three>JSON does not preserve the sequencing of elements and contents.<three>  III  </three>  <three>  T H R E E</three><four/>Content text is an implied structure in XML. <six content=\"6\"/>JSON does not have implied structure:<seven>7</seven>everything is explicit.<![CDATA[CDATA blocks<are><supported>!]]></xml>";
+            j = XML.toJSONObject(s);
+            System.out.println(j.toString(2));
+            System.out.println(XML.toString(j));
+            System.out.println("");
+            
+            ja = JSONML.toJSONArray(s);
+            System.out.println(ja.toString(4));
+            System.out.println(JSONML.toString(ja));
+            System.out.println("");
+            
+            s = "<xml do='0'>uno<a re='1' mi='2'>dos<b fa='3'/>tres<c>true</c>quatro</a>cinqo<d>seis<e/></d></xml>";
+            ja = JSONML.toJSONArray(s);
+            System.out.println(ja.toString(4));
+            System.out.println(JSONML.toString(ja));
+            System.out.println("");
+
+            s = "<mapping><empty/>   <class name = \"Customer\">      <field name = \"ID\" type = \"string\">         <bind-xml name=\"ID\" node=\"attribute\"/>      </field>      <field name = \"FirstName\" type = \"FirstName\"/>      <field name = \"MI\" type = \"MI\"/>      <field name = \"LastName\" type = \"LastName\"/>   </class>   <class name = \"FirstName\">      <field name = \"text\">         <bind-xml name = \"text\" node = \"text\"/>      </field>   </class>   <class name = \ [...]
+            j = XML.toJSONObject(s);
+
+            System.out.println(j.toString(2));
+            System.out.println(XML.toString(j));
+            System.out.println("");
+            ja = JSONML.toJSONArray(s);
+            System.out.println(ja.toString(4));
+            System.out.println(JSONML.toString(ja));
+            System.out.println("");
+
+            j = XML.toJSONObject("<?xml version=\"1.0\" ?><Book Author=\"Anonymous\"><Title>Sample Book</Title><Chapter id=\"1\">This is chapter 1. It is not very long or interesting.</Chapter><Chapter id=\"2\">This is chapter 2. Although it is longer than chapter 1, it is not any more interesting.</Chapter></Book>");
+            System.out.println(j.toString(2));
+            System.out.println(XML.toString(j));
+            System.out.println("");
+
+            j = XML.toJSONObject("<!DOCTYPE bCard 'http://www.cs.caltech.edu/~adam/schemas/bCard'><bCard><?xml default bCard        firstname = ''        lastname  = '' company   = '' email = '' homepage  = ''?><bCard        firstname = 'Rohit'        lastname  = 'Khare'        company   = 'MCI'        email     = 'khare at mci.net'        homepage  = 'http://pest.w3.org/'/><bCard        firstname = 'Adam'        lastname  = 'Rifkin'        company   = 'Caltech Infospheres Project'        e [...]
+            System.out.println(j.toString(2));
+            System.out.println(XML.toString(j));
+            System.out.println("");
+
+            j = XML.toJSONObject("<?xml version=\"1.0\"?><customer>    <firstName>        <text>Fred</text>    </firstName>    <ID>fbs0001</ID>    <lastName> <text>Scerbo</text>    </lastName>    <MI>        <text>B</text>    </MI></customer>");
+            System.out.println(j.toString(2));
+            System.out.println(XML.toString(j));
+            System.out.println("");
+
+            j = XML.toJSONObject("<!ENTITY tp-address PUBLIC '-//ABC University::Special Collections Library//TEXT (titlepage: name and address)//EN' 'tpspcoll.sgm'><list type='simple'><head>Repository Address </head><item>Special Collections Library</item><item>ABC University</item><item>Main Library, 40 Circle Drive</item><item>Ourtown, Pennsylvania</item><item>17654 USA</item></list>");
+            System.out.println(j.toString());
+            System.out.println(XML.toString(j));
+            System.out.println("");
+
+            j = XML.toJSONObject("<test intertag status=ok><empty/>deluxe<blip sweet=true>&"toot"&toot;&#x41;</blip><x>eks</x><w>bonus</w><w>bonus2</w></test>");
+            System.out.println(j.toString(2));
+            System.out.println(XML.toString(j));
+            System.out.println("");
+
+            j = HTTP.toJSONObject("GET / HTTP/1.0\nAccept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*\nAccept-Language: en-us\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows 98; Win 9x 4.90; T312461; Q312461)\nHost: www.nokko.com\nConnection: keep-alive\nAccept-encoding: gzip, deflate\n");
+            System.out.println(j.toString(2));
+            System.out.println(HTTP.toString(j));
+            System.out.println("");
+
+            j = HTTP.toJSONObject("HTTP/1.1 200 Oki Doki\nDate: Sun, 26 May 2002 17:38:52 GMT\nServer: Apache/1.3.23 (Unix) mod_perl/1.26\nKeep-Alive: timeout=15, max=100\nConnection: Keep-Alive\nTransfer-Encoding: chunked\nContent-Type: text/html\n");
+            System.out.println(j.toString(2));
+            System.out.println(HTTP.toString(j));
+            System.out.println("");
+
+            j = new JSONObject("{nix: null, nux: false, null: 'null', 'Request-URI': '/', Method: 'GET', 'HTTP-Version': 'HTTP/1.0'}");
+            System.out.println(j.toString(2));
+            System.out.println("isNull: " + j.isNull("nix"));
+            System.out.println("   has: " + j.has("nix"));
+            System.out.println(XML.toString(j));
+            System.out.println(HTTP.toString(j));
+            System.out.println("");
+
+            j = XML.toJSONObject("<?xml version='1.0' encoding='UTF-8'?>"+"\n\n"+"<SOAP-ENV:Envelope"+
+              " xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\""+
+              " xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\""+
+              " xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">"+
+              "<SOAP-ENV:Body><ns1:doGoogleSearch"+
+              " xmlns:ns1=\"urn:GoogleSearch\""+
+              " SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"+
+              "<key xsi:type=\"xsd:string\">GOOGLEKEY</key> <q"+
+              " xsi:type=\"xsd:string\">'+search+'</q> <start"+
+              " xsi:type=\"xsd:int\">0</start> <maxResults"+
+              " xsi:type=\"xsd:int\">10</maxResults> <filter"+
+              " xsi:type=\"xsd:boolean\">true</filter> <restrict"+
+              " xsi:type=\"xsd:string\"></restrict> <safeSearch"+
+              " xsi:type=\"xsd:boolean\">false</safeSearch> <lr"+
+              " xsi:type=\"xsd:string\"></lr> <ie"+
+              " xsi:type=\"xsd:string\">latin1</ie> <oe"+
+              " xsi:type=\"xsd:string\">latin1</oe>"+
+              "</ns1:doGoogleSearch>"+
+              "</SOAP-ENV:Body></SOAP-ENV:Envelope>");
+            System.out.println(j.toString(2));
+            System.out.println(XML.toString(j));
+            System.out.println("");
+
+            j = new JSONObject("{Envelope: {Body: {\"ns1:doGoogleSearch\": {oe: \"latin1\", filter: true, q: \"'+search+'\", key: \"GOOGLEKEY\", maxResults: 10, \"SOAP-ENV:encodingStyle\": \"http://schemas.xmlsoap.org/soap/encoding/\", start: 0, ie: \"latin1\", safeSearch:false, \"xmlns:ns1\": \"urn:GoogleSearch\"}}}}");
+            System.out.println(j.toString(2));
+            System.out.println(XML.toString(j));
+            System.out.println("");
+
+            j = CookieList.toJSONObject("  f%oo = b+l=ah  ; o;n%40e = t.wo ");
+            System.out.println(j.toString(2));
+            System.out.println(CookieList.toString(j));
+            System.out.println("");
+
+            j = Cookie.toJSONObject("f%oo=blah; secure ;expires = April 24, 2002");
+            System.out.println(j.toString(2));
+            System.out.println(Cookie.toString(j));
+            System.out.println("");
+
+            j = new JSONObject("{script: 'It is not allowed in HTML to send a close script tag in a string<script>because it confuses browsers</script>so we insert a backslash before the /'}");
+            System.out.println(j.toString());
+            System.out.println("");
+
+            JSONTokener jt = new JSONTokener("{op:'test', to:'session', pre:1}{op:'test', to:'session', pre:2}");
+            j = new JSONObject(jt);
+            System.out.println(j.toString());
+            System.out.println("pre: " + j.optInt("pre"));
+            int i = jt.skipTo('{');
+            System.out.println(i);
+            j = new JSONObject(jt);
+            System.out.println(j.toString());
+            System.out.println("");
+
+            a = CDL.toJSONArray("No quotes, 'Single Quotes', \"Double Quotes\"\n1,'2',\"3\"\n,'It is \"good,\"', \"It works.\"\n\n");
+
+            System.out.println(CDL.toString(a));
+            System.out.println("");
+            System.out.println(a.toString(4));
+            System.out.println("");
+
+            a = new JSONArray(" [\"<escape>\", next is an implied null , , ok,] ");
+            System.out.println(a.toString());
+            System.out.println("");
+            System.out.println(XML.toString(a));
+            System.out.println("");
+
+            j = new JSONObject("{ fun => with non-standard forms ; forgiving => This package can be used to parse formats that are similar to but not stricting conforming to JSON; why=To make it easier to migrate existing data to JSON,one = [[1.00]]; uno=[[{1=>1}]];'+':+6e66 ;pluses=+++;empty = '' , 'double':0.666,true: TRUE, false: FALSE, null=NULL;[true] = [[!,@;*]]; string=>  o. k. ; \r oct=0666; hex=0x666; dec=666; o=0999; noh=0x0x}");
+            System.out.println(j.toString(4));
+            System.out.println("");
+            if (j.getBoolean("true") && !j.getBoolean("false")) {
+                System.out.println("It's all good");
+            }
+
+            System.out.println("");
+            j = new JSONObject(j, new String[]{"dec", "oct", "hex", "missing"});
+            System.out.println(j.toString(4));
+
+            System.out.println("");
+            System.out.println(new JSONStringer().array().value(a).value(j).endArray());
+
+            j = new JSONObject("{string: \"98.6\", long: 2147483648, int: 2147483647, longer: 9223372036854775807, double: 9223372036854775808}");
+            System.out.println(j.toString(4));
+
+            System.out.println("\ngetInt");
+            System.out.println("int    " + j.getInt("int"));
+            System.out.println("long   " + j.getInt("long"));
+            System.out.println("longer " + j.getInt("longer"));
+            System.out.println("double " + j.getInt("double"));
+            System.out.println("string " + j.getInt("string"));
+
+            System.out.println("\ngetLong");
+            System.out.println("int    " + j.getLong("int"));
+            System.out.println("long   " + j.getLong("long"));
+            System.out.println("longer " + j.getLong("longer"));
+            System.out.println("double " + j.getLong("double"));
+            System.out.println("string " + j.getLong("string"));
+
+            System.out.println("\ngetDouble");
+            System.out.println("int    " + j.getDouble("int"));
+            System.out.println("long   " + j.getDouble("long"));
+            System.out.println("longer " + j.getDouble("longer"));
+            System.out.println("double " + j.getDouble("double"));
+            System.out.println("string " + j.getDouble("string"));
+
+            j.put("good sized", 9223372036854775807L);
+            System.out.println(j.toString(4));
+
+            a = new JSONArray("[2147483647, 2147483648, 9223372036854775807, 9223372036854775808]");
+            System.out.println(a.toString(4));
+
+            System.out.println("\nKeys: ");
+            it = j.keys();
+            while (it.hasNext()) {
+                s = (String)it.next();
+                System.out.println(s + ": " + j.getString(s));
+            }
+
+
+            System.out.println("\naccumulate: ");
+            j = new JSONObject();
+            j.accumulate("stooge", "Curly");
+            j.accumulate("stooge", "Larry");
+            j.accumulate("stooge", "Moe");
+            a = j.getJSONArray("stooge");
+            a.put(5, "Shemp");
+            System.out.println(j.toString(4));
+
+            System.out.println("\nwrite:");
+            System.out.println(j.write(new StringWriter()));
+
+            s = "<xml empty><a></a><a>1</a><a>22</a><a>333</a></xml>";
+            j = XML.toJSONObject(s);
+            System.out.println(j.toString(4));
+            System.out.println(XML.toString(j));
+            
+            s = "<book><chapter>Content of the first chapter</chapter><chapter>Content of the second chapter      <chapter>Content of the first subchapter</chapter>      <chapter>Content of the second subchapter</chapter></chapter><chapter>Third Chapter</chapter></book>";
+            j = XML.toJSONObject(s);
+            System.out.println(j.toString(4));
+            System.out.println(XML.toString(j));
+            
+            a = JSONML.toJSONArray(s);
+            System.out.println(a.toString(4));
+            System.out.println(JSONML.toString(a));
+            
+            Collection c = null;
+            Map m = null;
+            
+            j = new JSONObject(m);
+            a = new JSONArray(c);
+            j.append("stooge", "Joe DeRita");
+            j.append("stooge", "Shemp");
+            j.accumulate("stooges", "Curly");
+            j.accumulate("stooges", "Larry");
+            j.accumulate("stooges", "Moe");
+            j.accumulate("stoogearray", j.get("stooges"));
+            j.put("map", m);
+            j.put("collection", c);
+            j.put("array", a);
+            a.put(m);
+            a.put(c);
+            System.out.println(j.toString(4));
+            
+            s = "{plist=Apple; AnimalSmells = { pig = piggish; lamb = lambish; worm = wormy; }; AnimalSounds = { pig = oink; lamb = baa; worm = baa;  Lisa = \"Why is the worm talking like a lamb?\" } ; AnimalColors = { pig = pink; lamb = black; worm = pink; } } "; 
+            j = new JSONObject(s);
+            System.out.println(j.toString(4));
+            
+            s = " (\"San Francisco\", \"New York\", \"Seoul\", \"London\", \"Seattle\", \"Shanghai\")";
+            a = new JSONArray(s);
+            System.out.println(a.toString());
+            
+            s = "<a ichi='1' ni='2'><b>The content of b</b> and <c san='3'>The content of c</c><d>do</d><e></e><d>re</d><f/><d>mi</d></a>";
+            j = XML.toJSONObject(s);
+
+            System.out.println(j.toString(2));
+            System.out.println(XML.toString(j));
+            System.out.println("");
+            ja = JSONML.toJSONArray(s);
+            System.out.println(ja.toString(4));
+            System.out.println(JSONML.toString(ja));
+            System.out.println("");
+          
+            
+            System.out.println("\nTesting Exceptions: ");
+
+            System.out.print("Exception: ");
+            try {
+                a = new JSONArray();
+                a.put(Double.NEGATIVE_INFINITY);
+                a.put(Double.NaN);
+                System.out.println(a.toString());
+            } catch (Exception e) {
+                System.out.println(e);
+            }
+            System.out.print("Exception: ");
+            try {
+                System.out.println(j.getDouble("stooge"));
+            } catch (Exception e) {
+                System.out.println(e);
+            }
+            System.out.print("Exception: ");
+            try {
+                System.out.println(j.getDouble("howard"));
+            } catch (Exception e) {
+                System.out.println(e);
+            }
+            System.out.print("Exception: ");
+            try {
+                System.out.println(j.put(null, "howard"));
+            } catch (Exception e) {
+                System.out.println(e);
+            }
+            System.out.print("Exception: ");
+            try {
+                System.out.println(a.getDouble(0));
+            } catch (Exception e) {
+                System.out.println(e);
+            }
+            System.out.print("Exception: ");
+            try {
+                System.out.println(a.get(-1));
+            } catch (Exception e) {
+                System.out.println(e);
+            }
+            System.out.print("Exception: ");
+            try {
+                System.out.println(a.put(Double.NaN));
+            } catch (Exception e) {
+                System.out.println(e);
+            }
+            System.out.print("Exception: ");
+            try {
+            	j = XML.toJSONObject("<a><b>    ");
+            } catch (Exception e) {
+            	System.out.println(e);
+            }            
+            System.out.print("Exception: ");
+            try {
+            	j = XML.toJSONObject("<a></b>    ");
+            } catch (Exception e) {
+            	System.out.println(e);
+            }            
+            System.out.print("Exception: ");
+            try {
+            	j = XML.toJSONObject("<a></a    ");
+            } catch (Exception e) {
+            	System.out.println(e);
+            }
+            System.out.print("Exception: ");
+            try {            	
+            	ja = new JSONArray(new Object());
+            	System.out.println(ja.toString());
+            } catch (Exception e) {
+            	System.out.println(e);
+            }
+
+            System.out.print("Exception: ");
+            try {            	
+            	s = "[)";
+            	a = new JSONArray(s);
+            	System.out.println(a.toString());
+            } catch (Exception e) {
+            	System.out.println(e);
+            }
+
+            System.out.print("Exception: ");
+            try {            	
+                s = "<xml";
+                ja = JSONML.toJSONArray(s);
+                System.out.println(ja.toString(4));
+            } catch (Exception e) {
+            	System.out.println(e);
+            }
+
+            System.out.print("Exception: ");
+            try {            	
+                s = "<right></wrong>";
+                ja = JSONML.toJSONArray(s);
+                System.out.println(ja.toString(4));
+            } catch (Exception e) {
+            	System.out.println(e);
+            }
+
+            System.out.print("Exception: ");
+            try {            	
+                s = "{\"koda\": true, \"koda\": true}";
+                j = new JSONObject(s);
+                System.out.println(j.toString(4));
+            } catch (Exception e) {
+            	System.out.println(e);
+            }
+
+            System.out.print("Exception: ");
+            try {            	
+                jj = new JSONStringer();
+                s = jj
+    	            .object()
+    	                .key("bosanda")
+    	                .value("MARIE HAA'S")
+    	                .key("bosanda")
+    	                .value("MARIE HAA\\'S")
+    	            .endObject()
+    	            .toString();
+                System.out.println(j.toString(4));
+            } catch (Exception e) {
+            	System.out.println(e);
+            }
+        } catch (Exception e) {
+            System.out.println(e.toString());
+        }
+    }
+}
diff --git a/src/org/json/XML.java b/src/org/json/XML.java
new file mode 100644
index 0000000..4d95be4
--- /dev/null
+++ b/src/org/json/XML.java
@@ -0,0 +1,437 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.util.Iterator;
+
+
+/**
+ * This provides static methods to convert an XML text into a JSONObject,
+ * and to covert a JSONObject into an XML text.
+ * @author JSON.org
+ * @version 2008-10-14
+ */
+public class XML {
+
+    /** The Character '&'. */
+    public static final Character AMP   = new Character('&');
+
+    /** The Character '''. */
+    public static final Character APOS  = new Character('\'');
+
+    /** The Character '!'. */
+    public static final Character BANG  = new Character('!');
+
+    /** The Character '='. */
+    public static final Character EQ    = new Character('=');
+
+    /** The Character '>'. */
+    public static final Character GT    = new Character('>');
+
+    /** The Character '<'. */
+    public static final Character LT    = new Character('<');
+
+    /** The Character '?'. */
+    public static final Character QUEST = new Character('?');
+
+    /** The Character '"'. */
+    public static final Character QUOT  = new Character('"');
+
+    /** The Character '/'. */
+    public static final Character SLASH = new Character('/');
+
+    /**
+     * Replace special characters with XML escapes:
+     * <pre>
+     * & <small>(ampersand)</small> is replaced by &amp;
+     * < <small>(less than)</small> is replaced by &lt;
+     * > <small>(greater than)</small> is replaced by &gt;
+     * " <small>(double quote)</small> is replaced by &quot;
+     * </pre>
+     * @param string The string to be escaped.
+     * @return The escaped string.
+     */
+    public static String escape(String string) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0, len = string.length(); i < len; i++) {
+            char c = string.charAt(i);
+            switch (c) {
+            case '&':
+                sb.append("&");
+                break;
+            case '<':
+                sb.append("<");
+                break;
+            case '>':
+                sb.append(">");
+                break;
+            case '"':
+                sb.append(""");
+                break;
+            default:
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+    
+    /**
+     * Throw an exception if the string contains whitespace. 
+     * Whitespace is not allowed in tagNames and attributes.
+     * @param string
+     * @throws JSONException
+     */
+    public static void noSpace(String string) throws JSONException {
+    	int i, length = string.length();
+    	if (length == 0) {
+    		throw new JSONException("Empty string.");
+    	}
+    	for (i = 0; i < length; i += 1) {
+		    if (Character.isWhitespace(string.charAt(i))) {
+		    	throw new JSONException("'" + string + 
+		    			"' contains a space character.");
+		    }
+		}
+    }
+
+    /**
+     * Scan the content following the named tag, attaching it to the context.
+     * @param x       The XMLTokener containing the source string.
+     * @param context The JSONObject that will include the new material.
+     * @param name    The tag name.
+     * @return true if the close tag is processed.
+     * @throws JSONException
+     */
+    private static boolean parse(XMLTokener x, JSONObject context,
+                                 String name) throws JSONException {
+        char       c;
+        int        i;
+        String     n;
+        JSONObject o = null;
+        String     s;
+        Object     t;
+
+// Test for and skip past these forms:
+//      <!-- ... -->
+//      <!   ...   >
+//      <![  ... ]]>
+//      <?   ...  ?>
+// Report errors for these forms:
+//      <>
+//      <=
+//      <<
+
+        t = x.nextToken();
+
+// <!
+
+        if (t == BANG) {
+            c = x.next();
+            if (c == '-') {
+                if (x.next() == '-') {
+                    x.skipPast("-->");
+                    return false;
+                }
+                x.back();
+            } else if (c == '[') {
+                t = x.nextToken();
+                if (t.equals("CDATA")) {
+                    if (x.next() == '[') {
+                        s = x.nextCDATA();
+                        if (s.length() > 0) {
+                            context.accumulate("content", s);
+                        }
+                        return false;
+                    }
+                }
+                throw x.syntaxError("Expected 'CDATA['");
+            }
+            i = 1;
+            do {
+                t = x.nextMeta();
+                if (t == null) {
+                    throw x.syntaxError("Missing '>' after '<!'.");
+                } else if (t == LT) {
+                    i += 1;
+                } else if (t == GT) {
+                    i -= 1;
+                }
+            } while (i > 0);
+            return false;
+        } else if (t == QUEST) {
+
+// <?
+
+            x.skipPast("?>");
+            return false;
+        } else if (t == SLASH) {
+
+// Close tag </
+
+        	t = x.nextToken();
+            if (name == null) {
+                throw x.syntaxError("Mismatched close tag" + t);
+            }            
+            if (!t.equals(name)) {
+                throw x.syntaxError("Mismatched " + name + " and " + t);
+            }
+            if (x.nextToken() != GT) {
+                throw x.syntaxError("Misshaped close tag");
+            }
+            return true;
+
+        } else if (t instanceof Character) {
+            throw x.syntaxError("Misshaped tag");
+
+// Open tag <
+
+        } else {
+            n = (String)t;
+            t = null;
+            o = new JSONObject();
+            for (;;) {
+                if (t == null) {
+                    t = x.nextToken();
+                }
+
+// attribute = value
+
+                if (t instanceof String) {
+                    s = (String)t;
+                    t = x.nextToken();
+                    if (t == EQ) {
+                        t = x.nextToken();
+                        if (!(t instanceof String)) {
+                            throw x.syntaxError("Missing value");
+                        }
+                        o.accumulate(s, JSONObject.stringToValue((String)t));
+                        t = null;
+                    } else {
+                        o.accumulate(s, "");
+                    }
+
+// Empty tag <.../>
+
+                } else if (t == SLASH) {
+                    if (x.nextToken() != GT) {
+                        throw x.syntaxError("Misshaped tag");
+                    }
+                    context.accumulate(n, o);
+                    return false;
+
+// Content, between <...> and </...>
+
+                } else if (t == GT) {
+                    for (;;) {
+                        t = x.nextContent();
+                        if (t == null) {
+                            if (n != null) {
+                                throw x.syntaxError("Unclosed tag " + n);
+                            }
+                            return false;
+                        } else if (t instanceof String) {
+                            s = (String)t;
+                            if (s.length() > 0) {
+                                o.accumulate("content", JSONObject.stringToValue(s));
+                            }
+
+// Nested element
+
+                        } else if (t == LT) {
+                            if (parse(x, o, n)) {
+                                if (o.length() == 0) {
+                                    context.accumulate(n, "");
+                                } else if (o.length() == 1 &&
+                                       o.opt("content") != null) {
+                                    context.accumulate(n, o.opt("content"));
+                                } else {
+                                    context.accumulate(n, o);
+                                }
+                                return false;
+                            }
+                        }
+                    }
+                } else {
+                    throw x.syntaxError("Misshaped tag");
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Convert a well-formed (but not necessarily valid) XML string into a
+     * JSONObject. Some information may be lost in this transformation
+     * because JSON is a data format and XML is a document format. XML uses
+     * elements, attributes, and content text, while JSON uses unordered
+     * collections of name/value pairs and arrays of values. JSON does not
+     * does not like to distinguish between elements and attributes.
+     * Sequences of similar elements are represented as JSONArrays. Content
+     * text may be placed in a "content" member. Comments, prologs, DTDs, and
+     * <code><[ [ ]]></code> are ignored.
+     * @param string The source string.
+     * @return A JSONObject containing the structured data from the XML string.
+     * @throws JSONException
+     */
+    public static JSONObject toJSONObject(String string) throws JSONException {
+        JSONObject o = new JSONObject();
+        XMLTokener x = new XMLTokener(string);
+        while (x.more() && x.skipPast("<")) {
+            parse(x, o, null);
+        }
+        return o;
+    }
+
+
+    /**
+     * Convert a JSONObject into a well-formed, element-normal XML string.
+     * @param o A JSONObject.
+     * @return  A string.
+     * @throws  JSONException
+     */
+    public static String toString(Object o) throws JSONException {
+        return toString(o, null);
+    }
+
+
+    /**
+     * Convert a JSONObject into a well-formed, element-normal XML string.
+     * @param o A JSONObject.
+     * @param tagName The optional name of the enclosing tag.
+     * @return A string.
+     * @throws JSONException
+     */
+    public static String toString(Object o, String tagName)
+            throws JSONException {
+        StringBuffer b = new StringBuffer();
+        int          i;
+        JSONArray    ja;
+        JSONObject   jo;
+        String       k;
+        Iterator     keys;
+        int          len;
+        String       s;
+        Object       v;
+        if (o instanceof JSONObject) {
+
+// Emit <tagName>
+
+            if (tagName != null) {
+                b.append('<');
+                b.append(tagName);
+                b.append('>');
+            }
+
+// Loop thru the keys.
+
+            jo = (JSONObject)o;
+            keys = jo.keys();
+            while (keys.hasNext()) {
+                k = keys.next().toString();
+                v = jo.opt(k);
+                if (v == null) {
+                	v = "";
+                }
+                if (v instanceof String) {
+                    s = (String)v;
+                } else {
+                    s = null;
+                }
+
+// Emit content in body
+
+                if (k.equals("content")) {
+                    if (v instanceof JSONArray) {
+                        ja = (JSONArray)v;
+                        len = ja.length();
+                        for (i = 0; i < len; i += 1) {
+                            if (i > 0) {
+                                b.append('\n');
+                            }
+                            b.append(escape(ja.get(i).toString()));
+                        }
+                    } else {
+                        b.append(escape(v.toString()));
+                    }
+
+// Emit an array of similar keys
+
+                } else if (v instanceof JSONArray) {
+                    ja = (JSONArray)v;
+                    len = ja.length();
+                    for (i = 0; i < len; i += 1) {
+                    	v = ja.get(i);
+                    	if (v instanceof JSONArray) {
+                            b.append('<');
+                            b.append(k);
+                            b.append('>');
+                    		b.append(toString(v));
+                            b.append("</");
+                            b.append(k);
+                            b.append('>');
+                    	} else {
+                    		b.append(toString(v, k));
+                    	}
+                    }
+                } else if (v.equals("")) {
+                    b.append('<');
+                    b.append(k);
+                    b.append("/>");
+
+// Emit a new tag <k>
+
+                } else {
+                    b.append(toString(v, k));
+                }
+            }
+            if (tagName != null) {
+
+// Emit the </tagname> close tag
+
+                b.append("</");
+                b.append(tagName);
+                b.append('>');
+            }
+            return b.toString();
+
+// XML does not have good support for arrays. If an array appears in a place
+// where XML is lacking, synthesize an <array> element.
+
+        } else if (o instanceof JSONArray) {
+            ja = (JSONArray)o;
+            len = ja.length();
+            for (i = 0; i < len; ++i) {
+            	v = ja.opt(i);
+                b.append(toString(v, (tagName == null) ? "array" : tagName));
+            }
+            return b.toString();
+        } else {
+            s = (o == null) ? "null" : escape(o.toString());
+            return (tagName == null) ? "\"" + s + "\"" :
+                (s.length() == 0) ? "<" + tagName + "/>" :
+                "<" + tagName + ">" + s + "</" + tagName + ">";
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/org/json/XMLTokener.java b/src/org/json/XMLTokener.java
new file mode 100644
index 0000000..0f36084
--- /dev/null
+++ b/src/org/json/XMLTokener.java
@@ -0,0 +1,365 @@
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+/**
+ * The XMLTokener extends the JSONTokener to provide additional methods
+ * for the parsing of XML texts.
+ * @author JSON.org
+ * @version 2008-09-18
+ */
+public class XMLTokener extends JSONTokener {
+
+
+   /** The table of entity values. It initially contains Character values for
+    * amp, apos, gt, lt, quot.
+    */
+   public static final java.util.HashMap entity;
+
+   static {
+       entity = new java.util.HashMap(8);
+       entity.put("amp",  XML.AMP);
+       entity.put("apos", XML.APOS);
+       entity.put("gt",   XML.GT);
+       entity.put("lt",   XML.LT);
+       entity.put("quot", XML.QUOT);
+   }
+
+    /**
+     * Construct an XMLTokener from a string.
+     * @param s A source string.
+     */
+    public XMLTokener(String s) {
+        super(s);
+    }
+
+    /**
+     * Get the text in the CDATA block.
+     * @return The string up to the <code>]]></code>.
+     * @throws JSONException If the <code>]]></code> is not found.
+     */
+    public String nextCDATA() throws JSONException {
+        char         c;
+        int          i;
+        StringBuffer sb = new StringBuffer();
+        for (;;) {
+            c = next();
+            if (c == 0) {
+                throw syntaxError("Unclosed CDATA");
+            }
+            sb.append(c);
+            i = sb.length() - 3;
+            if (i >= 0 && sb.charAt(i) == ']' &&
+                          sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') {
+                sb.setLength(i);
+                return sb.toString();
+            }
+        }
+    }
+
+
+    /**
+     * Get the next XML outer token, trimming whitespace. There are two kinds
+     * of tokens: the '<' character which begins a markup tag, and the content
+     * text between markup tags.
+     *
+     * @return  A string, or a '<' Character, or null if there is no more
+     * source text.
+     * @throws JSONException
+     */
+    public Object nextContent() throws JSONException {
+        char         c;
+        StringBuffer sb;
+        do {
+            c = next();
+        } while (Character.isWhitespace(c));
+        if (c == 0) {
+            return null;
+        }
+        if (c == '<') {
+            return XML.LT;
+        }
+        sb = new StringBuffer();
+        for (;;) {
+            if (c == '<' || c == 0) {
+                back();
+                return sb.toString().trim();
+            }
+            if (c == '&') {
+                sb.append(nextEntity(c));
+            } else {
+                sb.append(c);
+            }
+            c = next();
+        }
+    }
+
+
+    /**
+     * Return the next entity. These entities are translated to Characters:
+     *     <code>&  '  >  <  "</code>.
+     * @param a An ampersand character.
+     * @return  A Character or an entity String if the entity is not recognized.
+     * @throws JSONException If missing ';' in XML entity.
+     */
+    public Object nextEntity(char a) throws JSONException {
+        StringBuffer sb = new StringBuffer();
+        for (;;) {
+            char c = next();
+            if (Character.isLetterOrDigit(c) || c == '#') {
+                sb.append(Character.toLowerCase(c));
+            } else if (c == ';') {
+                break;
+            } else {
+                throw syntaxError("Missing ';' in XML entity: &" + sb);
+            }
+        }
+        String s = sb.toString();
+        Object e = entity.get(s);
+        return e != null ? e : a + s + ";";
+    }
+
+
+    /**
+     * Returns the next XML meta token. This is used for skipping over <!...>
+     * and <?...?> structures.
+     * @return Syntax characters (<code>< > / = ! ?</code>) are returned as
+     *  Character, and strings and names are returned as Boolean. We don't care
+     *  what the values actually are.
+     * @throws JSONException If a string is not properly closed or if the XML
+     *  is badly structured.
+     */
+    public Object nextMeta() throws JSONException {
+        char c;
+        char q;
+        do {
+            c = next();
+        } while (Character.isWhitespace(c));
+        switch (c) {
+        case 0:
+            throw syntaxError("Misshaped meta tag");
+        case '<':
+            return XML.LT;
+        case '>':
+            return XML.GT;
+        case '/':
+            return XML.SLASH;
+        case '=':
+            return XML.EQ;
+        case '!':
+            return XML.BANG;
+        case '?':
+            return XML.QUEST;
+        case '"':
+        case '\'':
+            q = c;
+            for (;;) {
+                c = next();
+                if (c == 0) {
+                    throw syntaxError("Unterminated string");
+                }
+                if (c == q) {
+                    return Boolean.TRUE;
+                }
+            }
+        default:
+            for (;;) {
+                c = next();
+                if (Character.isWhitespace(c)) {
+                    return Boolean.TRUE;
+                }
+                switch (c) {
+                case 0:
+                case '<':
+                case '>':
+                case '/':
+                case '=':
+                case '!':
+                case '?':
+                case '"':
+                case '\'':
+                    back();
+                    return Boolean.TRUE;
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Get the next XML Token. These tokens are found inside of angle
+     * brackets. It may be one of these characters: <code>/ > = ! ?</code> or it
+     * may be a string wrapped in single quotes or double quotes, or it may be a
+     * name.
+     * @return a String or a Character.
+     * @throws JSONException If the XML is not well formed.
+     */
+    public Object nextToken() throws JSONException {
+        char c;
+        char q;
+        StringBuffer sb;
+        do {
+            c = next();
+        } while (Character.isWhitespace(c));
+        switch (c) {
+        case 0:
+            throw syntaxError("Misshaped element");
+        case '<':
+            throw syntaxError("Misplaced '<'");
+        case '>':
+            return XML.GT;
+        case '/':
+            return XML.SLASH;
+        case '=':
+            return XML.EQ;
+        case '!':
+            return XML.BANG;
+        case '?':
+            return XML.QUEST;
+
+// Quoted string
+
+        case '"':
+        case '\'':
+            q = c;
+            sb = new StringBuffer();
+            for (;;) {
+                c = next();
+                if (c == 0) {
+                    throw syntaxError("Unterminated string");
+                }
+                if (c == q) {
+                    return sb.toString();
+                }
+                if (c == '&') {
+                    sb.append(nextEntity(c));
+                } else {
+                    sb.append(c);
+                }
+            }
+        default:
+
+// Name
+
+            sb = new StringBuffer();
+            for (;;) {
+                sb.append(c);
+                c = next();
+                if (Character.isWhitespace(c)) {
+                    return sb.toString();
+                }
+                switch (c) {
+                case 0:
+                	return sb.toString();
+                case '>':
+                case '/':
+                case '=':
+                case '!':
+                case '?':
+                case '[':
+                case ']':
+                    back();
+                    return sb.toString();
+                case '<':
+                case '"':
+                case '\'':
+                    throw syntaxError("Bad character in a name");
+                }
+            }
+        }
+    }
+    
+    
+    /**
+     * Skip characters until past the requested string.
+     * If it is not found, we are left at the end of the source with a result of false.
+     * @param to A string to skip past.
+     * @throws JSONException
+     */
+    public boolean skipPast(String to) throws JSONException {
+    	boolean b;
+    	char c;
+    	int i;
+    	int j;
+    	int offset = 0;
+    	int n = to.length();
+        char[] circle = new char[n];
+        
+        /*
+         * First fill the circle buffer with as many characters as are in the
+         * to string. If we reach an early end, bail.
+         */
+        
+    	for (i = 0; i < n; i += 1) {
+    		c = next();
+    		if (c == 0) {
+    			return false;
+    		}
+    		circle[i] = c;
+    	}
+    	/*
+    	 * We will loop, possibly for all of the remaining characters.
+    	 */
+    	for (;;) {
+    		j = offset;
+    		b = true;
+    		/*
+    		 * Compare the circle buffer with the to string. 
+    		 */
+    		for (i = 0; i < n; i += 1) {
+    			if (circle[j] != to.charAt(i)) {
+    				b = false;
+    				break;
+    			}
+    			j += 1;
+    			if (j >= n) {
+    				j -= n;
+    			}
+    		}
+    		/*
+    		 * If we exit the loop with b intact, then victory is ours.
+    		 */
+    		if (b) {
+    			return true;
+    		}
+    		/*
+    		 * Get the next character. If there isn't one, then defeat is ours.
+    		 */
+    		c = next();
+    		if (c == 0) {
+    			return false;
+    		}
+    		/*
+    		 * Shove the character in the circle buffer and advance the 
+    		 * circle offset. The offset is mod n.
+    		 */
+    		circle[offset] = c;
+    		offset += 1;
+    		if (offset >= n) {
+    			offset -= n;
+    		}
+    	}
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/Alignment.java b/src/org/rki/sequenceeditor/model/Alignment.java
new file mode 100644
index 0000000..09e578d
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Alignment.java
@@ -0,0 +1,499 @@
+package org.rki.sequenceeditor.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Alignment {
+    public int tripletGrouping = -1;
+    private Settings _settings;
+    public MasterSequence masterSequenceAll = null;
+    public HashMap<GroupKey, MasterSequence> masterSequences = new HashMap<GroupKey, MasterSequence>();
+
+    
+    private ArrayList<Sequence> _sequences = new ArrayList<Sequence>();
+
+    public ArrayList<SNP> snps = new ArrayList<SNP>();
+	
+	public Alignment(Settings settings) {
+            _settings = settings;
+	}
+
+        public void setSettings(Settings settings) {
+            _settings = settings;
+        }
+
+        public Settings getSettings() {
+            return _settings;
+        }
+
+	public void addSequence(Sequence seq) {
+		_sequences.add(seq);
+	}
+	
+	public Sequence getSequence(int index) {
+            try {
+		return(_sequences.get(index));
+            } catch(IndexOutOfBoundsException e) {
+                return(null);
+            }
+	}
+	
+    public Collection<Sequence> getSequencesAll() {
+        return(_sequences);
+    }
+
+    public int getGroupFirst(GroupKey group) {        
+        for(int i=0; i<_sequences.size(); i++) {
+            if(_sequences.get(i).group == group) {
+                return(i);
+            }
+        }
+        return 0;
+    }
+
+	public Collection<Sequence> getSequences(GroupKey group) {
+            LinkedList<Sequence> seqs = new LinkedList<Sequence>();
+            for(Sequence s : _sequences) {
+                if(s.group == group) {
+                    seqs.add(s);
+                }
+            }
+            return(seqs);
+	}
+	
+        public Collection<GroupKey> getGroups() {
+            LinkedList<GroupKey> groups = new LinkedList<GroupKey>();
+            for(Sequence seq : _sequences) {
+                if(!groups.contains(seq.group)) {
+                    groups.add(seq.group);
+                }
+            }
+            return(groups);
+        }
+        
+        public int countAll() {
+            return(_sequences.size());            
+        }
+        
+	public int count(GroupKey group) {
+            return(getSequences(group).size());
+	}
+        
+        public int getLongestAll() {
+            int res = 0;
+            for(Sequence seq : _sequences) {
+                res = Math.max(res, seq.seq.length());
+            }
+            return(res);
+        }
+
+        public int getLongest(GroupKey group) {
+            int res = 0;
+            for(Sequence seq : getSequences(group)) {
+                res = Math.max(res, seq.seq.length());
+            }
+            return(res);
+        }
+
+        
+        public char[][] toCharArrayAll(int len) {
+            char[][] res = new char[countAll()][len];
+            int nseq = 0;
+            for(Sequence seq : _sequences) {
+                char[] s = seq.seq.toCharArray();
+                int pos = 0;
+                for(; pos<Math.min(len, s.length); pos++) {
+                    res[nseq][pos] = s[pos];
+                }
+                for(; pos<len; pos++) {
+                    res[nseq][pos] = '\0';
+                }
+                nseq ++;
+            }
+            return(res);
+        }
+
+        public char[][] toCharArray(int len, GroupKey group) {
+            char[][] res = new char[count(group)][len];
+            int nseq = 0;
+            for(Sequence seq :getSequences(group)) {
+                char[] s = seq.seq.toCharArray();
+                int pos = 0;
+                for(; pos<Math.min(len, s.length); pos++) {
+                    res[nseq][pos] = s[pos];
+                }
+                for(; pos<len; pos++) {
+                    res[nseq][pos] = '\0';
+                }
+                nseq ++;
+            }
+            return(res);
+        }
+        
+        public void moveSelected(int dist) {
+            LinkedList<Sequence> toMove = new LinkedList<Sequence>();
+            for(Sequence seq : _sequences) {
+                if(seq.selected) {
+                    if(dist < 0)
+                        toMove.add(seq);
+                    else 
+                        toMove.add(0, seq);
+                    int pos = _sequences.indexOf(seq);
+                    if(!seq.group.getName().equals(_sequences.get(pos+dist).group.getName())) {
+                        return;
+                    }
+                }
+            }
+            for(Sequence seq : toMove) {
+                int oldpos = _sequences.indexOf(seq);
+                _sequences.remove(oldpos);
+                _sequences.add(oldpos + dist, seq);
+            }
+        }
+
+        private String translateToRegexp(String sequence, boolean allowGaps) {
+            StringBuilder res = new StringBuilder();
+            char[] seq = sequence.toUpperCase().toCharArray();
+            for(char c : seq) {
+                switch(c) {
+                    case 'A':
+                        res.append("A");
+                        break;
+                    case 'G':
+                        res.append("G");
+                        break;
+                    case 'T':
+                        res.append("T");
+                        break;
+                    case 'C':
+                        res.append("C");
+                        break;
+                    case 'R':
+                        res.append("[AG]");
+                        break;
+                    case 'Y':
+                        res.append("[CT]");
+                        break;
+                    case 'M':
+                        res.append("[CA]");
+                        break;
+                    case 'K':
+                        res.append("[TG]");
+                        break;
+                    case 'W':
+                        res.append("[TA]");
+                        break;
+                    case 'S':
+                        res.append("[CG]");
+                        break;
+                    case 'B':
+                        res.append("[CTG]");
+                        break;
+                    case 'D':
+                        res.append("[ATG]");
+                        break;
+                    case 'H':
+                        res.append("[ATC]");
+                        break;
+                    case 'V':
+                        res.append("[ACG]");
+                        break;
+                    case 'N':
+                        res.append("[AGTC]");
+                        break;
+                }
+                if(allowGaps) {
+                    res.append("-*");
+                }
+            }
+            return res.toString();
+        }
+
+        public int[] findSubSequence(int fromSeq, int fromIndex, String sequence, boolean allowGaps) {
+            int[] res = {-1,-1, -1};
+            for(int i=fromSeq; i<_sequences.size(); i++) {
+                int from = 0;
+                if(i == fromSeq) {
+                    from = fromIndex;
+                }
+                Pattern search = Pattern.compile(translateToRegexp(sequence, allowGaps));
+                Matcher match = search.matcher(_sequences.get(i).seq);
+                if(match.find(from)) {
+                    res[0] = i;
+                    res[1] = match.start();
+                    res[2] = match.end() - match.start();
+                    return(res);
+                }
+/*                int pos = _sequences.get(i).seq.indexOf(sequence, from);
+                if(pos != -1) {
+                    res[0] = i;
+                    res[1] = pos;
+                    return(res);
+                }*/
+            }
+            return(res);
+        }
+        
+        public void sortGroups() {
+            Collections.sort(_sequences, new Comparator<Sequence>() {
+                @Override
+                public int compare(Sequence s1, Sequence s2) {
+                    return(s1.group.compareTo(s2.group));
+            }});            
+        }
+
+        public void sortByName() {
+            Collections.sort(_sequences, new Comparator<Sequence>() {
+                @Override
+                public int compare(Sequence s1, Sequence s2) {
+                    if(s1.group.compareTo(s2.group) == 0) {
+                        return(s1.name.toLowerCase().compareTo(s2.name.toLowerCase()));
+                    }
+                    return(s1.group.compareTo(s2.group)); 
+            }});
+        }
+
+        public void sortByHomology() {
+            Collections.sort(_sequences, new Comparator<Sequence>() {
+                @Override
+                public int compare(Sequence s1, Sequence s2) {
+                    if(s1.group.compareTo(s2.group) == 0) {
+                        return((int)Math.signum(s2.homology - s1.homology));
+                    }
+                    return(s1.group.compareTo(s2.group)); 
+            }});
+        }
+
+        public void sortByHomology(final int from, final int to) {
+            System.out.println(from + " : " + to);
+            Collections.sort(_sequences, new Comparator<Sequence>() {
+                public int compare(Sequence s1, Sequence s2) {
+                    if(s1.seq.length() < to || s2.seq.length() < to) {
+                        return s2.seq.length() - s1.seq.length();
+                    }
+                    if(s1.group.compareTo(s2.group) == 0) {
+                        byte[] seqs1 = s1.seq.substring(from, to).getBytes();
+                        byte[] seqs2 = s2.seq.substring(from, to).getBytes();
+                        int diffs = 0;
+                        int sign = 1;
+                        if(s1.seq.substring(from, to).compareTo(s2.seq.substring(from, to)) < 0) {
+                            sign = -1;
+                        }
+                        for(int i=0; i<seqs1.length; i++) {
+                            if(seqs1[i] != seqs2[i]) {
+                                diffs++;
+                            }
+                        }
+                        return(sign * diffs);
+                    }
+                    return(s1.group.compareTo(s2.group)); 
+            }});
+        }
+
+        public void calculateHomology(Sequence master) {
+            for(Sequence seq : _sequences) {
+                seq.calculateHomology(master);
+            }
+        }
+
+        public void toggleSnp(int pos) {
+            for(SNP snp : snps) {
+                if(snp.pos == pos) {
+                    snps.remove(snp);
+                    return;
+                }
+            }
+            snps.add(new SNP(pos));
+        }
+
+        public void setSnp(int pos) {
+            for(SNP snp : snps) {
+                if(snp.pos == pos) {
+                    return;
+                }
+            }
+            snps.add(new SNP(pos));
+        }
+
+        public Collection<Primer> getPrimers() {
+            ArrayList<Primer> primers = new ArrayList<Primer>();
+            for(Sequence seq : _sequences) {
+                for(Annotation a : seq.above.getAnnotations()) {
+                    if(a instanceof Primer) {
+                        primers.add((Primer)a);
+                    }
+                }
+                for(Annotation a : seq.below.getAnnotations()) {
+                    if(a instanceof Primer) {
+                        primers.add((Primer)a);
+                    }
+                }
+            }
+            return primers;
+        }
+
+        public Collection<Primer> getPyroPrimers() {
+            ArrayList<Primer> primers = new ArrayList<Primer>();
+            for(Sequence seq : _sequences) {
+                for(Annotation a : seq.above.getAnnotations()) {
+                    if(a instanceof Primer && ((Primer)a).isPyro) {
+                        primers.add((Primer)a);
+                    }
+                }
+                for(Annotation a : seq.below.getAnnotations()) {
+                    if(a instanceof Primer && ((Primer)a).isPyro) {
+                        primers.add((Primer)a);
+                    }
+                }
+            }
+            return primers;
+        }
+
+        public int[] getGroupScores(String seq, int from, GroupKey group) {
+            int[] scores = new int[seq.length()];
+            for(int i=0; i<seq.length(); i++) {
+                scores[i] = 100;
+                for(Sequence sequence : _sequences) {
+                    if(sequence.group.compareTo(group) != 0) {
+                        continue;
+                    }
+                    int cmpscore = compareBases(seq.charAt(i), sequence.seq.charAt(from+i));
+                    if(cmpscore < scores[i])
+                        scores[i] = cmpscore;
+                }
+            }
+            return scores;
+
+        }
+
+        public int[] getScores(String seq, int from) {
+            int[] scores = new int[seq.length()];
+            for(int i=0; i<seq.length(); i++) {
+                scores[i] = 100;
+                for(Sequence sequence : _sequences) {
+                    if(sequence.seq.length() <= from+i || seq.length() <= i)
+                        continue;
+                    int cmpscore = compareBases(seq.charAt(i), sequence.seq.charAt(from+i));
+                    if(cmpscore < scores[i])
+                        scores[i] = cmpscore;
+                }
+            }
+            return scores;
+        }
+
+        public int compareBases(char primer, char sequence) {
+            primer = Character.toLowerCase(primer);
+            sequence = Character.toLowerCase(sequence);
+            if(primer == sequence)
+                return 100;
+            switch(primer) {
+                case 'r':
+                    switch(sequence) {
+                        case 'a':
+                            return 80;
+                        case 'g':
+                            return 80;
+                        default:
+                            return 0;
+                    }
+                case 'm':
+                    switch(sequence) {
+                        case 'c':
+                            return 80;
+                        case 'a':
+                            return 80;
+                        default:
+                            return 0;
+                    }
+                case 's':
+                    switch(sequence) {
+                        case 'c':
+                            return 80;
+                        case 'g':
+                            return 80;
+                        default:
+                            return 0;
+                    }
+                case 'y':
+                    switch(sequence) {
+                        case 'c':
+                            return 80;
+                        case 't':
+                            return 80;
+                        default:
+                            return 0;
+                    }
+                case 'k':
+                    switch(sequence) {
+                        case 't':
+                            return 80;
+                        case 'g':
+                            return 80;
+                        default:
+                            return 0;
+                    }
+                case 'w':
+                    switch(sequence) {
+                        case 'a':
+                            return 80;
+                        case 't':
+                            return 80;
+                        default:
+                            return 0;
+                    }
+                case 'b':
+                    switch(sequence) {
+                        case 'c':
+                            return 65;
+                        case 't':
+                            return 65;
+                        case 'g':
+                            return 65;
+                        default:
+                            return 0;
+                    }
+                case 'd':
+                    switch(sequence) {
+                        case 'a':
+                            return 65;
+                        case 't':
+                            return 65;
+                        case 'g':
+                            return 65;
+                        default:
+                            return 0;
+                    }
+                case 'h':
+                    switch(sequence) {
+                        case 'a':
+                            return 65;
+                        case 't':
+                            return 65;
+                        case 'c':
+                            return 65;
+                        default:
+                            return 0;
+                    }
+                case 'v':
+                    switch(sequence) {
+                        case 'c':
+                            return 65;
+                        case 'a':
+                            return 65;
+                        case 'g':
+                            return 65;
+                        default:
+                            return 0;
+                    }
+                case 'n':
+                    return 50;
+            }
+            return 0;
+        }
+}
diff --git a/src/org/rki/sequenceeditor/model/Annotation.java b/src/org/rki/sequenceeditor/model/Annotation.java
new file mode 100644
index 0000000..9a8a7a0
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Annotation.java
@@ -0,0 +1,27 @@
+package org.rki.sequenceeditor.model;
+
+import java.awt.Color;
+
+public class Annotation {
+    public int from;
+    public int to;
+    public Color background;
+    public String text;
+    public AnnotationList list = null;
+    
+    public Annotation(int from, int to, Color background, String text, AnnotationList list) {
+        this.from = from;
+        this.to = to;
+        this.background = background;
+        this.text = text;
+        this.list = list;
+    }
+    
+    public void reset() {
+        list.resetAnnotation(this);
+    }
+
+    public String toString(boolean above) {
+        return "";
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/AnnotationList.java b/src/org/rki/sequenceeditor/model/AnnotationList.java
new file mode 100644
index 0000000..39fa844
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/AnnotationList.java
@@ -0,0 +1,117 @@
+package org.rki.sequenceeditor.model;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+public class AnnotationList {
+    public boolean above;
+    public LinkedList<LinkedList<Annotation>> levels = new LinkedList<LinkedList<Annotation>>();
+    public Sequence sequence;
+
+    public AnnotationList(boolean above, Sequence seq) {
+        this.above = above;
+        this.sequence = seq;
+    }
+    
+    private void addLevelWithAnnotation(Annotation anno) {
+        LinkedList<Annotation> level = new LinkedList<Annotation>();
+        level.add(anno);
+        levels.add(level);
+    }
+
+    private void addAnnotation(Annotation anno, boolean isNew) {        
+        if(levels.size() == 0) {
+            addLevelWithAnnotation(anno);
+            return;
+        }
+        boolean added = false;
+        for(LinkedList<Annotation> level : levels) {
+            boolean hitOnLevel = false;
+            for(Annotation a : level) {
+                if(a == anno) {
+                    continue;
+                }
+                if((anno.from >= a.from && anno.from <= a.to) || (anno.to >= a.from && anno.to <= a.to) ||
+                   (a.from >= anno.from && a.from <= anno.to) || (a.to >= anno.from && a.to <= anno.to)) {
+                    hitOnLevel = true;
+                    break;
+                }
+            }
+            if(!hitOnLevel) {
+                added = true;
+                if(!isNew) {
+                    removeAnnotation(anno);
+                }
+                level.add(anno);
+                break;
+            }
+        }
+        if(!added) {
+            if(!isNew) {
+                removeAnnotation(anno);
+            }
+            addLevelWithAnnotation(anno);
+        }
+    }
+    
+    public void addAnnotation(Annotation anno) {
+        anno.list = this;
+        addAnnotation(anno, true);
+    }
+
+    public void removeAnnotation(Annotation anno) {
+        for(LinkedList<Annotation> level : levels) {
+            boolean found = false;
+            for(Annotation a : level) {
+                if(a == anno) {
+                    found = true;
+                    break;
+                }
+            }
+            if(found) {
+                level.remove(anno);
+                break;
+            }
+        }
+        if(anno instanceof Primer) {
+            sequence.updateProducts();
+        }
+    }
+    
+    public void resetAnnotation(Annotation anno) {
+        addAnnotation(anno, false);
+    }
+    
+    public void resetAnnotations() {
+        LinkedList<LinkedList<Annotation>> tmplevels = new LinkedList<LinkedList<Annotation>>();
+        for(LinkedList<Annotation> level : levels) {
+            tmplevels.add((LinkedList<Annotation>)(level.clone()));
+        }
+        for(LinkedList<Annotation> level : tmplevels) {
+            for(Annotation anno : level) {
+                resetAnnotation(anno);
+            }
+        }
+        cleanupLevels();
+    }
+    
+    private void cleanupLevels() {        
+        LinkedList<LinkedList<Annotation>> toRemove = new LinkedList<LinkedList<Annotation>>();
+        for(LinkedList<Annotation> level : levels) {
+            if(level.size() == 0) {
+                toRemove.add(level);
+            }
+        }
+        for(LinkedList<Annotation> level : toRemove) {
+            levels.remove(level);
+        }
+    }
+
+    public Collection<Annotation> getAnnotations() {
+        LinkedList<Annotation> annotations = new LinkedList<Annotation>();
+        for(LinkedList<Annotation> level : levels) {
+            annotations.addAll(level);
+        }
+        return annotations;
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/Base64.java b/src/org/rki/sequenceeditor/model/Base64.java
new file mode 100644
index 0000000..abca0c8
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Base64.java
@@ -0,0 +1,2053 @@
+package org.rki.sequenceeditor.model;
+
+/**
+ * <p>Encodes and decodes to and from Base64 notation.</p>
+ * <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
+ * 
+ * <p>Example:</p>
+ * 
+ * <code>String encoded = Base64.encode( myByteArray );</code>
+ * <br />
+ * <code>byte[] myByteArray = Base64.decode( encoded );</code>
+ *
+ * <p>The <tt>options</tt> parameter, which appears in a few places, is used to pass 
+ * several pieces of information to the encoder. In the "higher level" methods such as 
+ * encodeBytes( bytes, options ) the options parameter can be used to indicate such 
+ * things as first gzipping the bytes before encoding them, not inserting linefeeds,
+ * and encoding using the URL-safe and Ordered dialects.</p>
+ *
+ * <p>Note, according to <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>,
+ * Section 2.1, implementations should not add line feeds unless explicitly told
+ * to do so. I've got Base64 set to this behavior now, although earlier versions
+ * broke lines by default.</p>
+ *
+ * <p>The constants defined in Base64 can be OR-ed together to combine options, so you 
+ * might make a call like this:</p>
+ *
+ * <code>String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES );</code>
+ * <p>to compress the data before encoding it and then making the output have newline characters.</p>
+ * <p>Also...</p>
+ * <code>String encoded = Base64.encodeBytes( crazyString.getBytes() );</code>
+ *
+ *
+ *
+ * <p>
+ * Change Log:
+ * </p>
+ * <ul>
+ *  <li>v2.3.5 - Fixed bug in {@link #encodeFromFile} where estimated buffer size
+ *   was wrong for files of size 31, 34, and 37 bytes.</li>
+ *  <li>v2.3.4 - Fixed bug when working with gzipped streams whereby flushing
+ *   the Base64.OutputStream closed the Base64 encoding (by padding with equals
+ *   signs) too soon. Also added an option to suppress the automatic decoding
+ *   of gzipped streams. Also added experimental support for specifying a
+ *   class loader when using the
+ *   {@link #decodeToObject(java.lang.String, int, java.lang.ClassLoader)}
+ *   method.</li>
+ *  <li>v2.3.3 - Changed default char encoding to US-ASCII which reduces the internal Java
+ *   footprint with its CharEncoders and so forth. Fixed some javadocs that were
+ *   inconsistent. Removed imports and specified things like java.io.IOException
+ *   explicitly inline.</li>
+ *  <li>v2.3.2 - Reduced memory footprint! Finally refined the "guessing" of how big the
+ *   final encoded data will be so that the code doesn't have to create two output
+ *   arrays: an oversized initial one and then a final, exact-sized one. Big win
+ *   when using the {@link #encodeBytesToBytes(byte[])} family of methods (and not
+ *   using the gzip options which uses a different mechanism with streams and stuff).</li>
+ *  <li>v2.3.1 - Added {@link #encodeBytesToBytes(byte[], int, int, int)} and some
+ *   similar helper methods to be more efficient with memory by not returning a
+ *   String but just a byte array.</li>
+ *  <li>v2.3 - <strong>This is not a drop-in replacement!</strong> This is two years of comments
+ *   and bug fixes queued up and finally executed. Thanks to everyone who sent
+ *   me stuff, and I'm sorry I wasn't able to distribute your fixes to everyone else.
+ *   Much bad coding was cleaned up including throwing exceptions where necessary 
+ *   instead of returning null values or something similar. Here are some changes
+ *   that may affect you:
+ *   <ul>
+ *    <li><em>Does not break lines, by default.</em> This is to keep in compliance with
+ *      <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>.</li>
+ *    <li><em>Throws exceptions instead of returning null values.</em> Because some operations
+ *      (especially those that may permit the GZIP option) use IO streams, there
+ *      is a possiblity of an java.io.IOException being thrown. After some discussion and
+ *      thought, I've changed the behavior of the methods to throw java.io.IOExceptions
+ *      rather than return null if ever there's an error. I think this is more
+ *      appropriate, though it will require some changes to your code. Sorry,
+ *      it should have been done this way to begin with.</li>
+ *    <li><em>Removed all references to System.out, System.err, and the like.</em>
+ *      Shame on me. All I can say is sorry they were ever there.</li>
+ *    <li><em>Throws NullPointerExceptions and IllegalArgumentExceptions</em> as needed
+ *      such as when passed arrays are null or offsets are invalid.</li>
+ *    <li>Cleaned up as much javadoc as I could to avoid any javadoc warnings.
+ *      This was especially annoying before for people who were thorough in their
+ *      own projects and then had gobs of javadoc warnings on this file.</li>
+ *   </ul>
+ *  <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug
+ *   when using very small files (~< 40 bytes).</li>
+ *  <li>v2.2 - Added some helper methods for encoding/decoding directly from
+ *   one file to the next. Also added a main() method to support command line
+ *   encoding/decoding from one file to the next. Also added these Base64 dialects:
+ *   <ol>
+ *   <li>The default is RFC3548 format.</li>
+ *   <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates
+ *   URL and file name friendly format as described in Section 4 of RFC3548.
+ *   http://www.faqs.org/rfcs/rfc3548.html</li>
+ *   <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates
+ *   URL and file name friendly format that preserves lexical ordering as described
+ *   in http://www.faqs.org/qa/rfcc-1940.html</li>
+ *   </ol>
+ *   Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>
+ *   for contributing the new Base64 dialects.
+ *  </li>
+ * 
+ *  <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
+ *   some convenience methods for reading and writing to and from files.</li>
+ *  <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
+ *   with other encodings (like EBCDIC).</li>
+ *  <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
+ *   encoded data was a single byte.</li>
+ *  <li>v2.0 - I got rid of methods that used booleans to set options. 
+ *   Now everything is more consolidated and cleaner. The code now detects
+ *   when data that's being decoded is gzip-compressed and will decompress it
+ *   automatically. Generally things are cleaner. You'll probably have to
+ *   change some method calls that you were making to support the new
+ *   options format (<tt>int</tt>s that you "OR" together).</li>
+ *  <li>v1.5.1 - Fixed bug when decompressing and decoding to a             
+ *   byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.      
+ *   Added the ability to "suspend" encoding in the Output Stream so        
+ *   you can turn on and off the encoding if you need to embed base64       
+ *   data in an otherwise "normal" stream (like an XML file).</li>  
+ *  <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.
+ *      This helps when using GZIP streams.
+ *      Added the ability to GZip-compress objects before encoding them.</li>
+ *  <li>v1.4 - Added helper methods to read/write files.</li>
+ *  <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
+ *  <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
+ *      where last buffer being read, if not completely full, was not returned.</li>
+ *  <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
+ *  <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
+ * </ul>
+ *
+ * <p>
+ * I am placing this code in the Public Domain. Do with it as you will.
+ * This software comes with no guarantees or warranties but with
+ * plenty of well-wishing instead!
+ * Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a>
+ * periodically to check for updates or to contribute improvements.
+ * </p>
+ *
+ * @author Robert Harder
+ * @author rob at iharder.net
+ * @version 2.3.5
+ */
+public class Base64
+{
+    
+/* ********  P U B L I C   F I E L D S  ******** */   
+    
+    
+    /** No options specified. Value is zero. */
+    public final static int NO_OPTIONS = 0;
+    
+    /** Specify encoding in first bit. Value is one. */
+    public final static int ENCODE = 1;
+    
+    
+    /** Specify decoding in first bit. Value is zero. */
+    public final static int DECODE = 0;
+    
+
+    /** Specify that data should be gzip-compressed in second bit. Value is two. */
+    public final static int GZIP = 2;
+
+    /** Specify that gzipped data should <em>not</em> be automatically gunzipped. */
+    public final static int DONT_GUNZIP = 4;
+    
+    
+    /** Do break lines when encoding. Value is 8. */
+    public final static int DO_BREAK_LINES = 8;
+	
+    /** 
+     * Encode using Base64-like encoding that is URL- and Filename-safe as described
+     * in Section 4 of RFC3548: 
+     * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
+     * It is important to note that data encoded this way is <em>not</em> officially valid Base64, 
+     * or at the very least should not be called Base64 without also specifying that is
+     * was encoded using the URL- and Filename-safe dialect.
+     */
+     public final static int URL_SAFE = 16;
+
+
+     /**
+      * Encode using the special "ordered" dialect of Base64 described here:
+      * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
+      */
+     public final static int ORDERED = 32;
+    
+    
+/* ********  P R I V A T E   F I E L D S  ******** */  
+    
+    
+    /** Maximum line length (76) of Base64 output. */
+    private final static int MAX_LINE_LENGTH = 76;
+    
+    
+    /** The equals sign (=) as a byte. */
+    private final static byte EQUALS_SIGN = (byte)'=';
+    
+    
+    /** The new line character (\n) as a byte. */
+    private final static byte NEW_LINE = (byte)'\n';
+    
+    
+    /** Preferred encoding. */
+    private final static String PREFERRED_ENCODING = "US-ASCII";
+    
+	
+    private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
+    private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
+	
+	
+/* ********  S T A N D A R D   B A S E 6 4   A L P H A B E T  ******** */	
+    
+    /** The 64 valid Base64 values. */
+    /* Host platform me be something funny like EBCDIC, so we hardcode these values. */
+    private final static byte[] _STANDARD_ALPHABET = {
+        (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+        (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+        (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', 
+        (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+        (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+        (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+        (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', 
+        (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+        (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', 
+        (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
+    };
+	
+    
+    /** 
+     * Translates a Base64 value to either its 6-bit reconstruction value
+     * or a negative number indicating some other meaning.
+     **/
+    private final static byte[] _STANDARD_DECODABET = {
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
+        -5,-5,                                      // Whitespace: Tab and Linefeed
+        -9,-9,                                      // Decimal 11 - 12
+        -5,                                         // Whitespace: Carriage Return
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
+        -9,-9,-9,-9,-9,                             // Decimal 27 - 31
+        -5,                                         // Whitespace: Space
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
+        62,                                         // Plus sign at decimal 43
+        -9,-9,-9,                                   // Decimal 44 - 46
+        63,                                         // Slash at decimal 47
+        52,53,54,55,56,57,58,59,60,61,              // Numbers zero through nine
+        -9,-9,-9,                                   // Decimal 58 - 60
+        -1,                                         // Equals sign at decimal 61
+        -9,-9,-9,                                      // Decimal 62 - 64
+        0,1,2,3,4,5,6,7,8,9,10,11,12,13,            // Letters 'A' through 'N'
+        14,15,16,17,18,19,20,21,22,23,24,25,        // Letters 'O' through 'Z'
+        -9,-9,-9,-9,-9,-9,                          // Decimal 91 - 96
+        26,27,28,29,30,31,32,33,34,35,36,37,38,     // Letters 'a' through 'm'
+        39,40,41,42,43,44,45,46,47,48,49,50,51,     // Letters 'n' through 'z'
+        -9,-9,-9,-9                                 // Decimal 123 - 126
+        /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
+    };
+	
+	
+/* ********  U R L   S A F E   B A S E 6 4   A L P H A B E T  ******** */
+	
+    /**
+     * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548: 
+     * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
+     * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."
+     */
+    private final static byte[] _URL_SAFE_ALPHABET = {
+      (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+      (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+      (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', 
+      (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+      (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+      (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+      (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', 
+      (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
+      (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', 
+      (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_'
+    };
+	
+    /**
+     * Used in decoding URL- and Filename-safe dialects of Base64.
+     */
+    private final static byte[] _URL_SAFE_DECODABET = {
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
+      -5,-5,                                      // Whitespace: Tab and Linefeed
+      -9,-9,                                      // Decimal 11 - 12
+      -5,                                         // Whitespace: Carriage Return
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
+      -9,-9,-9,-9,-9,                             // Decimal 27 - 31
+      -5,                                         // Whitespace: Space
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
+      -9,                                         // Plus sign at decimal 43
+      -9,                                         // Decimal 44
+      62,                                         // Minus sign at decimal 45
+      -9,                                         // Decimal 46
+      -9,                                         // Slash at decimal 47
+      52,53,54,55,56,57,58,59,60,61,              // Numbers zero through nine
+      -9,-9,-9,                                   // Decimal 58 - 60
+      -1,                                         // Equals sign at decimal 61
+      -9,-9,-9,                                   // Decimal 62 - 64
+      0,1,2,3,4,5,6,7,8,9,10,11,12,13,            // Letters 'A' through 'N'
+      14,15,16,17,18,19,20,21,22,23,24,25,        // Letters 'O' through 'Z'
+      -9,-9,-9,-9,                                // Decimal 91 - 94
+      63,                                         // Underscore at decimal 95
+      -9,                                         // Decimal 96
+      26,27,28,29,30,31,32,33,34,35,36,37,38,     // Letters 'a' through 'm'
+      39,40,41,42,43,44,45,46,47,48,49,50,51,     // Letters 'n' through 'z'
+      -9,-9,-9,-9                                 // Decimal 123 - 126
+      /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
+    };
+
+
+
+/* ********  O R D E R E D   B A S E 6 4   A L P H A B E T  ******** */
+
+    /**
+     * I don't get the point of this technique, but someone requested it,
+     * and it is described here:
+     * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
+     */
+    private final static byte[] _ORDERED_ALPHABET = {
+      (byte)'-',
+      (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
+      (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',
+      (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
+      (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
+      (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
+      (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
+      (byte)'_',
+      (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
+      (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
+      (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
+      (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z'
+    };
+	
+    /**
+     * Used in decoding the "ordered" dialect of Base64.
+     */
+    private final static byte[] _ORDERED_DECODABET = {
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
+      -5,-5,                                      // Whitespace: Tab and Linefeed
+      -9,-9,                                      // Decimal 11 - 12
+      -5,                                         // Whitespace: Carriage Return
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
+      -9,-9,-9,-9,-9,                             // Decimal 27 - 31
+      -5,                                         // Whitespace: Space
+      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
+      -9,                                         // Plus sign at decimal 43
+      -9,                                         // Decimal 44
+      0,                                          // Minus sign at decimal 45
+      -9,                                         // Decimal 46
+      -9,                                         // Slash at decimal 47
+      1,2,3,4,5,6,7,8,9,10,                       // Numbers zero through nine
+      -9,-9,-9,                                   // Decimal 58 - 60
+      -1,                                         // Equals sign at decimal 61
+      -9,-9,-9,                                   // Decimal 62 - 64
+      11,12,13,14,15,16,17,18,19,20,21,22,23,     // Letters 'A' through 'M'
+      24,25,26,27,28,29,30,31,32,33,34,35,36,     // Letters 'N' through 'Z'
+      -9,-9,-9,-9,                                // Decimal 91 - 94
+      37,                                         // Underscore at decimal 95
+      -9,                                         // Decimal 96
+      38,39,40,41,42,43,44,45,46,47,48,49,50,     // Letters 'a' through 'm'
+      51,52,53,54,55,56,57,58,59,60,61,62,63,     // Letters 'n' through 'z'
+      -9,-9,-9,-9                                 // Decimal 123 - 126
+      /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
+        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
+    };
+
+	
+/* ********  D E T E R M I N E   W H I C H   A L H A B E T  ******** */
+
+
+    /**
+     * Returns one of the _SOMETHING_ALPHABET byte arrays depending on
+     * the options specified.
+     * It's possible, though silly, to specify ORDERED <b>and</b> URLSAFE
+     * in which case one of them will be picked, though there is
+     * no guarantee as to which one will be picked.
+     */
+    private final static byte[] getAlphabet( int options ) {
+        if ((options & URL_SAFE) == URL_SAFE) {
+            return _URL_SAFE_ALPHABET;
+        } else if ((options & ORDERED) == ORDERED) {
+            return _ORDERED_ALPHABET;
+        } else {
+            return _STANDARD_ALPHABET;
+        }
+    }	// end getAlphabet
+
+
+    /**
+     * Returns one of the _SOMETHING_DECODABET byte arrays depending on
+     * the options specified.
+     * It's possible, though silly, to specify ORDERED and URL_SAFE
+     * in which case one of them will be picked, though there is
+     * no guarantee as to which one will be picked.
+     */
+    private final static byte[] getDecodabet( int options ) {
+        if( (options & URL_SAFE) == URL_SAFE) {
+            return _URL_SAFE_DECODABET;
+        } else if ((options & ORDERED) == ORDERED) {
+            return _ORDERED_DECODABET;
+        } else {
+            return _STANDARD_DECODABET;
+        }
+    }	// end getAlphabet
+
+
+    
+    /** Defeats instantiation. */
+    private Base64(){}
+    
+
+    
+    
+/* ********  E N C O D I N G   M E T H O D S  ******** */    
+    
+    
+    /**
+     * Encodes up to the first three bytes of array <var>threeBytes</var>
+     * and returns a four-byte array in Base64 notation.
+     * The actual number of significant bytes in your array is
+     * given by <var>numSigBytes</var>.
+     * The array <var>threeBytes</var> needs only be as big as
+     * <var>numSigBytes</var>.
+     * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
+     *
+     * @param b4 A reusable byte array to reduce array instantiation
+     * @param threeBytes the array to convert
+     * @param numSigBytes the number of significant bytes in your array
+     * @return four byte array in Base64 notation.
+     * @since 1.5.1
+     */
+    private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options ) {
+        encode3to4( threeBytes, 0, numSigBytes, b4, 0, options );
+        return b4;
+    }   // end encode3to4
+
+    
+    /**
+     * <p>Encodes up to three bytes of the array <var>source</var>
+     * and writes the resulting four Base64 bytes to <var>destination</var>.
+     * The source and destination arrays can be manipulated
+     * anywhere along their length by specifying 
+     * <var>srcOffset</var> and <var>destOffset</var>.
+     * This method does not check to make sure your arrays
+     * are large enough to accomodate <var>srcOffset</var> + 3 for
+     * the <var>source</var> array or <var>destOffset</var> + 4 for
+     * the <var>destination</var> array.
+     * The actual number of significant bytes in your array is
+     * given by <var>numSigBytes</var>.</p>
+	 * <p>This is the lowest level of the encoding methods with
+	 * all possible parameters.</p>
+     *
+     * @param source the array to convert
+     * @param srcOffset the index where conversion begins
+     * @param numSigBytes the number of significant bytes in your array
+     * @param destination the array to hold the conversion
+     * @param destOffset the index where output will be put
+     * @return the <var>destination</var> array
+     * @since 1.3
+     */
+    private static byte[] encode3to4( 
+    byte[] source, int srcOffset, int numSigBytes,
+    byte[] destination, int destOffset, int options ) {
+        
+	byte[] ALPHABET = getAlphabet( options ); 
+	
+        //           1         2         3  
+        // 01234567890123456789012345678901 Bit position
+        // --------000000001111111122222222 Array position from threeBytes
+        // --------|    ||    ||    ||    | Six bit groups to index ALPHABET
+        //          >>18  >>12  >> 6  >> 0  Right shift necessary
+        //                0x3f  0x3f  0x3f  Additional AND
+        
+        // Create buffer with zero-padding if there are only one or two
+        // significant bytes passed in the array.
+        // We have to shift left 24 in order to flush out the 1's that appear
+        // when Java treats a value as negative that is cast from a byte to an int.
+        int inBuff =   ( numSigBytes > 0 ? ((source[ srcOffset     ] << 24) >>>  8) : 0 )
+                     | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
+                     | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
+
+        switch( numSigBytes )
+        {
+            case 3:
+                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
+                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+                destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>>  6) & 0x3f ];
+                destination[ destOffset + 3 ] = ALPHABET[ (inBuff       ) & 0x3f ];
+                return destination;
+                
+            case 2:
+                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
+                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+                destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>>  6) & 0x3f ];
+                destination[ destOffset + 3 ] = EQUALS_SIGN;
+                return destination;
+                
+            case 1:
+                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
+                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
+                destination[ destOffset + 2 ] = EQUALS_SIGN;
+                destination[ destOffset + 3 ] = EQUALS_SIGN;
+                return destination;
+                
+            default:
+                return destination;
+        }   // end switch
+    }   // end encode3to4
+
+
+
+    /**
+     * Performs Base64 encoding on the <code>raw</code> ByteBuffer,
+     * writing it to the <code>encoded</code> ByteBuffer.
+     * This is an experimental feature. Currently it does not
+     * pass along any options (such as {@link #DO_BREAK_LINES}
+     * or {@link #GZIP}.
+     *
+     * @param raw input buffer
+     * @param encoded output buffer
+     * @since 2.3
+     */
+    public static void encode( java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded ){
+        byte[] raw3 = new byte[3];
+        byte[] enc4 = new byte[4];
+
+        while( raw.hasRemaining() ){
+            int rem = Math.min(3,raw.remaining());
+            raw.get(raw3,0,rem);
+            Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );
+            encoded.put(enc4);
+        }   // end input remaining
+    }
+
+
+    /**
+     * Performs Base64 encoding on the <code>raw</code> ByteBuffer,
+     * writing it to the <code>encoded</code> CharBuffer.
+     * This is an experimental feature. Currently it does not
+     * pass along any options (such as {@link #DO_BREAK_LINES}
+     * or {@link #GZIP}.
+     *
+     * @param raw input buffer
+     * @param encoded output buffer
+     * @since 2.3
+     */
+    public static void encode( java.nio.ByteBuffer raw, java.nio.CharBuffer encoded ){
+        byte[] raw3 = new byte[3];
+        byte[] enc4 = new byte[4];
+
+        while( raw.hasRemaining() ){
+            int rem = Math.min(3,raw.remaining());
+            raw.get(raw3,0,rem);
+            Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );
+            for( int i = 0; i < 4; i++ ){
+                encoded.put( (char)(enc4[i] & 0xFF) );
+            }
+        }   // end input remaining
+    }
+
+
+    
+    
+    /**
+     * Serializes an object and returns the Base64-encoded
+     * version of that serialized object.  
+     *  
+     * <p>As of v 2.3, if the object
+     * cannot be serialized or there is another error,
+     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+     * In earlier versions, it just returned a null value, but
+     * in retrospect that's a pretty poor way to handle it.</p>
+     * 
+     * The object is not GZip-compressed before being encoded.
+     *
+     * @param serializableObject The object to encode
+     * @return The Base64-encoded object
+     * @throws java.io.IOException if there is an error
+     * @throws NullPointerException if serializedObject is null
+     * @since 1.4
+     */
+    public static String encodeObject( java.io.Serializable serializableObject )
+    throws java.io.IOException {
+        return encodeObject( serializableObject, NO_OPTIONS );
+    }   // end encodeObject
+    
+
+
+    /**
+     * Serializes an object and returns the Base64-encoded
+     * version of that serialized object.
+     *  
+     * <p>As of v 2.3, if the object
+     * cannot be serialized or there is another error,
+     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+     * In earlier versions, it just returned a null value, but
+     * in retrospect that's a pretty poor way to handle it.</p>
+     * 
+     * The object is not GZip-compressed before being encoded.
+     * <p>
+     * Example options:<pre>
+     *   GZIP: gzip-compresses object before encoding it.
+     *   DO_BREAK_LINES: break lines at 76 characters
+     * </pre>
+     * <p>
+     * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
+     * <p>
+     * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
+     *
+     * @param serializableObject The object to encode
+     * @param options Specified options
+     * @return The Base64-encoded object
+     * @see Base64#GZIP
+     * @see Base64#DO_BREAK_LINES
+     * @throws java.io.IOException if there is an error
+     * @since 2.0
+     */
+    public static String encodeObject( java.io.Serializable serializableObject, int options )
+    throws java.io.IOException {
+
+        if( serializableObject == null ){
+            throw new NullPointerException( "Cannot serialize a null object." );
+        }   // end if: null
+        
+        // Streams
+        java.io.ByteArrayOutputStream  baos  = null; 
+        java.io.OutputStream           b64os = null;
+        java.util.zip.GZIPOutputStream gzos  = null;
+        java.io.ObjectOutputStream     oos   = null;
+        
+        
+        try {
+            // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
+            baos  = new java.io.ByteArrayOutputStream();
+            b64os = new Base64.OutputStream( baos, ENCODE | options );
+            if( (options & GZIP) != 0 ){
+                // Gzip
+                gzos = new java.util.zip.GZIPOutputStream(b64os);
+                oos = new java.io.ObjectOutputStream( gzos );
+            } else {
+                // Not gzipped
+                oos = new java.io.ObjectOutputStream( b64os );
+            }
+            oos.writeObject( serializableObject );
+        }   // end try
+        catch( java.io.IOException e ) {
+            // Catch it and then throw it immediately so that
+            // the finally{} block is called for cleanup.
+            throw e;
+        }   // end catch
+        finally {
+            try{ oos.close();   } catch( Exception e ){}
+            try{ gzos.close();  } catch( Exception e ){}
+            try{ b64os.close(); } catch( Exception e ){}
+            try{ baos.close();  } catch( Exception e ){}
+        }   // end finally
+        
+        // Return value according to relevant encoding.
+        try {
+            return new String( baos.toByteArray(), PREFERRED_ENCODING );
+        }   // end try
+        catch (java.io.UnsupportedEncodingException uue){
+            // Fall back to some Java default
+            return new String( baos.toByteArray() );
+        }   // end catch
+        
+    }   // end encode
+    
+    
+
+    /**
+     * Encodes a byte array into Base64 notation.
+     * Does not GZip-compress data.
+     *  
+     * @param source The data to convert
+     * @return The data in Base64-encoded form
+     * @throws NullPointerException if source array is null
+     * @since 1.4
+     */
+    public static String encodeBytes( byte[] source ) {
+        // Since we're not going to have the GZIP encoding turned on,
+        // we're not going to have an java.io.IOException thrown, so
+        // we should not force the user to have to catch it.
+        String encoded = null;
+        try {
+            encoded = encodeBytes(source, 0, source.length, NO_OPTIONS);
+        } catch (java.io.IOException ex) {
+            assert false : ex.getMessage();
+        }   // end catch
+        assert encoded != null;
+        return encoded;
+    }   // end encodeBytes
+    
+
+
+    /**
+     * Encodes a byte array into Base64 notation.
+     * <p>
+     * Example options:<pre>
+     *   GZIP: gzip-compresses object before encoding it.
+     *   DO_BREAK_LINES: break lines at 76 characters
+     *     <i>Note: Technically, this makes your encoding non-compliant.</i>
+     * </pre>
+     * <p>
+     * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
+     * <p>
+     * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
+     *
+     *  
+     * <p>As of v 2.3, if there is an error with the GZIP stream,
+     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+     * In earlier versions, it just returned a null value, but
+     * in retrospect that's a pretty poor way to handle it.</p>
+     * 
+     *
+     * @param source The data to convert
+     * @param options Specified options
+     * @return The Base64-encoded data as a String
+     * @see Base64#GZIP
+     * @see Base64#DO_BREAK_LINES
+     * @throws java.io.IOException if there is an error
+     * @throws NullPointerException if source array is null
+     * @since 2.0
+     */
+    public static String encodeBytes( byte[] source, int options ) throws java.io.IOException {
+        return encodeBytes( source, 0, source.length, options );
+    }   // end encodeBytes
+    
+    
+    /**
+     * Encodes a byte array into Base64 notation.
+     * Does not GZip-compress data.
+     *  
+     * <p>As of v 2.3, if there is an error,
+     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+     * In earlier versions, it just returned a null value, but
+     * in retrospect that's a pretty poor way to handle it.</p>
+     * 
+     *
+     * @param source The data to convert
+     * @param off Offset in array where conversion should begin
+     * @param len Length of data to convert
+     * @return The Base64-encoded data as a String
+     * @throws NullPointerException if source array is null
+     * @throws IllegalArgumentException if source array, offset, or length are invalid
+     * @since 1.4
+     */
+    public static String encodeBytes( byte[] source, int off, int len ) {
+        // Since we're not going to have the GZIP encoding turned on,
+        // we're not going to have an java.io.IOException thrown, so
+        // we should not force the user to have to catch it.
+        String encoded = null;
+        try {
+            encoded = encodeBytes( source, off, len, NO_OPTIONS );
+        } catch (java.io.IOException ex) {
+            assert false : ex.getMessage();
+        }   // end catch
+        assert encoded != null;
+        return encoded;
+    }   // end encodeBytes
+    
+    
+
+    /**
+     * Encodes a byte array into Base64 notation.
+     * <p>
+     * Example options:<pre>
+     *   GZIP: gzip-compresses object before encoding it.
+     *   DO_BREAK_LINES: break lines at 76 characters
+     *     <i>Note: Technically, this makes your encoding non-compliant.</i>
+     * </pre>
+     * <p>
+     * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
+     * <p>
+     * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
+     *
+     *  
+     * <p>As of v 2.3, if there is an error with the GZIP stream,
+     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+     * In earlier versions, it just returned a null value, but
+     * in retrospect that's a pretty poor way to handle it.</p>
+     * 
+     *
+     * @param source The data to convert
+     * @param off Offset in array where conversion should begin
+     * @param len Length of data to convert
+     * @param options Specified options
+     * @return The Base64-encoded data as a String
+     * @see Base64#GZIP
+     * @see Base64#DO_BREAK_LINES
+     * @throws java.io.IOException if there is an error
+     * @throws NullPointerException if source array is null
+     * @throws IllegalArgumentException if source array, offset, or length are invalid
+     * @since 2.0
+     */
+    public static String encodeBytes( byte[] source, int off, int len, int options ) throws java.io.IOException {
+        byte[] encoded = encodeBytesToBytes( source, off, len, options );
+
+        // Return value according to relevant encoding.
+        try {
+            return new String( encoded, PREFERRED_ENCODING );
+        }   // end try
+        catch (java.io.UnsupportedEncodingException uue) {
+            return new String( encoded );
+        }   // end catch
+        
+    }   // end encodeBytes
+
+
+
+
+    /**
+     * Similar to {@link #encodeBytes(byte[])} but returns
+     * a byte array instead of instantiating a String. This is more efficient
+     * if you're working with I/O streams and have large data sets to encode.
+     *
+     *
+     * @param source The data to convert
+     * @return The Base64-encoded data as a byte[] (of ASCII characters)
+     * @throws NullPointerException if source array is null
+     * @since 2.3.1
+     */
+    public static byte[] encodeBytesToBytes( byte[] source ) {
+        byte[] encoded = null;
+        try {
+            encoded = encodeBytesToBytes( source, 0, source.length, Base64.NO_OPTIONS );
+        } catch( java.io.IOException ex ) {
+            assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
+        }
+        return encoded;
+    }
+
+
+    /**
+     * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns
+     * a byte array instead of instantiating a String. This is more efficient
+     * if you're working with I/O streams and have large data sets to encode.
+     *
+     *
+     * @param source The data to convert
+     * @param off Offset in array where conversion should begin
+     * @param len Length of data to convert
+     * @param options Specified options
+     * @return The Base64-encoded data as a String
+     * @see Base64#GZIP
+     * @see Base64#DO_BREAK_LINES
+     * @throws java.io.IOException if there is an error
+     * @throws NullPointerException if source array is null
+     * @throws IllegalArgumentException if source array, offset, or length are invalid
+     * @since 2.3.1
+     */
+    public static byte[] encodeBytesToBytes( byte[] source, int off, int len, int options ) throws java.io.IOException {
+
+        if( source == null ){
+            throw new NullPointerException( "Cannot serialize a null array." );
+        }   // end if: null
+
+        if( off < 0 ){
+            throw new IllegalArgumentException( "Cannot have negative offset: " + off );
+        }   // end if: off < 0
+
+        if( len < 0 ){
+            throw new IllegalArgumentException( "Cannot have length offset: " + len );
+        }   // end if: len < 0
+
+        if( off + len > source.length  ){
+            throw new IllegalArgumentException(
+            String.format( "Cannot have offset of %d and length of %d with array of length %d", off,len,source.length));
+        }   // end if: off < 0
+
+
+
+        // Compress?
+        if( (options & GZIP) != 0 ) {
+            java.io.ByteArrayOutputStream  baos  = null;
+            java.util.zip.GZIPOutputStream gzos  = null;
+            Base64.OutputStream            b64os = null;
+
+            try {
+                // GZip -> Base64 -> ByteArray
+                baos = new java.io.ByteArrayOutputStream();
+                b64os = new Base64.OutputStream( baos, ENCODE | options );
+                gzos  = new java.util.zip.GZIPOutputStream( b64os );
+
+                gzos.write( source, off, len );
+                gzos.close();
+            }   // end try
+            catch( java.io.IOException e ) {
+                // Catch it and then throw it immediately so that
+                // the finally{} block is called for cleanup.
+                throw e;
+            }   // end catch
+            finally {
+                try{ gzos.close();  } catch( Exception e ){}
+                try{ b64os.close(); } catch( Exception e ){}
+                try{ baos.close();  } catch( Exception e ){}
+            }   // end finally
+
+            return baos.toByteArray();
+        }   // end if: compress
+
+        // Else, don't compress. Better not to use streams at all then.
+        else {
+            boolean breakLines = (options & DO_BREAK_LINES) > 0;
+
+            //int    len43   = len * 4 / 3;
+            //byte[] outBuff = new byte[   ( len43 )                      // Main 4:3
+            //                           + ( (len % 3) > 0 ? 4 : 0 )      // Account for padding
+            //                           + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
+            // Try to determine more precisely how big the array needs to be.
+            // If we get it right, we don't have to do an array copy, and
+            // we save a bunch of memory.
+            int encLen = ( len / 3 ) * 4 + ( len % 3 > 0 ? 4 : 0 ); // Bytes needed for actual encoding
+            if( breakLines ){
+                encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters
+            }
+            byte[] outBuff = new byte[ encLen ];
+
+
+            int d = 0;
+            int e = 0;
+            int len2 = len - 2;
+            int lineLength = 0;
+            for( ; d < len2; d+=3, e+=4 ) {
+                encode3to4( source, d+off, 3, outBuff, e, options );
+
+                lineLength += 4;
+                if( breakLines && lineLength >= MAX_LINE_LENGTH )
+                {
+                    outBuff[e+4] = NEW_LINE;
+                    e++;
+                    lineLength = 0;
+                }   // end if: end of line
+            }   // en dfor: each piece of array
+
+            if( d < len ) {
+                encode3to4( source, d+off, len - d, outBuff, e, options );
+                e += 4;
+            }   // end if: some padding needed
+
+
+            // Only resize array if we didn't guess it right.
+            if( e < outBuff.length - 1 ){
+                byte[] finalOut = new byte[e];
+                System.arraycopy(outBuff,0, finalOut,0,e);
+                //System.err.println("Having to resize array from " + outBuff.length + " to " + e );
+                return finalOut;
+            } else {
+                //System.err.println("No need to resize array.");
+                return outBuff;
+            }
+        
+        }   // end else: don't compress
+
+    }   // end encodeBytesToBytes
+    
+
+    
+    
+    
+/* ********  D E C O D I N G   M E T H O D S  ******** */
+    
+    
+    /**
+     * Decodes four bytes from array <var>source</var>
+     * and writes the resulting bytes (up to three of them)
+     * to <var>destination</var>.
+     * The source and destination arrays can be manipulated
+     * anywhere along their length by specifying 
+     * <var>srcOffset</var> and <var>destOffset</var>.
+     * This method does not check to make sure your arrays
+     * are large enough to accomodate <var>srcOffset</var> + 4 for
+     * the <var>source</var> array or <var>destOffset</var> + 3 for
+     * the <var>destination</var> array.
+     * This method returns the actual number of bytes that 
+     * were converted from the Base64 encoding.
+	 * <p>This is the lowest level of the decoding methods with
+	 * all possible parameters.</p>
+     * 
+     *
+     * @param source the array to convert
+     * @param srcOffset the index where conversion begins
+     * @param destination the array to hold the conversion
+     * @param destOffset the index where output will be put
+	 * @param options alphabet type is pulled from this (standard, url-safe, ordered)
+     * @return the number of decoded bytes converted
+     * @throws NullPointerException if source or destination arrays are null
+     * @throws IllegalArgumentException if srcOffset or destOffset are invalid
+     *         or there is not enough room in the array.
+     * @since 1.3
+     */
+    private static int decode4to3( 
+    byte[] source, int srcOffset, 
+    byte[] destination, int destOffset, int options ) {
+        
+        // Lots of error checking and exception throwing
+        if( source == null ){
+            throw new NullPointerException( "Source array was null." );
+        }   // end if
+        if( destination == null ){
+            throw new NullPointerException( "Destination array was null." );
+        }   // end if
+        if( srcOffset < 0 || srcOffset + 3 >= source.length ){
+            throw new IllegalArgumentException( String.format(
+            "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset ) );
+        }   // end if
+        if( destOffset < 0 || destOffset +2 >= destination.length ){
+            throw new IllegalArgumentException( String.format(
+            "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset ) );
+        }   // end if
+        
+        
+        byte[] DECODABET = getDecodabet( options ); 
+	
+        // Example: Dk==
+        if( source[ srcOffset + 2] == EQUALS_SIGN ) {
+            // Two ways to do the same thing. Don't know which way I like best.
+          //int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] << 24 ) >>>  6 )
+          //              | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
+            int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] & 0xFF ) << 18 )
+                          | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
+            
+            destination[ destOffset ] = (byte)( outBuff >>> 16 );
+            return 1;
+        }
+        
+        // Example: DkL=
+        else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) {
+            // Two ways to do the same thing. Don't know which way I like best.
+          //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
+          //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
+          //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
+            int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] & 0xFF ) << 18 )
+                          | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
+                          | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) <<  6 );
+            
+            destination[ destOffset     ] = (byte)( outBuff >>> 16 );
+            destination[ destOffset + 1 ] = (byte)( outBuff >>>  8 );
+            return 2;
+        }
+        
+        // Example: DkLE
+        else {
+            // Two ways to do the same thing. Don't know which way I like best.
+          //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
+          //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
+          //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
+          //              | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
+            int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] & 0xFF ) << 18 )
+                          | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
+                          | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) <<  6)
+                          | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF )      );
+
+            
+            destination[ destOffset     ] = (byte)( outBuff >> 16 );
+            destination[ destOffset + 1 ] = (byte)( outBuff >>  8 );
+            destination[ destOffset + 2 ] = (byte)( outBuff       );
+
+            return 3;
+        }
+    }   // end decodeToBytes
+    
+
+
+
+
+    /**
+     * Low-level access to decoding ASCII characters in
+     * the form of a byte array. <strong>Ignores GUNZIP option, if
+     * it's set.</strong> This is not generally a recommended method,
+     * although it is used internally as part of the decoding process.
+     * Special case: if len = 0, an empty array is returned. Still,
+     * if you need more speed and reduced memory footprint (and aren't
+     * gzipping), consider this method.
+     *
+     * @param source The Base64 encoded data
+     * @return decoded data
+     * @since 2.3.1
+     */
+    public static byte[] decode( byte[] source ){
+        byte[] decoded = null;
+        try {
+            decoded = decode( source, 0, source.length, Base64.NO_OPTIONS );
+        } catch( java.io.IOException ex ) {
+            assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
+        }
+        return decoded;
+    }
+
+    
+    
+    /**
+     * Low-level access to decoding ASCII characters in
+     * the form of a byte array. <strong>Ignores GUNZIP option, if
+     * it's set.</strong> This is not generally a recommended method,
+     * although it is used internally as part of the decoding process.
+     * Special case: if len = 0, an empty array is returned. Still,
+     * if you need more speed and reduced memory footprint (and aren't
+     * gzipping), consider this method.
+     *
+     * @param source The Base64 encoded data
+     * @param off    The offset of where to begin decoding
+     * @param len    The length of characters to decode
+     * @param options Can specify options such as alphabet type to use
+     * @return decoded data
+     * @throws java.io.IOException If bogus characters exist in source data
+     * @since 1.3
+     */
+    public static byte[] decode( byte[] source, int off, int len, int options )
+    throws java.io.IOException {
+        
+        // Lots of error checking and exception throwing
+        if( source == null ){
+            throw new NullPointerException( "Cannot decode null source array." );
+        }   // end if
+        if( off < 0 || off + len > source.length ){
+            throw new IllegalArgumentException( String.format(
+            "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, len ) );
+        }   // end if
+        
+        if( len == 0 ){
+            return new byte[0];
+        }else if( len < 4 ){
+            throw new IllegalArgumentException( 
+            "Base64-encoded string must have at least four characters, but length specified was " + len );
+        }   // end if
+        
+        byte[] DECODABET = getDecodabet( options );
+	
+        int    len34   = len * 3 / 4;       // Estimate on array size
+        byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output
+        int    outBuffPosn = 0;             // Keep track of where we're writing
+        
+        byte[] b4        = new byte[4];     // Four byte buffer from source, eliminating white space
+        int    b4Posn    = 0;               // Keep track of four byte input buffer
+        int    i         = 0;               // Source array counter
+        byte   sbiCrop   = 0;               // Low seven bits (ASCII) of input
+        byte   sbiDecode = 0;               // Special value from DECODABET
+        
+        for( i = off; i < off+len; i++ ) {  // Loop through source
+            
+            sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
+            sbiDecode = DECODABET[ sbiCrop ];   // Special value
+            
+            // White space, Equals sign, or legit Base64 character
+            // Note the values such as -5 and -9 in the
+            // DECODABETs at the top of the file.
+            if( sbiDecode >= WHITE_SPACE_ENC )  {
+                if( sbiDecode >= EQUALS_SIGN_ENC ) {
+                    b4[ b4Posn++ ] = sbiCrop;           // Save non-whitespace
+                    if( b4Posn > 3 ) {                  // Time to decode?
+                        outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );
+                        b4Posn = 0;
+                        
+                        // If that was the equals sign, break out of 'for' loop
+                        if( sbiCrop == EQUALS_SIGN ) {
+                            break;
+                        }   // end if: equals sign
+                    }   // end if: quartet built
+                }   // end if: equals sign or better
+            }   // end if: white space, equals sign or better
+            else {
+                // There's a bad input character in the Base64 stream.
+                throw new java.io.IOException( String.format(
+                "Bad Base64 input character '%c' in array position %d", source[i], i ) );
+            }   // end else: 
+        }   // each input character
+                                   
+        byte[] out = new byte[ outBuffPosn ];
+        System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); 
+        return out;
+    }   // end decode
+    
+    
+	
+	
+    /**
+     * Decodes data from Base64 notation, automatically
+     * detecting gzip-compressed data and decompressing it.
+     *
+     * @param s the string to decode
+     * @return the decoded data
+     * @throws java.io.IOException If there is a problem
+     * @since 1.4
+     */
+    public static byte[] decode( String s ) throws java.io.IOException {
+        return decode( s, NO_OPTIONS );
+    }
+
+    
+    
+    /**
+     * Decodes data from Base64 notation, automatically
+     * detecting gzip-compressed data and decompressing it.
+     *
+     * @param s the string to decode
+     * @param options encode options such as URL_SAFE
+     * @return the decoded data
+     * @throws java.io.IOException if there is an error
+     * @throws NullPointerException if <tt>s</tt> is null
+     * @since 1.4
+     */
+    public static byte[] decode( String s, int options ) throws java.io.IOException {
+        
+        if( s == null ){
+            throw new NullPointerException( "Input string was null." );
+        }   // end if
+        
+        byte[] bytes;
+        try {
+            bytes = s.getBytes( PREFERRED_ENCODING );
+        }   // end try
+        catch( java.io.UnsupportedEncodingException uee ) {
+            bytes = s.getBytes();
+        }   // end catch
+		//</change>
+        
+        // Decode
+        bytes = decode( bytes, 0, bytes.length, options );
+        
+        // Check to see if it's gzip-compressed
+        // GZIP Magic Two-Byte Number: 0x8b1f (35615)
+        boolean dontGunzip = (options & DONT_GUNZIP) != 0;
+        if( (bytes != null) && (bytes.length >= 4) && (!dontGunzip) ) {
+            
+            int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
+            if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head )  {
+                java.io.ByteArrayInputStream  bais = null;
+                java.util.zip.GZIPInputStream gzis = null;
+                java.io.ByteArrayOutputStream baos = null;
+                byte[] buffer = new byte[2048];
+                int    length = 0;
+
+                try {
+                    baos = new java.io.ByteArrayOutputStream();
+                    bais = new java.io.ByteArrayInputStream( bytes );
+                    gzis = new java.util.zip.GZIPInputStream( bais );
+
+                    while( ( length = gzis.read( buffer ) ) >= 0 ) {
+                        baos.write(buffer,0,length);
+                    }   // end while: reading input
+
+                    // No error? Get new bytes.
+                    bytes = baos.toByteArray();
+
+                }   // end try
+                catch( java.io.IOException e ) {
+                    e.printStackTrace();
+                    // Just return originally-decoded bytes
+                }   // end catch
+                finally {
+                    try{ baos.close(); } catch( Exception e ){}
+                    try{ gzis.close(); } catch( Exception e ){}
+                    try{ bais.close(); } catch( Exception e ){}
+                }   // end finally
+
+            }   // end if: gzipped
+        }   // end if: bytes.length >= 2
+        
+        return bytes;
+    }   // end decode
+
+
+
+    /**
+     * Attempts to decode Base64 data and deserialize a Java
+     * Object within. Returns <tt>null</tt> if there was an error.
+     *
+     * @param encodedObject The Base64 data to decode
+     * @return The decoded and deserialized object
+     * @throws NullPointerException if encodedObject is null
+     * @throws java.io.IOException if there is a general error
+     * @throws ClassNotFoundException if the decoded object is of a
+     *         class that cannot be found by the JVM
+     * @since 1.5
+     */
+    public static Object decodeToObject( String encodedObject )
+    throws java.io.IOException, java.lang.ClassNotFoundException {
+        return decodeToObject(encodedObject,NO_OPTIONS,null);
+    }
+    
+
+    /**
+     * Attempts to decode Base64 data and deserialize a Java
+     * Object within. Returns <tt>null</tt> if there was an error.
+     * If <tt>loader</tt> is not null, it will be the class loader
+     * used when deserializing.
+     *
+     * @param encodedObject The Base64 data to decode
+     * @param options Various parameters related to decoding
+     * @param loader Optional class loader to use in deserializing classes.
+     * @return The decoded and deserialized object
+     * @throws NullPointerException if encodedObject is null
+     * @throws java.io.IOException if there is a general error
+     * @throws ClassNotFoundException if the decoded object is of a 
+     *         class that cannot be found by the JVM
+     * @since 2.3.4
+     */
+    public static Object decodeToObject( 
+    String encodedObject, int options, final ClassLoader loader )
+    throws java.io.IOException, java.lang.ClassNotFoundException {
+        
+        // Decode and gunzip if necessary
+        byte[] objBytes = decode( encodedObject, options );
+        
+        java.io.ByteArrayInputStream  bais = null;
+        java.io.ObjectInputStream     ois  = null;
+        Object obj = null;
+        
+        try {
+            bais = new java.io.ByteArrayInputStream( objBytes );
+
+            // If no custom class loader is provided, use Java's builtin OIS.
+            if( loader == null ){
+                ois  = new java.io.ObjectInputStream( bais );
+            }   // end if: no loader provided
+
+            // Else make a customized object input stream that uses
+            // the provided class loader.
+            else {
+                ois = new java.io.ObjectInputStream(bais){
+                    @Override
+                    public Class<?> resolveClass(java.io.ObjectStreamClass streamClass)
+                    throws java.io.IOException, ClassNotFoundException {
+                        Class c = Class.forName(streamClass.getName(), false, loader);
+                        if( c == null ){
+                            return super.resolveClass(streamClass);
+                        } else {
+                            return c;   // Class loader knows of this class.
+                        }   // end else: not null
+                    }   // end resolveClass
+                };  // end ois
+            }   // end else: no custom class loader
+        
+            obj = ois.readObject();
+        }   // end try
+        catch( java.io.IOException e ) {
+            throw e;    // Catch and throw in order to execute finally{}
+        }   // end catch
+        catch( java.lang.ClassNotFoundException e ) {
+            throw e;    // Catch and throw in order to execute finally{}
+        }   // end catch
+        finally {
+            try{ bais.close(); } catch( Exception e ){}
+            try{ ois.close();  } catch( Exception e ){}
+        }   // end finally
+        
+        return obj;
+    }   // end decodeObject
+    
+    
+    
+    /**
+     * Convenience method for encoding data to a file.
+     *
+     * <p>As of v 2.3, if there is a error,
+     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+     * In earlier versions, it just returned false, but
+     * in retrospect that's a pretty poor way to handle it.</p>
+     * 
+     * @param dataToEncode byte array of data to encode in base64 form
+     * @param filename Filename for saving encoded data
+     * @throws java.io.IOException if there is an error
+     * @throws NullPointerException if dataToEncode is null
+     * @since 2.1
+     */
+    public static void encodeToFile( byte[] dataToEncode, String filename )
+    throws java.io.IOException {
+        
+        if( dataToEncode == null ){
+            throw new NullPointerException( "Data to encode was null." );
+        }   // end iff
+        
+        Base64.OutputStream bos = null;
+        try {
+            bos = new Base64.OutputStream( 
+                  new java.io.FileOutputStream( filename ), Base64.ENCODE );
+            bos.write( dataToEncode );
+        }   // end try
+        catch( java.io.IOException e ) {
+            throw e; // Catch and throw to execute finally{} block
+        }   // end catch: java.io.IOException
+        finally {
+            try{ bos.close(); } catch( Exception e ){}
+        }   // end finally
+        
+    }   // end encodeToFile
+    
+    
+    /**
+     * Convenience method for decoding data to a file.
+     *
+     * <p>As of v 2.3, if there is a error,
+     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+     * In earlier versions, it just returned false, but
+     * in retrospect that's a pretty poor way to handle it.</p>
+     * 
+     * @param dataToDecode Base64-encoded data as a string
+     * @param filename Filename for saving decoded data
+     * @throws java.io.IOException if there is an error
+     * @since 2.1
+     */
+    public static void decodeToFile( String dataToDecode, String filename )
+    throws java.io.IOException {
+        
+        Base64.OutputStream bos = null;
+        try{
+            bos = new Base64.OutputStream( 
+                      new java.io.FileOutputStream( filename ), Base64.DECODE );
+            bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) );
+        }   // end try
+        catch( java.io.IOException e ) {
+            throw e; // Catch and throw to execute finally{} block
+        }   // end catch: java.io.IOException
+        finally {
+                try{ bos.close(); } catch( Exception e ){}
+        }   // end finally
+        
+    }   // end decodeToFile
+    
+    
+    
+    
+    /**
+     * Convenience method for reading a base64-encoded
+     * file and decoding it.
+     *
+     * <p>As of v 2.3, if there is a error,
+     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+     * In earlier versions, it just returned false, but
+     * in retrospect that's a pretty poor way to handle it.</p>
+     * 
+     * @param filename Filename for reading encoded data
+     * @return decoded byte array
+     * @throws java.io.IOException if there is an error
+     * @since 2.1
+     */
+    public static byte[] decodeFromFile( String filename )
+    throws java.io.IOException {
+        
+        byte[] decodedData = null;
+        Base64.InputStream bis = null;
+        try
+        {
+            // Set up some useful variables
+            java.io.File file = new java.io.File( filename );
+            byte[] buffer = null;
+            int length   = 0;
+            int numBytes = 0;
+            
+            // Check for size of file
+            if( file.length() > Integer.MAX_VALUE )
+            {
+                throw new java.io.IOException( "File is too big for this convenience method (" + file.length() + " bytes)." );
+            }   // end if: file too big for int index
+            buffer = new byte[ (int)file.length() ];
+            
+            // Open a stream
+            bis = new Base64.InputStream( 
+                      new java.io.BufferedInputStream( 
+                      new java.io.FileInputStream( file ) ), Base64.DECODE );
+            
+            // Read until done
+            while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) {
+                length += numBytes;
+            }   // end while
+            
+            // Save in a variable to return
+            decodedData = new byte[ length ];
+            System.arraycopy( buffer, 0, decodedData, 0, length );
+            
+        }   // end try
+        catch( java.io.IOException e ) {
+            throw e; // Catch and release to execute finally{}
+        }   // end catch: java.io.IOException
+        finally {
+            try{ bis.close(); } catch( Exception e) {}
+        }   // end finally
+        
+        return decodedData;
+    }   // end decodeFromFile
+    
+    
+    
+    /**
+     * Convenience method for reading a binary file
+     * and base64-encoding it.
+     *
+     * <p>As of v 2.3, if there is a error,
+     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
+     * In earlier versions, it just returned false, but
+     * in retrospect that's a pretty poor way to handle it.</p>
+     * 
+     * @param filename Filename for reading binary data
+     * @return base64-encoded string
+     * @throws java.io.IOException if there is an error
+     * @since 2.1
+     */
+    public static String encodeFromFile( String filename )
+    throws java.io.IOException {
+        
+        String encodedData = null;
+        Base64.InputStream bis = null;
+        try
+        {
+            // Set up some useful variables
+            java.io.File file = new java.io.File( filename );
+            byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4+1),40) ]; // Need max() for math on small files (v2.2.1); Need +1 for a few corner cases (v2.3.5)
+            int length   = 0;
+            int numBytes = 0;
+            
+            // Open a stream
+            bis = new Base64.InputStream( 
+                      new java.io.BufferedInputStream( 
+                      new java.io.FileInputStream( file ) ), Base64.ENCODE );
+            
+            // Read until done
+            while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 ) {
+                length += numBytes;
+            }   // end while
+            
+            // Save in a variable to return
+            encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING );
+                
+        }   // end try
+        catch( java.io.IOException e ) {
+            throw e; // Catch and release to execute finally{}
+        }   // end catch: java.io.IOException
+        finally {
+            try{ bis.close(); } catch( Exception e) {}
+        }   // end finally
+        
+        return encodedData;
+        }   // end encodeFromFile
+    
+    /**
+     * Reads <tt>infile</tt> and encodes it to <tt>outfile</tt>.
+     *
+     * @param infile Input file
+     * @param outfile Output file
+     * @throws java.io.IOException if there is an error
+     * @since 2.2
+     */
+    public static void encodeFileToFile( String infile, String outfile )
+    throws java.io.IOException {
+        
+        String encoded = Base64.encodeFromFile( infile );
+        java.io.OutputStream out = null;
+        try{
+            out = new java.io.BufferedOutputStream(
+                  new java.io.FileOutputStream( outfile ) );
+            out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output.
+        }   // end try
+        catch( java.io.IOException e ) {
+            throw e; // Catch and release to execute finally{}
+        }   // end catch
+        finally {
+            try { out.close(); }
+            catch( Exception ex ){}
+        }   // end finally    
+    }   // end encodeFileToFile
+
+
+    /**
+     * Reads <tt>infile</tt> and decodes it to <tt>outfile</tt>.
+     *
+     * @param infile Input file
+     * @param outfile Output file
+     * @throws java.io.IOException if there is an error
+     * @since 2.2
+     */
+    public static void decodeFileToFile( String infile, String outfile )
+    throws java.io.IOException {
+        
+        byte[] decoded = Base64.decodeFromFile( infile );
+        java.io.OutputStream out = null;
+        try{
+            out = new java.io.BufferedOutputStream(
+                  new java.io.FileOutputStream( outfile ) );
+            out.write( decoded );
+        }   // end try
+        catch( java.io.IOException e ) {
+            throw e; // Catch and release to execute finally{}
+        }   // end catch
+        finally {
+            try { out.close(); }
+            catch( Exception ex ){}
+        }   // end finally    
+    }   // end decodeFileToFile
+    
+    
+    /* ********  I N N E R   C L A S S   I N P U T S T R E A M  ******** */
+    
+    
+    
+    /**
+     * A {@link Base64.InputStream} will read data from another
+     * <tt>java.io.InputStream</tt>, given in the constructor,
+     * and encode/decode to/from Base64 notation on the fly.
+     *
+     * @see Base64
+     * @since 1.3
+     */
+    public static class InputStream extends java.io.FilterInputStream {
+        
+        private boolean encode;         // Encoding or decoding
+        private int     position;       // Current position in the buffer
+        private byte[]  buffer;         // Small buffer holding converted data
+        private int     bufferLength;   // Length of buffer (3 or 4)
+        private int     numSigBytes;    // Number of meaningful bytes in the buffer
+        private int     lineLength;
+        private boolean breakLines;     // Break lines at less than 80 characters
+        private int     options;        // Record options used to create the stream.
+        private byte[]  decodabet;      // Local copies to avoid extra method calls
+        
+        
+        /**
+         * Constructs a {@link Base64.InputStream} in DECODE mode.
+         *
+         * @param in the <tt>java.io.InputStream</tt> from which to read data.
+         * @since 1.3
+         */
+        public InputStream( java.io.InputStream in ) {
+            this( in, DECODE );
+        }   // end constructor
+        
+        
+        /**
+         * Constructs a {@link Base64.InputStream} in
+         * either ENCODE or DECODE mode.
+         * <p>
+         * Valid options:<pre>
+         *   ENCODE or DECODE: Encode or Decode as data is read.
+         *   DO_BREAK_LINES: break lines at 76 characters
+         *     (only meaningful when encoding)</i>
+         * </pre>
+         * <p>
+         * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
+         *
+         *
+         * @param in the <tt>java.io.InputStream</tt> from which to read data.
+         * @param options Specified options
+         * @see Base64#ENCODE
+         * @see Base64#DECODE
+         * @see Base64#DO_BREAK_LINES
+         * @since 2.0
+         */
+        public InputStream( java.io.InputStream in, int options ) {
+            
+            super( in );
+            this.options      = options; // Record for later
+            this.breakLines   = (options & DO_BREAK_LINES) > 0;
+            this.encode       = (options & ENCODE) > 0;
+            this.bufferLength = encode ? 4 : 3;
+            this.buffer       = new byte[ bufferLength ];
+            this.position     = -1;
+            this.lineLength   = 0;
+            this.decodabet    = getDecodabet(options);
+        }   // end constructor
+        
+        /**
+         * Reads enough of the input stream to convert
+         * to/from Base64 and returns the next byte.
+         *
+         * @return next byte
+         * @since 1.3
+         */
+        @Override
+        public int read() throws java.io.IOException  {
+            
+            // Do we need to get data?
+            if( position < 0 ) {
+                if( encode ) {
+                    byte[] b3 = new byte[3];
+                    int numBinaryBytes = 0;
+                    for( int i = 0; i < 3; i++ ) {
+                        int b = in.read();
+
+                        // If end of stream, b is -1.
+                        if( b >= 0 ) {
+                            b3[i] = (byte)b;
+                            numBinaryBytes++;
+                        } else {
+                            break; // out of for loop
+                        }   // end else: end of stream
+                            
+                    }   // end for: each needed input byte
+                    
+                    if( numBinaryBytes > 0 ) {
+                        encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
+                        position = 0;
+                        numSigBytes = 4;
+                    }   // end if: got data
+                    else {
+                        return -1;  // Must be end of stream
+                    }   // end else
+                }   // end if: encoding
+                
+                // Else decoding
+                else {
+                    byte[] b4 = new byte[4];
+                    int i = 0;
+                    for( i = 0; i < 4; i++ ) {
+                        // Read four "meaningful" bytes:
+                        int b = 0;
+                        do{ b = in.read(); }
+                        while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
+                        
+                        if( b < 0 ) {
+                            break; // Reads a -1 if end of stream
+                        }   // end if: end of stream
+                        
+                        b4[i] = (byte)b;
+                    }   // end for: each needed input byte
+                    
+                    if( i == 4 ) {
+                        numSigBytes = decode4to3( b4, 0, buffer, 0, options );
+                        position = 0;
+                    }   // end if: got four characters
+                    else if( i == 0 ){
+                        return -1;
+                    }   // end else if: also padded correctly
+                    else {
+                        // Must have broken out from above.
+                        throw new java.io.IOException( "Improperly padded Base64 input." );
+                    }   // end 
+                    
+                }   // end else: decode
+            }   // end else: get data
+            
+            // Got data?
+            if( position >= 0 ) {
+                // End of relevant data?
+                if( /*!encode &&*/ position >= numSigBytes ){
+                    return -1;
+                }   // end if: got data
+                
+                if( encode && breakLines && lineLength >= MAX_LINE_LENGTH ) {
+                    lineLength = 0;
+                    return '\n';
+                }   // end if
+                else {
+                    lineLength++;   // This isn't important when decoding
+                                    // but throwing an extra "if" seems
+                                    // just as wasteful.
+                    
+                    int b = buffer[ position++ ];
+
+                    if( position >= bufferLength ) {
+                        position = -1;
+                    }   // end if: end
+
+                    return b & 0xFF; // This is how you "cast" a byte that's
+                                     // intended to be unsigned.
+                }   // end else
+            }   // end if: position >= 0
+            
+            // Else error
+            else {
+                throw new java.io.IOException( "Error in Base64 code reading stream." );
+            }   // end else
+        }   // end read
+        
+        
+        /**
+         * Calls {@link #read()} repeatedly until the end of stream
+         * is reached or <var>len</var> bytes are read.
+         * Returns number of bytes read into array or -1 if
+         * end of stream is encountered.
+         *
+         * @param dest array to hold values
+         * @param off offset for array
+         * @param len max number of bytes to read into array
+         * @return bytes read into array or -1 if end of stream is encountered.
+         * @since 1.3
+         */
+        @Override
+        public int read( byte[] dest, int off, int len ) 
+        throws java.io.IOException {
+            int i;
+            int b;
+            for( i = 0; i < len; i++ ) {
+                b = read();
+                
+                if( b >= 0 ) {
+                    dest[off + i] = (byte) b;
+                }
+                else if( i == 0 ) {
+                    return -1;
+                }
+                else {
+                    break; // Out of 'for' loop
+                } // Out of 'for' loop
+            }   // end for: each byte read
+            return i;
+        }   // end read
+        
+    }   // end inner class InputStream
+    
+    
+    
+    
+    
+    
+    /* ********  I N N E R   C L A S S   O U T P U T S T R E A M  ******** */
+    
+    
+    
+    /**
+     * A {@link Base64.OutputStream} will write data to another
+     * <tt>java.io.OutputStream</tt>, given in the constructor,
+     * and encode/decode to/from Base64 notation on the fly.
+     *
+     * @see Base64
+     * @since 1.3
+     */
+    public static class OutputStream extends java.io.FilterOutputStream {
+        
+        private boolean encode;
+        private int     position;
+        private byte[]  buffer;
+        private int     bufferLength;
+        private int     lineLength;
+        private boolean breakLines;
+        private byte[]  b4;         // Scratch used in a few places
+        private boolean suspendEncoding;
+        private int     options;    // Record for later
+        private byte[]  decodabet;  // Local copies to avoid extra method calls
+        
+        /**
+         * Constructs a {@link Base64.OutputStream} in ENCODE mode.
+         *
+         * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
+         * @since 1.3
+         */
+        public OutputStream( java.io.OutputStream out ) {
+            this( out, ENCODE );
+        }   // end constructor
+        
+        
+        /**
+         * Constructs a {@link Base64.OutputStream} in
+         * either ENCODE or DECODE mode.
+         * <p>
+         * Valid options:<pre>
+         *   ENCODE or DECODE: Encode or Decode as data is read.
+         *   DO_BREAK_LINES: don't break lines at 76 characters
+         *     (only meaningful when encoding)</i>
+         * </pre>
+         * <p>
+         * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
+         *
+         * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
+         * @param options Specified options.
+         * @see Base64#ENCODE
+         * @see Base64#DECODE
+         * @see Base64#DO_BREAK_LINES
+         * @since 1.3
+         */
+        public OutputStream( java.io.OutputStream out, int options ) {
+            super( out );
+            this.breakLines   = (options & DO_BREAK_LINES) != 0;
+            this.encode       = (options & ENCODE) != 0;
+            this.bufferLength = encode ? 3 : 4;
+            this.buffer       = new byte[ bufferLength ];
+            this.position     = 0;
+            this.lineLength   = 0;
+            this.suspendEncoding = false;
+            this.b4           = new byte[4];
+            this.options      = options;
+            this.decodabet    = getDecodabet(options);
+        }   // end constructor
+        
+        
+        /**
+         * Writes the byte to the output stream after
+         * converting to/from Base64 notation.
+         * When encoding, bytes are buffered three
+         * at a time before the output stream actually
+         * gets a write() call.
+         * When decoding, bytes are buffered four
+         * at a time.
+         *
+         * @param theByte the byte to write
+         * @since 1.3
+         */
+        @Override
+        public void write(int theByte) 
+        throws java.io.IOException {
+            // Encoding suspended?
+            if( suspendEncoding ) {
+                this.out.write( theByte );
+                return;
+            }   // end if: supsended
+            
+            // Encode?
+            if( encode ) {
+                buffer[ position++ ] = (byte)theByte;
+                if( position >= bufferLength ) { // Enough to encode.
+                
+                    this.out.write( encode3to4( b4, buffer, bufferLength, options ) );
+
+                    lineLength += 4;
+                    if( breakLines && lineLength >= MAX_LINE_LENGTH ) {
+                        this.out.write( NEW_LINE );
+                        lineLength = 0;
+                    }   // end if: end of line
+
+                    position = 0;
+                }   // end if: enough to output
+            }   // end if: encoding
+
+            // Else, Decoding
+            else {
+                // Meaningful Base64 character?
+                if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC ) {
+                    buffer[ position++ ] = (byte)theByte;
+                    if( position >= bufferLength ) { // Enough to output.
+                    
+                        int len = Base64.decode4to3( buffer, 0, b4, 0, options );
+                        out.write( b4, 0, len );
+                        position = 0;
+                    }   // end if: enough to output
+                }   // end if: meaningful base64 character
+                else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC ) {
+                    throw new java.io.IOException( "Invalid character in Base64 data." );
+                }   // end else: not white space either
+            }   // end else: decoding
+        }   // end write
+        
+        
+        
+        /**
+         * Calls {@link #write(int)} repeatedly until <var>len</var> 
+         * bytes are written.
+         *
+         * @param theBytes array from which to read bytes
+         * @param off offset for array
+         * @param len max number of bytes to read into array
+         * @since 1.3
+         */
+        @Override
+        public void write( byte[] theBytes, int off, int len ) 
+        throws java.io.IOException {
+            // Encoding suspended?
+            if( suspendEncoding ) {
+                this.out.write( theBytes, off, len );
+                return;
+            }   // end if: supsended
+            
+            for( int i = 0; i < len; i++ ) {
+                write( theBytes[ off + i ] );
+            }   // end for: each byte written
+            
+        }   // end write
+        
+        
+        
+        /**
+         * Method added by PHIL. [Thanks, PHIL. -Rob]
+         * This pads the buffer without closing the stream.
+         * @throws java.io.IOException  if there's an error.
+         */
+        public void flushBase64() throws java.io.IOException  {
+            if( position > 0 ) {
+                if( encode ) {
+                    out.write( encode3to4( b4, buffer, position, options ) );
+                    position = 0;
+                }   // end if: encoding
+                else {
+                    throw new java.io.IOException( "Base64 input not properly padded." );
+                }   // end else: decoding
+            }   // end if: buffer partially full
+
+        }   // end flush
+
+        
+        /** 
+         * Flushes and closes (I think, in the superclass) the stream. 
+         *
+         * @since 1.3
+         */
+        @Override
+        public void close() throws java.io.IOException {
+            // 1. Ensure that pending characters are written
+            flushBase64();
+
+            // 2. Actually close the stream
+            // Base class both flushes and closes.
+            super.close();
+            
+            buffer = null;
+            out    = null;
+        }   // end close
+        
+        
+        
+        /**
+         * Suspends encoding of the stream.
+         * May be helpful if you need to embed a piece of
+         * base64-encoded data in a stream.
+         *
+         * @throws java.io.IOException  if there's an error flushing
+         * @since 1.5.1
+         */
+        public void suspendEncoding() throws java.io.IOException  {
+            flushBase64();
+            this.suspendEncoding = true;
+        }   // end suspendEncoding
+        
+        
+        /**
+         * Resumes encoding of the stream.
+         * May be helpful if you need to embed a piece of
+         * base64-encoded data in a stream.
+         *
+         * @since 1.5.1
+         */
+        public void resumeEncoding() {
+            this.suspendEncoding = false;
+        }   // end resumeEncoding
+        
+        
+        
+    }   // end inner class OutputStream
+    
+    
+}   // end class Base64
diff --git a/src/org/rki/sequenceeditor/model/BaseColorModel.java b/src/org/rki/sequenceeditor/model/BaseColorModel.java
new file mode 100644
index 0000000..250f8b9
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/BaseColorModel.java
@@ -0,0 +1,22 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+import java.util.HashMap;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class BaseColorModel {
+//    public HashMap<Character, int[]> baseColor = new HashMap<Character, int[]>();
+    public BaseColorModelMap baseColor = new BaseColorModelMap();
+    
+    public void addBaseColor(char base, int fg, int bg, int foregroundDominant) {
+        int[] colors = {fg, bg, foregroundDominant};
+        baseColor.put(base, colors);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/BaseColorModelMap.java b/src/org/rki/sequenceeditor/model/BaseColorModelMap.java
new file mode 100644
index 0000000..59c7e36
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/BaseColorModelMap.java
@@ -0,0 +1,30 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+import java.util.HashMap;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class BaseColorModelMap {
+    private HashMap<Character, int[]> _colorModelMap = new HashMap<Character, int[]>();
+    
+    public BaseColorModelMap() {}
+    
+    public void put(Character base, int[] model) {
+        _colorModelMap.put(base, model);
+    }
+    
+    public int[] get(Character base) {
+        try {
+            return _colorModelMap.get(base);
+        } catch(Exception e) {
+            return _colorModelMap.get('?');
+        }
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/ClientHttpRequest.java b/src/org/rki/sequenceeditor/model/ClientHttpRequest.java
new file mode 100644
index 0000000..cb0b0d9
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/ClientHttpRequest.java
@@ -0,0 +1,552 @@
+/**
+ * <p>Title: MyJavaTools: Client HTTP Request class</p>
+ * <p>Description: this class helps to send POST HTTP requests with various form data,
+ * including files. Cookies can be added to be included in the request.</p>
+ *
+ * <p>Copyright: This is public domain;
+ * The right of people to use, distribute, copy or improve the contents of the
+ * following may not be restricted.</p>
+ *
+ * @author Vlad Patryshev, Alexei Trebounskikh
+ * @version 1.4
+ */
+package org.rki.sequenceeditor.model;
+
+import java.net.URLConnection;
+import java.net.URL;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.io.File;
+import java.io.InputStream;
+import java.util.Random;
+import java.io.OutputStream;
+import java.io.FileInputStream;
+import java.util.Iterator;
+
+public class ClientHttpRequest {
+  URLConnection _connection;
+  OutputStream _os = null;
+  Map _cookies = new HashMap();
+  String _rawCookies = "";
+
+  protected void connect() throws IOException {
+    if (_os == null) _os = _connection.getOutputStream();
+  }
+
+  protected void write(char c) throws IOException {
+    connect();
+    _os.write(c);
+  }
+
+  protected void write(String s) throws IOException {
+    connect();
+    _os.write(s.getBytes());
+  }
+
+  protected void newline() throws IOException {
+    connect();
+    write("\r\n");
+  }
+
+  protected void writeln(String s) throws IOException {
+    connect();
+    write(s);
+    newline();
+  }
+
+  private static Random random = new Random();
+
+  protected static String randomString() {
+    return Long.toString(random.nextLong(), 36);
+  }
+
+  String boundary = "---------------------------" + randomString() + randomString() + randomString();
+
+  private void boundary() throws IOException {
+    write("--");
+    write(boundary);
+  }
+
+  /**
+   * Creates a new multipart POST HTTP request on a freshly opened URLConnection
+   *
+   * @param connection an already open URL connection
+   * @throws IOException
+   */
+  public ClientHttpRequest(URLConnection connection) throws IOException {
+    this._connection = connection;
+    connection.setDoOutput(true);
+    connection.setDoInput(true);
+    connection.setRequestProperty("Content-Type",
+                                  "multipart/form-data; boundary=" + boundary);
+  }
+
+  /**
+   * Creates a new multipart POST HTTP request for a specified URL
+   *
+   * @param url the URL to send request to
+   * @throws IOException
+   */
+  public ClientHttpRequest(URL url) throws IOException {
+    this(url.openConnection());
+  }
+
+  /**
+   * Creates a new multipart POST HTTP request for a specified URL string
+   *
+   * @param urlString the string representation of the URL to send request to
+   * @throws IOException
+   */
+  public ClientHttpRequest(String urlString) throws IOException {
+    this(new URL(urlString));
+  }
+
+
+  private void postCookies() {
+    StringBuffer cookieList = new StringBuffer(_rawCookies);
+
+    for (Iterator i = _cookies.entrySet().iterator(); i.hasNext();) {
+      Map.Entry entry = (Map.Entry)(i.next());
+      cookieList.append(entry.getKey().toString() + "=" + entry.getValue());
+
+      if (i.hasNext()) {
+        cookieList.append("; ");
+      }
+    }
+    if (cookieList.length() > 0) {
+      _connection.setRequestProperty("Cookie", cookieList.toString());
+    }
+  }
+
+  /**
+   * adds a cookie to the requst
+   * @param name cookie name
+   * @param value cookie value
+   * @throws IOException
+   */
+  public void setCookies(String rawCookies) throws IOException {
+    this._rawCookies = (rawCookies == null) ? "" : rawCookies;
+    _cookies.clear();
+  }
+
+  /**
+   * adds a cookie to the requst
+   * @param name cookie name
+   * @param value cookie value
+   * @throws IOException
+   */
+  public void setCookie(String name, String value) throws IOException {
+        _cookies.put(name, value);
+  }
+
+  /**
+   * adds cookies to the request
+   * @param cookies the cookie "name-to-value" map
+   * @throws IOException
+   */
+  public void setCookies(Map cookies) throws IOException {
+    if (cookies == null) return;
+    this._cookies.putAll(cookies);
+  }
+
+  /**
+   * adds cookies to the request
+   * @param cookies array of cookie names and values (cookies[2*i] is a name, cookies[2*i + 1] is a value)
+   * @throws IOException
+   */
+  public void setCookies(String[] cookies) throws IOException {
+    if (cookies == null) return;
+    for (int i = 0; i < cookies.length - 1; i+=2) {
+      setCookie(cookies[i], cookies[i+1]);
+    }
+  }
+
+  private void writeName(String name) throws IOException {
+    newline();
+    write("Content-Disposition: form-data; name=\"");
+    write(name);
+    write('"');
+  }
+
+  /**
+   * adds a string parameter to the request
+   * @param name parameter name
+   * @param value parameter value
+   * @throws IOException
+   */
+  public void setParameter(String name, String value) throws IOException {
+    boundary();
+    writeName(name);
+    newline(); newline();
+    writeln(value);
+  }
+
+  private static void pipe(InputStream in, OutputStream out) throws IOException {
+    byte[] buf = new byte[500000];
+    int nread;
+    int total = 0;
+
+    synchronized (in) {
+      while((nread = in.read(buf, 0, buf.length)) >= 0) {
+        out.write(buf, 0, nread);
+        total += nread;
+      }
+    }
+    out.flush();
+    buf = null;
+  }
+
+  /**
+   * adds a file parameter to the request
+   * @param name parameter name
+   * @param filename the name of the file
+   * @param is input stream to read the contents of the file from
+   * @throws IOException
+   */
+  public void setParameter(String name, String filename, InputStream is) throws IOException {
+    boundary();
+    writeName(name);
+    write("; filename=\"");
+    write(filename);
+    write('"');
+    newline();
+    write("Content-Type: ");
+    String type = URLConnection.guessContentTypeFromName(filename);
+    if (type == null) type = "application/octet-stream";
+    writeln(type);
+    newline();
+    pipe(is, _os);
+    newline();
+  }
+
+  /**
+   * adds a file parameter to the request
+   * @param name parameter name
+   * @param file the file to upload
+   * @throws IOException
+   */
+  public void setParameter(String name, File file) throws IOException {
+    setParameter(name, file.getPath(), new FileInputStream(file));
+  }
+
+  /**
+   * adds a parameter to the request; if the parameter is a File, the file is uploaded, otherwise the string value of the parameter is passed in the request
+   * @param name parameter name
+   * @param object parameter value, a File or anything else that can be stringified
+   * @throws IOException
+   */
+  public void setParameter(String name, Object object) throws IOException {
+    if (object instanceof File) {
+      setParameter(name, (File) object);
+    } else {
+      setParameter(name, object.toString());
+    }
+  }
+
+  /**
+   * adds parameters to the request
+   * @param parameters "name-to-value" map of parameters; if a value is a file, the file is uploaded, otherwise it is stringified and sent in the request
+   * @throws IOException
+   */
+  public void setParameters(Map parameters) throws IOException {
+    if (parameters != null) {
+      for (Iterator i = parameters.entrySet().iterator(); i.hasNext();) {
+        Map.Entry entry = (Map.Entry)i.next();
+        setParameter(entry.getKey().toString(), entry.getValue());
+      }
+    }
+  }
+
+  /**
+   * adds parameters to the request
+   * @param parameters array of parameter names and values (parameters[2*i] is a name, parameters[2*i + 1] is a value); if a value is a file, the file is uploaded, otherwise it is stringified and sent in the request
+   * @throws IOException
+   */
+  public void setParameters(Object[] parameters) throws IOException {
+    if (parameters != null) {
+      for (int i = 0; i < parameters.length - 1; i += 2) {
+        setParameter(parameters[i].toString(), parameters[i + 1]);
+      }
+    }
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added
+   * @return input stream with the server response
+   * @throws IOException
+   */
+  private InputStream doPost() throws IOException {
+    boundary();
+    writeln("--");
+    _os.close();
+
+    return _connection.getInputStream();
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added
+   * @return input stream with the server response
+   * @throws IOException
+   */
+  public InputStream post() throws IOException {
+          postCookies();
+        return doPost();
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with parameters that are passed in the argument
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   */
+  public InputStream post(Map parameters) throws IOException {
+    postCookies();
+    setParameters(parameters);
+    return doPost();
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with parameters that are passed in the argument
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   */
+  public InputStream post(Object[] parameters) throws IOException {
+    postCookies();
+    setParameters(parameters);
+    return doPost();
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with cookies and parameters that are passed in the arguments
+   * @param cookies request cookies
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   * @see setCookies
+   */
+  public InputStream post(Map cookies, Map parameters) throws IOException {
+    setCookies(cookies);
+    postCookies();
+    setParameters(parameters);
+    return doPost();
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with cookies and parameters that are passed in the arguments
+   * @param cookies request cookies
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   * @see setCookies
+   */
+  public InputStream post(String raw_cookies, Map parameters) throws IOException {
+    setCookies(raw_cookies);
+    postCookies();
+    setParameters(parameters);
+    return doPost();
+  }
+
+  /**
+   * posts the requests to the server, with all the cookies and parameters that were added before (if any), and with cookies and parameters that are passed in the arguments
+   * @param cookies request cookies
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   * @see setCookies
+   */
+  public InputStream post(String[] cookies, Object[] parameters) throws IOException {
+    setCookies(cookies);
+    postCookies();
+    setParameters(parameters);
+    return doPost();
+  }
+
+  /**
+   * post the POST request to the server, with the specified parameter
+   * @param name parameter name
+   * @param value parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public InputStream post(String name, Object value) throws IOException {
+    postCookies();
+    setParameter(name, value);
+    return doPost();
+  }
+
+  /**
+   * post the POST request to the server, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public InputStream post(String name1, Object value1, String name2, Object value2) throws IOException {
+    postCookies();
+    setParameter(name1, value1);
+    setParameter(name2, value2);
+    return doPost();
+  }
+
+  /**
+   * post the POST request to the server, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @param name3 third parameter name
+   * @param value3 third parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public InputStream post(String name1, Object value1, String name2, Object value2, String name3, Object value3) throws IOException {
+    postCookies();
+    setParameter(name1, value1);
+    setParameter(name2, value2);
+    setParameter(name3, value3);
+    return doPost();
+  }
+
+  /**
+   * post the POST request to the server, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @param name3 third parameter name
+   * @param value3 third parameter value
+   * @param name4 fourth parameter name
+   * @param value4 fourth parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public InputStream post(String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) throws IOException {
+    postCookies();
+    setParameter(name1, value1);
+    setParameter(name2, value2);
+    setParameter(name3, value3);
+    setParameter(name4, value4);
+    return doPost();
+  }
+
+  /**
+   * posts a new request to specified URL, with parameters that are passed in the argument
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   */
+  public static InputStream post(URL url, Map parameters) throws IOException {
+    return new ClientHttpRequest(url).post(parameters);
+  }
+
+  /**
+   * posts a new request to specified URL, with parameters that are passed in the argument
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameters
+   */
+  public static InputStream post(URL url, Object[] parameters) throws IOException {
+    return new ClientHttpRequest(url).post(parameters);
+  }
+
+  /**
+   * posts a new request to specified URL, with cookies and parameters that are passed in the argument
+   * @param cookies request cookies
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setCookies
+   * @see setParameters
+   */
+  public static InputStream post(URL url, Map cookies, Map parameters) throws IOException {
+    return new ClientHttpRequest(url).post(cookies, parameters);
+  }
+
+  /**
+   * posts a new request to specified URL, with cookies and parameters that are passed in the argument
+   * @param cookies request cookies
+   * @param parameters request parameters
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setCookies
+   * @see setParameters
+   */
+  public static InputStream post(URL url, String[] cookies, Object[] parameters) throws IOException {
+    return new ClientHttpRequest(url).post(cookies, parameters);
+  }
+
+  /**
+   * post the POST request specified URL, with the specified parameter
+   * @param name parameter name
+   * @param value parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public static InputStream post(URL url, String name1, Object value1) throws IOException {
+    return new ClientHttpRequest(url).post(name1, value1);
+  }
+
+  /**
+   * post the POST request to specified URL, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public static InputStream post(URL url, String name1, Object value1, String name2, Object value2) throws IOException {
+    return new ClientHttpRequest(url).post(name1, value1, name2, value2);
+  }
+
+  /**
+   * post the POST request to specified URL, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @param name3 third parameter name
+   * @param value3 third parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public static InputStream post(URL url, String name1, Object value1, String name2, Object value2, String name3, Object value3) throws IOException {
+    return new ClientHttpRequest(url).post(name1, value1, name2, value2, name3, value3);
+  }
+
+  /**
+   * post the POST request to specified URL, with the specified parameters
+   * @param name1 first parameter name
+   * @param value1 first parameter value
+   * @param name2 second parameter name
+   * @param value2 second parameter value
+   * @param name3 third parameter name
+   * @param value3 third parameter value
+   * @param name4 fourth parameter name
+   * @param value4 fourth parameter value
+   * @return input stream with the server response
+   * @throws IOException
+   * @see setParameter
+   */
+  public static InputStream post(URL url, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) throws IOException {
+    return new ClientHttpRequest(url).post(name1, value1, name2, value2, name3, value3, name4, value4);
+  }
+}
\ No newline at end of file
diff --git a/src/org/rki/sequenceeditor/model/ColorModels.java b/src/org/rki/sequenceeditor/model/ColorModels.java
new file mode 100644
index 0000000..03a4c89
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/ColorModels.java
@@ -0,0 +1,103 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+import java.util.HashMap;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class ColorModels {
+    public static HashMap<String, BaseColorModel> models = new HashMap<String, BaseColorModel>();
+    public static String currentModel = "UPGMA";
+    
+    static {
+        BaseColorModel cm = new BaseColorModel();
+        cm.addBaseColor('A', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('G', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('T', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('U', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('C', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('R', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('Y', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('S', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('W', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('K', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('M', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('B', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('D', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('H', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('V', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('N', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('-', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('?', 0x000000, 0xffffff, 1);
+        models.put("Monochrome", cm);
+
+        cm = new BaseColorModel();
+        cm.addBaseColor('A', 0xff0000, 0xffffff, 1);
+        cm.addBaseColor('G', 0xdddd00, 0xffffff, 1);
+        cm.addBaseColor('T', 0x0000ff, 0xffffff, 1);
+        cm.addBaseColor('U', 0x0000ff, 0xffffff, 1);
+        cm.addBaseColor('C', 0x00ff00, 0xffffff, 1);
+        cm.addBaseColor('R', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('Y', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('S', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('W', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('K', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('M', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('B', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('D', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('H', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('V', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('N', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('-', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('?', 0x000000, 0xffffff, 1);
+        models.put("UPGMA", cm);
+
+        cm = new BaseColorModel();
+        cm.addBaseColor('A', 0x000000, 0xff0000, 0);
+        cm.addBaseColor('G', 0x000000, 0xffff00, 0);
+        cm.addBaseColor('T', 0x000000, 0x0000ff, 0);
+        cm.addBaseColor('U', 0x000000, 0x0000ff, 0);
+        cm.addBaseColor('C', 0x000000, 0x00ff00, 0);
+        cm.addBaseColor('R', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('Y', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('S', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('W', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('K', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('M', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('B', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('D', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('H', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('V', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('N', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('-', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('?', 0x000000, 0xffffff, 1);
+        models.put("UPGMA (background)", cm);
+        
+        cm = new BaseColorModel();
+        cm.addBaseColor('A', 0x000000, 0x9bf48a, 0);
+        cm.addBaseColor('G', 0x000000, 0xb8c7cc, 0);
+        cm.addBaseColor('T', 0x000000, 0xf7b289, 0);
+        cm.addBaseColor('U', 0x000000, 0xf7b289, 0);
+        cm.addBaseColor('C', 0x000000, 0xbef2ee, 0);
+        cm.addBaseColor('R', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('Y', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('S', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('W', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('K', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('M', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('B', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('D', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('H', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('V', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('N', 0x000000, 0xffffff, 0);
+        cm.addBaseColor('-', 0x000000, 0xffffff, 1);
+        cm.addBaseColor('?', 0x000000, 0xffffff, 1);
+        models.put("BioEdit (background)", cm);        
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/Data.java b/src/org/rki/sequenceeditor/model/Data.java
new file mode 100644
index 0000000..8c48e7d
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Data.java
@@ -0,0 +1,18 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class Data {
+
+    public static GroupKey defaultGroup = new GroupKey("All");
+    
+    public static void loadDefaultAlignment(Alignment align) {
+    }    
+}
diff --git a/src/org/rki/sequenceeditor/model/Flowgram.java b/src/org/rki/sequenceeditor/model/Flowgram.java
new file mode 100644
index 0000000..401095e
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Flowgram.java
@@ -0,0 +1,143 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class Flowgram implements Comparable<Flowgram> {
+    private char[] _order;
+    private ArrayList<Integer> _signals = new ArrayList<Integer>();
+    private Color[] _colors = {Color.RED, Color.GREEN, Color.BLUE, Color.ORANGE};
+    private String _name;
+
+    public Flowgram(char[] seq, char[] order, int len, String name) {
+        _order = order;
+        _name = name.substring(0, Math.min(name.length(), 20));
+        int pos = 0;
+        int flowPos = 0;
+        int totalFlowPos = 0;
+        while(pos < seq.length) {
+            if(totalFlowPos > len) {
+                break;
+            }
+            if(seq[pos] == '-') {
+                pos += 1;
+                continue;
+            }
+            if(!inOrder(seq[pos])) {
+                break;
+            }
+            if(seq[pos] == _order[flowPos]) {
+                _signals.add(1);
+                pos ++;
+                while(pos < seq.length && seq[pos] == _order[flowPos]) {
+                    _signals.set(_signals.size()-1, _signals.get(_signals.size()-1)+1);
+                    pos ++;
+                }
+                flowPos = (flowPos + 1)%_order.length;
+                totalFlowPos += 1;
+                continue;
+            }
+            _signals.add(0);
+            flowPos = (flowPos + 1)%_order.length;
+            totalFlowPos += 1;
+        }
+    }
+
+    public int draw(Graphics g, int x0, int y0, Collection<Flowgram> identical) {
+        int pos = 0;
+        int xf = x0 + 125;
+        int additional_dist = 0;
+        g.setFont(new Font("Courier", 0, 10));
+        for(Integer signal : _signals) {
+            g.setColor(Color.BLACK);
+            g.drawString(_name, x0, y0);
+            if(signal != 0)
+                g.drawRect(xf+10*pos-1, y0-signal*5-1, 6, signal*5);
+            g.setColor(_colors[pos%(_colors.length)]);
+            g.fillRect(xf+10*pos, y0-signal*5, 5, signal*5);
+            char[] data = {_order[pos%_order.length]};
+            g.drawChars(data, 0, 1, xf-2+10*pos, y0+10);
+            if(identical.size() >= 1) {
+                int ipos = 0;
+                for(Flowgram flow : identical) {
+                    drawIdentical(flow.getName(), g, x0, y0+ipos*10, ipos==identical.size()-1);
+                    ipos++;
+                }
+                additional_dist = (ipos-1)*10;
+            }
+            pos ++;
+        }
+        return additional_dist;
+    }
+
+    private void drawIdentical(String name, Graphics g, int x, int y, boolean last) {
+        g.setFont(new Font("Courier", 0, 10));
+        g.setColor(Color.GRAY);
+        g.drawLine(x+4, y, x+4, y+10);
+        if(!last)
+            g.drawLine(x+4, y+10, x+4, y+20);
+        g.drawLine(x+4, y+10, x+9, y+10);
+        g.drawString(name, x+10, y+5+8);
+    }
+
+    private boolean inOrder(char x) {
+        for(char o : _order) {
+            if(o == x) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void add(Flowgram flow) {
+        ArrayList<Integer> longFlow = flow._signals.size() >= _signals.size() ? flow._signals : _signals;
+        ArrayList<Integer> shortFlow = flow._signals.size() >= _signals.size() ? _signals : flow._signals;
+        for(int i=0; i<shortFlow.size(); i++) {
+            longFlow.set(i, longFlow.get(i) + shortFlow.get(i));
+        }
+        _signals = longFlow;
+    }
+
+    @Override
+    public boolean equals(Object o) 
+    {
+        if(!(o instanceof Flowgram)) {
+            return false;
+        }
+        Flowgram flow = (Flowgram)o;
+        ArrayList<Integer> longFlow = flow._signals.size() >= _signals.size() ? flow._signals : _signals;
+        ArrayList<Integer> shortFlow = flow._signals.size() >= _signals.size() ? _signals : flow._signals;
+        for(int i=0; i<shortFlow.size(); i++) {
+            if(shortFlow.get(i) != longFlow.get(i))
+                return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 3;
+        hash = 83 * hash + (this._signals != null ? this._signals.hashCode() : 0);
+        return hash;
+    }
+
+    public String getName() {
+        return _name;
+    }
+
+    public int compareTo(Flowgram o) {
+        return o.getName().compareTo(getName());
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/Globals.java b/src/org/rki/sequenceeditor/model/Globals.java
new file mode 100644
index 0000000..296a82e
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Globals.java
@@ -0,0 +1,24 @@
+package org.rki.sequenceeditor.model;
+
+import java.util.HashMap;
+
+public class Globals {
+    public static HashMap<Character, Character> complementary = new HashMap<Character, Character>();
+    
+    static {
+        complementary.put('A', 'T');
+        complementary.put('G', 'C');
+        complementary.put('T', 'A');
+        complementary.put('C', 'G');
+        complementary.put('R', 'Y');
+        complementary.put('Y', 'R');
+        complementary.put('N', 'N');
+        complementary.put('W', 'W');
+        complementary.put('S', 'S');
+        complementary.put('H', 'D');
+        complementary.put('D', 'H');
+        complementary.put('B', 'V');
+        complementary.put('V', 'B');
+        complementary.put('-', '-');
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/GroupKey.java b/src/org/rki/sequenceeditor/model/GroupKey.java
new file mode 100644
index 0000000..5281e95
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/GroupKey.java
@@ -0,0 +1,39 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class GroupKey implements Comparable<GroupKey> {
+    private String _name;
+    
+    public GroupKey(Object name) {
+        _name = name.toString();
+    }
+
+    public String getName() {
+        return(_name);
+    }
+    
+    @Override
+    public String toString() {
+        return(_name);
+    }
+
+    public int compareTo(GroupKey o) {
+        return(_name.toLowerCase().compareTo(o.getName().toLowerCase()));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if(o instanceof GroupKey) 
+            return ((GroupKey)o).getName().toLowerCase().equals(_name.toLowerCase());
+        else
+            return false;
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/Letters.java b/src/org/rki/sequenceeditor/model/Letters.java
new file mode 100644
index 0000000..3663580
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Letters.java
@@ -0,0 +1,909 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+import java.util.HashMap;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class Letters {
+    public static final int[] sizes = {1, 2, 4, 8, 10, 12};
+    
+    private static final int[] __1 = 
+    {
+        0,
+        0,
+        0,
+        1,
+        0,
+        0,
+        0,
+        0,
+    };
+    private static final int[] _a1 = 
+    {
+        0,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0,
+    };
+    private static final int[] _g1 = _a1;
+    private static final int[] _t1 = _a1;
+    private static final int[] _u1 = _a1;
+    private static final int[] _c1 = _a1;
+
+    private static final int[] __2 = 
+    {
+        0,0,
+        0,0,
+        0,0,
+        1,1,
+        0,0,
+        0,0,
+        0,0,
+        0,0,
+    };
+    private static final int[] _a2 = 
+    {
+        0,0,
+        1,1,
+        1,1,
+        1,1,
+        1,1,
+        1,1,
+        1,1,
+        0,0,
+    };
+    private static final int[] _g2 = _a2;
+    private static final int[] _t2 = _a2;
+    private static final int[] _u2 = _a2;
+    private static final int[] _c2 = _a2;
+
+    private static final int[] __4 = 
+    {
+        0,0,0,0,
+        0,0,0,0,
+        0,0,0,0,
+        1,1,1,1,
+        0,0,0,0,
+        0,0,0,0,
+        0,0,0,0,
+        0,0,0,0
+    };
+    private static final int[] _a4 = 
+    {
+        0,0,0,0,
+        0,1,1,0,
+        0,1,1,0,
+        0,1,1,0,
+        0,1,1,0,
+        0,1,1,0,
+        0,1,1,0,
+        0,0,0,0
+    };
+    private static final int[] _g4 = _a4;
+    private static final int[] _t4 = _a4;
+    private static final int[] _u4 = _a4;
+    private static final int[] _c4 = _a4;
+
+    
+    private static final int[] __8 = 
+    {
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 1, 1, 1, 1, 1, 1, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0
+    };
+    private static final int[] _a8 = {0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 1, 1, 0, 0, 0,
+        0, 0, 1, 0, 0, 1, 0, 0,
+        0, 0, 1, 0, 0, 1, 0, 0,
+        0, 0, 1, 1, 1, 1, 0, 0,
+        0, 1, 0, 0, 0, 0, 1, 0,
+        0, 1, 0, 0, 0, 0, 1, 0,
+        0, 0, 0, 0, 0, 0, 0, 0
+    };
+    private static final int[] _g8 = {0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 1, 1, 0, 0, 0,
+        0, 0, 1, 0, 0, 1, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 1, 0, 1, 1, 0, 0,
+        0, 0, 1, 0, 0, 1, 0, 0,
+        0, 0, 0, 1, 1, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0
+    };
+    private static final int[] _t8 = {0, 0, 0, 0, 0, 0, 0, 0,
+        0, 1, 1, 1, 1, 1, 0, 0,
+        0, 0, 0, 1, 0, 0, 0, 0,
+        0, 0, 0, 1, 0, 0, 0, 0,
+        0, 0, 0, 1, 0, 0, 0, 0,
+        0, 0, 0, 1, 0, 0, 0, 0,
+        0, 0, 0, 1, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0
+    };
+    private static final int[] _u8 = {0, 0, 0, 0, 0, 0, 0, 0,
+        0, 1, 0, 0, 0, 1, 0, 0,
+        0, 1, 0, 0, 0, 1, 0, 0,
+        0, 1, 0, 0, 0, 1, 0, 0,
+        0, 1, 0, 0, 0, 1, 0, 0,
+        0, 1, 0, 0, 0, 1, 0, 0,
+        0, 0, 1, 1, 1, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0
+    };
+    private static final int[] _c8 = {0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 1, 1, 0, 0, 0,
+        0, 0, 1, 0, 0, 1, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 1, 0, 0, 1, 0, 0,
+        0, 0, 0, 1, 1, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0
+    };
+
+    private static final int[] _qm8 = {0, 0, 0, 0, 0, 0, 0, 0,
+        0,0,0,1,1,0,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,0,0,0,1,0,0,
+        0,0,0,0,1,0,0,0,
+        0,0,0,1,0,0,0,0,
+        0,0,0,0,0,0,0,0,
+        0,0,0,1,0,0,0,0
+    };
+
+    private static final int[] _r8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,1,1,1,0,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,1,1,0,0,0,
+        0,0,1,0,1,0,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] _y8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,
+        0,0,0,1,0,1,0,0,
+        0,0,0,0,1,0,0,0,
+        0,0,0,0,1,0,0,0,
+        0,0,0,0,1,0,0,0,
+        0,0,0,0,1,0,0,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] _s8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,0,1,1,0,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,
+        0,0,0,1,1,0,0,0,
+        0,0,0,0,0,1,0,0,
+        0,0,0,1,1,0,0,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] _w8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,
+        0,0,1,0,0,0,1,0,
+        0,0,1,0,0,0,1,0,
+        0,0,1,0,1,0,1,0,
+        0,0,1,0,1,0,1,0,
+        0,0,0,1,0,1,0,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] _k8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,1,0,0,0,
+        0,0,1,1,1,0,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,0,1,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] _m8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,0,1,0,1,0,0,
+        0,0,1,0,1,0,1,0,
+        0,0,1,0,1,0,1,0,
+        0,0,1,0,0,0,1,0,
+        0,0,1,0,0,0,1,0,
+        0,0,1,0,0,0,1,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] _b8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,1,1,1,0,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,1,1,0,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,1,1,0,0,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] _d8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,1,1,1,0,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,1,1,0,0,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] _h8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,1,1,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] _v8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,
+        0,0,1,0,0,0,1,0,
+        0,0,1,0,0,0,1,0,
+        0,0,0,1,0,1,0,0,
+        0,0,0,1,0,1,0,0,
+        0,0,0,0,1,0,0,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] _n8 = {
+        0,0,0,0,0,0,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,1,0,1,0,0,
+        0,0,1,0,1,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,
+        0,0,0,0,0,0,0,0
+    };
+
+    private static final int[] __10 = {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    };
+    
+    private static final int[] _a10 = {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+        0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
+        0, 0, 1, 1, 1, 1, 1, 1, 0, 0,
+        0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
+        0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
+        0, 1, 0, 0, 0, 0, 0, 0, 1, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    };
+    private static final int[] _g10 = {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
+        0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 1, 0, 0, 1, 1, 1, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
+        0, 0, 0, 1, 0, 0, 0, 1, 0, 0,
+        0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    };
+
+    private static final int[] _t10 = {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+        0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    };
+
+    private static final int[] _u10 = {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
+        0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
+        0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
+        0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
+        0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
+        0, 1, 0, 0, 0, 0, 0, 1, 0, 0,
+        0, 1, 1, 0, 0, 0, 1, 1, 0, 0,
+        0, 0, 1, 1, 1, 1, 1, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    };
+
+    private static final int[] _c10 = {
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+        0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
+        0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
+        0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    };
+
+    private static final int[] _r10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,
+        0,0,1,1,0,0,0,0,0,0,
+        0,0,1,0,1,0,0,0,0,0,
+        0,0,1,0,0,1,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+    
+    private static final int[] _y10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,1,0,
+        0,0,0,1,0,0,0,1,0,0,
+        0,0,0,0,1,0,1,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+    
+    private static final int[] _s10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,0,1,1,1,1,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,1,1,1,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,0,1,1,1,1,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+    
+    private static final int[] _w10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,1,1,0,1,0,0,
+        0,0,1,0,1,1,0,1,0,0,
+        0,0,0,1,0,0,1,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+    
+    private static final int[] _k10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,1,0,0,0,0,
+        0,0,1,0,1,0,0,0,0,0,
+        0,0,1,1,1,0,0,0,0,0,
+        0,0,1,0,0,1,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+    
+    private static final int[] _m10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,0,1,1,0,1,1,0,0,
+        0,0,1,0,0,1,0,0,1,0,
+        0,0,1,0,0,1,0,0,1,0,
+        0,0,1,0,0,0,0,0,1,0,
+        0,0,1,0,0,0,0,0,1,0,
+        0,0,1,0,0,0,0,0,1,0,
+        0,0,1,0,0,0,0,0,1,0,
+        0,0,1,0,0,0,0,0,1,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+    
+    private static final int[] _b10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+    
+    private static final int[] _d10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+    
+    private static final int[] _h10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,1,1,1,1,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+    
+    private static final int[] _v10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,0,1,0,0,1,0,0,0,
+        0,0,0,1,0,0,1,0,0,0,
+        0,0,0,0,1,1,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+    
+    private static final int[] _n10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,1,0,0,0,1,0,0,
+        0,0,1,0,1,0,0,1,0,0,
+        0,0,1,0,0,1,0,1,0,0,
+        0,0,1,0,0,0,1,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _qm10 = {
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,0,1,1,1,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,
+        0,0,0,0,1,0,0,0,0,0,
+        0,0,0,0,1,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,1,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] __12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,1,1,1,1,1,1,1,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+    private static final int[] _a12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,1,1,1,1,0,0,0,0,0,
+        0,0,0,0,1,1,1,0,0,0,0,0,
+        0,0,0,0,1,0,1,0,0,0,0,0,
+        0,0,0,1,1,0,1,1,0,0,0,0,
+        0,0,0,1,0,0,0,1,0,0,0,0,
+        0,0,0,1,0,0,0,1,0,0,0,0,
+        0,0,1,1,1,1,1,1,1,0,0,0,
+        0,0,1,0,0,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,0,0,1,1,0,0,
+        0,1,1,1,1,0,0,1,1,1,1,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _g12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,1,1,1,1,0,1,0,0,
+        0,0,0,1,1,0,0,0,1,1,0,0,
+        0,0,1,1,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,1,1,1,1,1,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,1,0,0,0,0,0,1,0,0,
+        0,0,0,1,1,0,0,0,1,1,0,0,
+        0,0,0,0,1,1,1,1,1,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _t12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,1,1,1,1,1,1,0,0,0,
+        0,0,1,0,0,1,0,0,1,0,0,0,
+        0,0,1,0,0,1,0,0,1,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,1,1,1,1,1,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _u12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,0,0,1,0,0,0,
+        0,0,1,0,0,0,0,0,1,0,0,0,
+        0,0,1,1,0,0,0,1,1,0,0,0,
+        0,0,0,1,1,1,1,1,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    
+    private static final int[] _c12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,1,1,1,1,0,1,0,0,
+        0,0,0,1,1,0,0,0,1,1,0,0,
+        0,0,1,1,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,0,0,0,0,
+        0,0,1,1,0,0,0,0,0,0,0,0,
+        0,0,0,1,1,0,0,0,1,1,0,0,
+        0,0,0,0,1,1,1,1,1,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _r12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,0,0,
+        0,0,1,0,0,1,0,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,0,0,
+        0,1,1,1,0,0,1,1,1,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _y12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,1,0,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,1,0,0,0,
+        0,0,0,1,0,0,0,1,0,0,0,0,
+        0,0,0,0,1,0,1,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,1,1,1,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _s12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,1,1,1,0,0,0,0,0,
+        0,0,0,1,0,0,0,1,0,0,0,0,
+        0,0,0,1,0,0,0,1,0,0,0,0,
+        0,0,0,0,1,0,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,0,1,0,0,0,0,0,
+        0,0,0,0,0,0,0,1,0,0,0,0,
+        0,0,0,1,0,0,0,1,0,0,0,0,
+        0,0,0,1,0,0,0,1,0,0,0,0,
+        0,0,0,0,1,1,1,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _w12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,1,1,0,0,1,0,0,
+        0,0,1,0,1,0,0,1,0,1,0,0,
+        0,0,1,0,1,0,0,1,0,1,0,0,
+        0,0,1,0,1,0,0,1,0,1,0,0,
+        0,0,0,1,1,0,0,1,1,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _k12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,1,0,0,0,0,0,1,0,0,
+        0,0,0,1,0,0,0,0,1,0,0,0,
+        0,0,0,1,0,0,0,1,0,0,0,0,
+        0,0,0,1,0,0,1,0,0,0,0,0,
+        0,0,0,1,0,1,0,0,0,0,0,0,
+        0,0,0,1,1,1,0,0,0,0,0,0,
+        0,0,0,1,0,0,1,0,0,0,0,0,
+        0,0,0,1,0,0,0,1,0,0,0,0,
+        0,0,0,1,0,0,0,0,1,0,0,0,
+        0,0,0,1,0,0,0,0,0,1,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _m12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,1,1,1,0,0,0,1,1,1,0,0,
+        0,1,0,0,1,0,1,0,0,1,0,0,
+        0,1,0,0,0,1,0,0,0,1,0,0,
+        0,1,0,0,0,0,0,0,0,1,0,0,
+        0,1,0,0,0,0,0,0,0,1,0,0,
+        0,1,0,0,0,0,0,0,0,1,0,0,
+        0,1,0,0,0,0,0,0,0,1,0,0,
+        0,1,0,0,0,0,0,0,0,1,0,0,
+        0,1,0,0,0,0,0,0,0,1,0,0,
+        0,1,0,0,0,0,0,0,0,1,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _b12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,0,0,
+        0,0,1,0,0,1,0,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _d12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,0,0,
+        0,0,1,0,0,0,0,1,0,0,0,0,
+        0,0,1,0,0,0,1,0,0,0,0,0,
+        0,0,1,1,1,1,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _h12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,1,1,1,1,1,1,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _v12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,0,0,1,0,
+        0,0,1,0,0,0,0,0,0,0,1,0,
+        0,0,0,1,0,0,0,0,0,1,0,0,
+        0,0,0,1,0,0,0,0,0,1,0,0,
+        0,0,0,0,1,0,0,0,1,0,0,0,
+        0,0,0,0,1,0,0,0,1,0,0,0,
+        0,0,0,0,0,1,0,1,0,0,0,0,
+        0,0,0,0,0,1,0,1,0,0,0,0,
+        0,0,0,0,0,0,1,0,0,0,0,0,
+        0,0,0,0,0,0,1,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _n12 = {
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,1,0,0,0,0,0,1,0,0,
+        0,0,1,0,1,0,0,0,0,1,0,0,
+        0,0,1,0,0,1,0,0,0,1,0,0,
+        0,0,1,0,0,0,1,0,0,1,0,0,
+        0,0,1,0,0,0,0,1,0,1,0,0,
+        0,0,1,0,0,0,0,0,1,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,1,0,0,0,0,0,0,1,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    private static final int[] _qm12 = {
+        0,0,0,0,0,1,1,0,0,0,0,0,
+        0,0,0,0,1,0,0,1,0,0,0,0,
+        0,0,0,1,0,0,0,0,1,0,0,0,
+        0,0,0,1,0,0,0,0,1,0,0,0,
+        0,0,0,0,1,0,0,0,1,0,0,0,
+        0,0,0,0,0,0,0,1,0,0,0,0,
+        0,0,0,0,0,0,1,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+        0,0,0,0,0,1,0,0,0,0,0,0,
+        0,0,0,0,0,0,0,0,0,0,0,0,
+    };
+
+    
+public static HashMap<Integer, int[]> letters = new HashMap<Integer, int[]>();
+
+    static {
+        letters.put('-' + 100, __1);
+        letters.put('A' + 100, _a1);
+        letters.put('G' + 100, _g1);
+        letters.put('T' + 100, _t1);
+        letters.put('U' + 100, _t1);
+        letters.put('C' + 100, _c1);
+        letters.put('R' + 100, _c1);
+        letters.put('Y' + 100, _c1);
+        letters.put('S' + 100, _c1);
+        letters.put('W' + 100, _c1);
+        letters.put('K' + 100, _c1);
+        letters.put('M' + 100, _c1);
+        letters.put('B' + 100, _c1);
+        letters.put('D' + 100, _c1);
+        letters.put('H' + 100, _c1);
+        letters.put('V' + 100, _c1);
+        letters.put('N' + 100, _c1);
+        letters.put('?' + 100, __1);
+
+        letters.put('-' + 200, __2);
+        letters.put('A' + 200, _a2);
+        letters.put('G' + 200, _g2);
+        letters.put('T' + 200, _t2);
+        letters.put('U' + 200, _u2);
+        letters.put('R' + 200, _c2);
+        letters.put('C' + 200, _c2);
+        letters.put('Y' + 200, _c2);
+        letters.put('S' + 200, _c2);
+        letters.put('W' + 200, _c2);
+        letters.put('K' + 200, _c2);
+        letters.put('M' + 200, _c2);
+        letters.put('B' + 200, _c2);
+        letters.put('D' + 200, _c2);
+        letters.put('H' + 200, _c2);
+        letters.put('V' + 200, _c2);
+        letters.put('N' + 200, _c2);
+        letters.put('?' + 200, __2);
+        
+        letters.put('-' + 400, __4);
+        letters.put('A' + 400, _a4);
+        letters.put('G' + 400, _g4);
+        letters.put('T' + 400, _t4);
+        letters.put('U' + 400, _u4);
+        letters.put('C' + 400, _c4);
+        letters.put('R' + 400, _c4);
+        letters.put('Y' + 400, _c4);
+        letters.put('S' + 400, _c4);
+        letters.put('W' + 400, _c4);
+        letters.put('K' + 400, _c4);
+        letters.put('M' + 400, _c4);
+        letters.put('B' + 400, _c4);
+        letters.put('D' + 400, _c4);
+        letters.put('H' + 400, _c4);
+        letters.put('V' + 400, _c4);
+        letters.put('N' + 400, _c4);
+        letters.put('?' + 400, __4);
+        
+        letters.put('-' + 800, __8);
+        letters.put('A' + 800, _a8);
+        letters.put('G' + 800, _g8);
+        letters.put('T' + 800, _t8);
+        letters.put('U' + 800, _u8);
+        letters.put('C' + 800, _c8);
+        letters.put('R' + 800, _r8);
+        letters.put('Y' + 800, _y8);
+        letters.put('S' + 800, _s8);
+        letters.put('W' + 800, _w8);
+        letters.put('K' + 800, _k8);
+        letters.put('M' + 800, _m8);
+        letters.put('B' + 800, _b8);
+        letters.put('D' + 800, _d8);
+        letters.put('H' + 800, _h8);
+        letters.put('V' + 800, _v8);
+        letters.put('N' + 800, _n8);
+        letters.put('?' + 800, _qm8);
+
+        letters.put('-' + 1000, __10);
+        letters.put('A' + 1000, _a10);
+        letters.put('G' + 1000, _g10);
+        letters.put('T' + 1000, _t10);
+        letters.put('U' + 1000, _u10);
+        letters.put('C' + 1000, _c10);
+        letters.put('R' + 1000, _r10);
+        letters.put('Y' + 1000, _y10);
+        letters.put('S' + 1000, _s10);
+        letters.put('W' + 1000, _w10);
+        letters.put('K' + 1000, _k10);
+        letters.put('M' + 1000, _m10);
+        letters.put('B' + 1000, _b10);
+        letters.put('D' + 1000, _d10);
+        letters.put('H' + 1000, _h10);
+        letters.put('V' + 1000, _v10);
+        letters.put('N' + 1000, _n10);
+        letters.put('?' + 1000, _qm10);
+        
+        letters.put('-' + 1200, __12);
+        letters.put('A' + 1200, _a12);
+        letters.put('G' + 1200, _g12);
+        letters.put('T' + 1200, _t12);
+        letters.put('U' + 1200, _u12);
+        letters.put('C' + 1200, _c12);
+        letters.put('R' + 1200, _r12);
+        letters.put('Y' + 1200, _y12);
+        letters.put('S' + 1200, _s12);
+        letters.put('W' + 1200, _w12);
+        letters.put('K' + 1200, _k12);
+        letters.put('M' + 1200, _m12);
+        letters.put('B' + 1200, _b12);
+        letters.put('D' + 1200, _d12);
+        letters.put('H' + 1200, _h12);
+        letters.put('V' + 1200, _v12);
+        letters.put('N' + 1200, _n12);
+        letters.put('?' + 1200, _qm12);
+    }
+    
+}
diff --git a/src/org/rki/sequenceeditor/model/MasterSequence.java b/src/org/rki/sequenceeditor/model/MasterSequence.java
new file mode 100644
index 0000000..3ff6d0a
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/MasterSequence.java
@@ -0,0 +1,33 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class MasterSequence extends Sequence {
+    public double[] conservation;
+    public Sequence IUB;
+    
+    public MasterSequence(String name, String seq, GroupKey group, Alignment align) {
+        super(name, seq, group, align);
+    }
+
+    public MasterSequence(Sequence s) {
+        super(s.name, s.seq, s.group, s.align);
+    }
+    
+    @Override
+    public int compareTo(Object o) {
+        if(!(o instanceof MasterSequence)) {
+            return 0;
+        }
+        MasterSequence s = (MasterSequence)o;
+        System.out.println(s.group.compareTo(group));
+        return s.group.compareTo(group);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/Position.java b/src/org/rki/sequenceeditor/model/Position.java
new file mode 100644
index 0000000..73e7d14
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Position.java
@@ -0,0 +1,26 @@
+package org.rki.sequenceeditor.model;
+
+public class Position {
+    public int x;
+    public int y;
+    public boolean onAnnotation;
+    public Annotation annotation;
+    public boolean onCollapser;
+    public boolean onConsensus;
+    public GroupKey consensusGroup = null;
+    
+    public Position(int x, int y, boolean onAnnotation, Annotation annotation, boolean onCollapser, boolean onConsensus, GroupKey consensusGroup) {
+        this.x = x;
+        this.y = y;
+        this.onAnnotation = onAnnotation;
+        this.annotation = annotation;
+        this.onCollapser = onCollapser;
+        this.onConsensus = onConsensus;
+        this.consensusGroup = consensusGroup;
+    }
+    
+    public int[] getCoordinates() {
+        int[] res = {x, y};
+        return(res);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/Primer.java b/src/org/rki/sequenceeditor/model/Primer.java
new file mode 100644
index 0000000..71e99aa
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Primer.java
@@ -0,0 +1,383 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+import java.awt.Color;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class Primer extends Annotation {
+    private boolean _above;
+    private HashMap<Integer, Character> _locked = new HashMap<Integer, Character>();
+    private int[] _scores;
+    private int[] _groupScores;
+    private float _tm;
+    public boolean isPyro = false;
+    // Just a helper variable for loading of primers
+    public String loadSequence;
+    // If another primer is present on the sequence so that it can form a product with this one,
+    // opposite should reference that primer.
+    public Primer opposite = null;
+
+    public Primer(int from, int to, Color background, String text, boolean above, AnnotationList list) {
+        super(from, to, background, text, list);
+        _above = above;
+        if(list != null) {
+            updateScores();
+            updateOpposite();
+        }
+    }
+
+    public final void updateScores() {
+        _scores = list.sequence.align.getScores(getSequence(), from);
+        _groupScores = list.sequence.align.getGroupScores(getSequence(), from, list.sequence.group);
+        updateTm();
+    }
+
+    public final void updateOpposite() {
+        Collection<Annotation> otherSide = null;
+        Collection<Annotation> thisSide = null;
+        if(_above) {
+            otherSide = list.sequence.below.getAnnotations();
+            thisSide = list.sequence.above.getAnnotations();
+        }
+        else {
+            otherSide = list.sequence.above.getAnnotations();
+            thisSide = list.sequence.below.getAnnotations();
+        }
+        int direction = _above?-1:1;
+        int closestOtherside = list.sequence.seq.length();
+        int closestThisside = closestOtherside;
+        Primer closest = null;
+        for(Annotation anno : otherSide) {
+            if(anno instanceof Primer) {
+                Primer p = (Primer)anno;
+                int dist = direction*((_above?to:from) - (_above?p.from:p.to));
+                if(dist < closestOtherside && dist > 0) {
+                    closestOtherside = dist;
+                    closest = p;
+                }
+            }
+        }
+        for(Annotation anno : thisSide) {
+            if(anno instanceof Primer) {
+                Primer p = (Primer)anno;
+                int dist = direction*((_above?to:from) - (_above?p.to:p.from));
+                if(dist < closestThisside && dist > 0) {
+                    closestThisside = dist;
+                }
+            }
+        }
+        if(closestOtherside < closestThisside && closest != null) {
+            opposite = closest;
+            opposite.opposite = this;
+        }
+        else {
+            opposite = null;
+        }
+    }
+
+    public Flowgram getFlowgram(Sequence seq, int len, String name) {
+        char[] order = {'A', 'G', 'T', 'C'};
+        if(_above) {
+            return new Flowgram(seq.seq.substring(to, to+10*len).toCharArray(), order, len, name);
+        }
+        else {
+            return new Flowgram(Sequence.invert(seq.seq.substring(Math.max(from-10*len, 0), from)).toCharArray(), order, len, name);
+        }
+    }
+
+    public int getMaxFlowgramLength() {
+        int maxlength = 1000;
+        System.out.println(list.sequence.align.masterSequences.size());
+        for(GroupKey group : list.sequence.align.masterSequences.keySet()) {
+            int gmaxlen = 0;
+            MasterSequence mseq = list.sequence.align.masterSequences.get(group);
+            if(_above) {
+                for(int i=to; i<mseq.seq.length() && mseq.conservation[i]==1; i++) {
+                    gmaxlen++;
+                }
+            }
+            else {
+                for(int i=from; i>=0 && mseq.conservation[i]==1; i--) {
+                    gmaxlen++;
+                }
+            }
+            maxlength = Math.min(maxlength, gmaxlen);
+        }
+        return(maxlength);
+    }
+
+    public String getSequence() {
+        char[] res = list.sequence.seq.substring(from, to).toCharArray();
+        for(Integer pos : _locked.keySet()) {
+            if(pos >= from && pos+1 <= to) {
+                res[pos-from] = _locked.get(pos);
+            }
+        }
+        return new String(res);
+    }
+
+    public int[] getScores() {
+        return _scores;
+    }
+
+    public int[] getGroupScores() {
+        return _groupScores;
+    }
+
+    public void lockBase(int pos, char base) {
+        int fullpos = pos+from;
+        if(base != list.sequence.seq.charAt(fullpos)) {
+            _locked.put(fullpos, base);
+        }
+        else {
+            _locked.remove(fullpos);
+        }
+    }
+
+    public void degenerate(String master) {
+        for(int i=0; i<master.length(); i++)
+            lockBase(i, master.charAt(i));
+        updateScores();
+    }
+
+    private char[] getBases(char base) {
+        switch(base) {
+            case 'a':
+                char[] res = {'a'};
+                return res;
+            case 'g':
+                char[] res2 = {'g'};
+                return res2;
+            case 't':
+                char[] res3 = {'t'};
+                return res3;
+            case 'u':
+                char[] res16 = {'u'};
+                return res16;
+            case 'c':
+                char[] res4 = {'c'};
+                return res4;
+            case 'r':
+                char[] res5 = {'a', 'g'};
+                return res5;
+            case 'y':
+                char[] res6 = {'c', 't'};
+                return res6;
+            case 'm':
+                char[] res7 = {'c', 'a'};
+                return res7;
+            case 'k':
+                char[] res8 = {'t', 'g'};
+                return res8;
+            case 'w':
+                char[] res9 = {'t', 'a'};
+                return res9;
+            case 's':
+                char[] res10 = {'c', 'g'};
+                return res10;
+            case 'b':
+                char[] res11 = {'c', 't', 'g'};
+                return res11;
+            case 'd':
+                char[] res12 = {'a', 't', 'g'};
+                return res12;
+            case 'h':
+                char[] res13 = {'a', 't', 'c'};
+                return res13;
+            case 'v':
+                char[] res14 = {'a', 'g', 'c'};
+                return res14;
+            case 'n':
+                char[] res15 = {'a', 't', 'c', 'g'};
+                return res15;
+        }
+        return null;
+    }
+
+    private LinkedList<char[]> getAllDimeres(char[] degenerated) {
+        LinkedList<char[]> res = new LinkedList<char[]>();
+        char[] bases1 = getBases(degenerated[0]);
+        char[] bases2 = getBases(degenerated[1]);
+        for(char base1 : bases1) {
+            for(char base2 : bases2) {
+                char[] dimer = {base1, base2};
+                res.add(dimer);
+            }
+        }
+        return res;
+    }
+
+    private char[] getLowestDimer(char[] degenerated) {
+        LinkedList<char[]> all = getAllDimeres(degenerated);
+        char[] lowest = all.getFirst();
+        float[] lowestDhDs = getDimereDhDs(lowest);
+        for(char[] dimer : all) {
+            float[] DhDs = getDimereDhDs(dimer);
+            if(DhDs[0] > lowestDhDs[0]) {
+                lowest = dimer;
+                lowestDhDs = DhDs;
+            }
+            else if(DhDs[0] == lowestDhDs[0] && DhDs[1] < lowestDhDs[1]) {
+                lowest = dimer;
+                lowestDhDs = DhDs;
+            }
+        }
+        return lowest;
+    }
+
+    private char[] getLowestMelting() {
+        char[] seq = getSequence().replace("-", "").toLowerCase().toCharArray();
+        if(seq.length < 2) {
+            char[] res = {'A', 'A'};
+            return(res);
+        }
+        char[] resSeq = new char[seq.length];
+        char[] dimer = {seq[0], seq[1]};
+        dimer = getLowestDimer(dimer);
+        resSeq[0] = dimer[0];
+        for(int i=1; i<seq.length-1; i++) {
+            dimer[0] = dimer[1];
+            dimer[1] = seq[i+1];
+            dimer = getLowestDimer(dimer);
+            resSeq[i] = dimer[0];
+            resSeq[i+1] = dimer[1];
+        }
+        return resSeq;
+    }
+
+    private float[] getDimereDhDs(char[] dimere) {
+        float[] res = {0, 0};
+        float sumdh = 0;
+        float sumds = 0;
+        switch (dimere[0]) {
+            case 'a':
+                switch (dimere[1]) {
+                    case 'a':
+                        sumdh -= 7.9;
+                        sumds -= 22.2;
+                        break;
+                    case 'g':
+                        sumdh -= 7.8;
+                        sumds -= 21.0;
+                        break;
+                    case 't':
+                        sumdh -= 7.2;
+                        sumds -= 20.4;
+                        break;
+                    case 'c':
+                        sumdh -= 8.4;
+                        sumds -= 22.4;
+                        break;
+                }
+                break;
+            case 'g':
+                switch (dimere[1]) {
+                    case 'a':
+                        sumdh -= 8.2;
+                        sumds -= 22.2;
+                        break;
+                    case 'g':
+                        sumdh -= 8.0;
+                        sumds -= 19.9;
+                        break;
+                    case 't':
+                        sumdh -= 8.4;
+                        sumds -= 22.4;
+                        break;
+                    case 'c':
+                        sumdh -= 10.6;
+                        sumds -= 27.2;
+                        break;
+                }
+                break;
+            case 't':
+                switch (dimere[1]) {
+                    case 'a':
+                        sumdh -= 7.2;
+                        sumds -= 21.3;
+                        break;
+                    case 'g':
+                        sumdh -= 8.5;
+                        sumds -= 22.7;
+                        break;
+                    case 't':
+                        sumdh -= 7.9;
+                        sumds -= 22.2;
+                        break;
+                    case 'c':
+                        sumdh -= 8.2;
+                        sumds -= 22.2;
+                        break;
+                }
+                break;
+            case 'c':
+                switch (dimere[1]) {
+                    case 'a':
+                        sumdh -= 8.5;
+                        sumds -= 22.7;
+                        break;
+                    case 'g':
+                        sumdh -= 10.6;
+                        sumds -= 27.2;
+                        break;
+                    case 't':
+                        sumdh -= 7.8;
+                        sumds -= 21.0;
+                        break;
+                    case 'c':
+                        sumdh -= 8;
+                        sumds -= 19.9;
+                        break;
+                }
+                break;
+
+        }
+        res[0] = sumdh;
+        res[1] = sumds;
+        return res;
+    }
+
+    public void updateTm() {
+        float sumdh = 0;
+        float sumds = 0;
+//        char[] seq = getSequence().toLowerCase().toCharArray();
+        char[] seq = getLowestMelting();
+        char base = seq[0];
+        // dH, dS calculations (Santalucia, 1998)
+        for(int i=1; i<seq.length; i++) {
+            char nbase = seq[i];
+            char[] dimere = {base, nbase};
+            float[] energies = getDimereDhDs(dimere);
+            sumdh += energies[0];
+            sumds += energies[1];
+            base = nbase;
+        }
+        // Terminal and starting corrections, Santalucia 1998
+        if(seq[0] == 'a' || seq[0] == 't') {sumdh += 2.3; sumds += 4.1; }
+        else if(seq[0] == 'g' || seq[0] == 'c') {sumdh += 0.1; sumds += -2.8; }
+        if(seq[seq.length-1] == 'a' || seq[seq.length-1] == 't') {sumdh += 2.3; sumds += 4.1; }
+        else if(seq[seq.length-1] == 'g' || seq[seq.length-1] == 'c') {sumdh += 0.1; sumds += -2.8; }
+
+        //Salt correction, von Shsen et al 1999
+        Settings settings = list.sequence.align.getSettings();
+        float saltconc = settings.getFloat(Settings.SALT_CONCENTRATION);
+        float mgconc = settings.getFloat(Settings.MG_CONCENTRATION);
+        float conc_primer = settings.getFloat(Settings.PRIMER_CONCENTRATION);
+        sumds += 0.368*(seq.length)*Math.log(saltconc/1000 + mgconc/1000*140);
+        _tm = (float)((1000*sumdh)/(sumds+(1.987*Math.log(conc_primer/2000000000)))-273.15);
+    }
+
+    public float getTm() {
+        return _tm;
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/RKIFile.java b/src/org/rki/sequenceeditor/model/RKIFile.java
new file mode 100644
index 0000000..fbb0018
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/RKIFile.java
@@ -0,0 +1,25 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class RKIFile {
+    public String name;
+    public String id;
+
+    public RKIFile(String name, int id) {
+        this.name = name;
+        this.id = new Integer(id).toString();
+    }
+
+    @Override
+    public String toString() {
+        return(name);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/RKIFolder.java b/src/org/rki/sequenceeditor/model/RKIFolder.java
new file mode 100644
index 0000000..1ab8e3b
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/RKIFolder.java
@@ -0,0 +1,25 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class RKIFolder {
+    public String name = "";
+    public String id = "";
+
+    public RKIFolder(String name, String id) {
+        this.name = name;
+        this.id = id;
+    }
+
+    @Override
+    public String toString() {
+        return(name);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/SNP.java b/src/org/rki/sequenceeditor/model/SNP.java
new file mode 100644
index 0000000..39d9b69
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/SNP.java
@@ -0,0 +1,13 @@
+package org.rki.sequenceeditor.model;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class SNP {
+    public int pos;
+
+    public SNP(int pos) {
+        this.pos = pos;
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/Sequence.java b/src/org/rki/sequenceeditor/model/Sequence.java
new file mode 100644
index 0000000..e180072
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Sequence.java
@@ -0,0 +1,184 @@
+package org.rki.sequenceeditor.model;
+
+import java.awt.Color;
+import java.util.HashMap;
+
+public class Sequence implements Comparable {
+    public String seq;
+    public String name;
+    public double homology = 0.0;
+    public boolean selected = false;
+    public boolean collapsed = false;
+    public AnnotationList above = new AnnotationList(true, this);
+    public AnnotationList below = new AnnotationList(false, this);
+    public Alignment align;
+
+    public GroupKey group;
+    
+    public Sequence(String name, String seq, GroupKey group, Alignment align) {
+        this.seq = seq;
+        this.name = name;
+        this.group = group;
+        this.align = align;
+    }
+
+    /**
+     * Creates complementary, inverted sequence.
+     */
+    public void invert() {
+        this.seq = invert(this.seq);
+    }
+    
+    public static String cleanUpSequence(String seq) {
+        seq = seq.replaceAll(" ", "");
+        seq = seq.replaceAll("[0-9]", "");
+        return(seq);
+    }
+
+    public static String invert(String sequence) {
+        char[] cseq = sequence.toCharArray();
+        HashMap<Character, Character> gc = Globals.complementary;
+        char[] nseq = new char[cseq.length];
+        for(int i=cseq.length-1; i>=0; i--) {
+            nseq[cseq.length-i-1] = Globals.complementary.get(cseq[i]);
+        }
+        return(new String(nseq));
+    }
+    
+    public void setCharAt(int pos, char ch) {
+        char[] cseq = seq.toCharArray();
+        cseq[pos] = ch;
+        this.seq = new String(cseq);
+    }
+    
+    public void calculateHomology(Sequence master) {
+        int minlen = Math.min(master.seq.length(), seq.length());
+        char[] mastercseq = master.seq.toCharArray();
+        char[] cseq = seq.toCharArray();
+        int identities = 0;
+        for(int i=0; i<minlen; i++) {
+            if(mastercseq[i] == cseq[i]) {
+                identities ++;
+            }
+        }
+        homology = (double)identities/(double)minlen;
+    }
+    
+    /**
+     * Adds an annotation to the sequence
+     * @param above true if annotation is to be added above the sequence, false otherwise
+     * @param from first base to be included in the annotation
+     * @param to last base to be included in the annotation
+     * @param text text of the annotation
+     */
+    public void addAnnotation(boolean above, int from, int to, String text, boolean primer) {
+        Annotation anno = null;
+        Color c = null;
+        if(primer && above)
+            c = Color.decode(align.getSettings().get(Settings.DEFAULT_FORWARD_PRIMER_COLOR).trim());
+        else if(primer && !above)
+            c = Color.decode(align.getSettings().get(Settings.DEFAULT_REVERSE_PRIMER_COLOR).trim());
+        else if(!primer && above)
+            c = Color.decode(align.getSettings().get(Settings.DEFAULT_ABOVE_ANNOTATION_COLOR).trim());
+        else if(!primer && !above)
+            c = Color.decode(align.getSettings().get(Settings.DEFAULT_BELOW_ANNOTATION_COLOR).trim());
+        if(primer)
+            anno = new Primer(from, to, c, text, above, this.above);
+        else
+            anno = new Annotation(from, to, c, text, this.below);
+        if(above) {
+            this.above.addAnnotation(anno);
+        }
+        else {
+            this.below.addAnnotation(anno);
+        }
+        if(primer) {
+            ((Primer)anno).updateOpposite();
+        }
+    }
+
+    public void updateProducts() {
+        for(Annotation anno : above.getAnnotations()) {
+            if(anno instanceof Primer) {
+                ((Primer)anno).updateOpposite();
+            }
+        }
+    }
+
+    public boolean removePart(int start, int end) {
+        if(start < 0)
+            start = 0;
+        if(end > seq.length()) {
+            end = seq.length();
+        }
+        if(start > end) {
+            int tmp = start;
+            start = end;
+            end = start;
+        }
+        char[] cseq = seq.toCharArray();
+        char[] res = new char[cseq.length - (end - start)];
+        int j=0;
+        for(int i=0; i<cseq.length; i++) {
+            if(i >= start && i < end) {
+                continue;
+            }
+            res[j] = cseq[i];
+            j++;
+        }
+        this.seq = new String(res);
+        return true;
+    }
+
+    /**  
+     * Moves part of the sequece
+     * 
+     * @param start beginning of slice to move
+     * @param end end of slice to move
+     * @param diff amount to move by
+     * @return true on success, false on failure (e.g. out of bounds) 
+     */
+    public boolean movePart(int start, int end, int diff) {
+        // In Editor, the selection is given as from (including) to (excluding). The
+        // calculations here are using bounds from (including) to (including).
+        end -= 1;
+        if(start+diff < 0 || end + diff > seq.length()) {
+            return(false);
+        }
+        char[] cseq = seq.toCharArray();
+        char[] tmp = new char[Math.abs(diff)];
+        if(diff > 0) {
+            for(int i=end+1; i<=end+diff; i++) {
+                tmp[i-end-1] = cseq[i];
+            }
+            for(int i=end; i>=start; i--) {
+                cseq[i+diff] = cseq[i];
+            }
+            for(int i=start; i<start+diff; i++) {
+                cseq[i] = tmp[i-start];
+            }
+        }
+        else if(diff < 0) {
+            diff *= -1;
+            for(int i=start-diff; i<start; i++) {
+                tmp[i-start+diff] = cseq[i];
+            }
+            for(int i=start; i<=end; i++) {
+                cseq[i-diff] = cseq[i];
+            }
+            for(int i=end-diff+1; i<=end; i++) {
+                cseq[i] = tmp[i-end+diff-1];
+            }
+        }
+        this.seq = new String(cseq);        
+        return(true);
+    }
+
+    public int compareTo(Object o) {
+        if(!(o instanceof Sequence)) {
+            return 0;
+        }
+        Sequence s = (Sequence)o;
+        return s.group.compareTo(group);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/Settings.java b/src/org/rki/sequenceeditor/model/Settings.java
new file mode 100644
index 0000000..07e1041
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/Settings.java
@@ -0,0 +1,191 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.swing.JOptionPane;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class Settings {
+    public static String[] SALT_CONCENTRATION = {"saltConcentration", "200"};
+    public static String[] MG_CONCENTRATION = {"mgConcentration", "0"};
+    public static String[] PRIMER_CONCENTRATION = {"primerConcentration", "50"};
+    public static String[] DISPLAY_PRIMER_LENGTH = {"displayPrimerLength", "1"};
+    public static String[] DISPLAY_PRIMER_TEMPERATURE = {"displayPrimerTemperature", "1"};
+    public static String[] DISPLAY_PRIMER_NAME = {"displayPrimerName", "1"};
+    public static String[] DISPLAY_IUB = {"DisplayIUB", "0"};
+    public static String[] DISPLAY_SEQUENCE_NAME = {"displaySequenceName", "1"};
+    public static String[] LAST_LOAD_PATH = {"lastLoadPath", "."};
+    public static String[] LAST_SAVE_PATH = {"lastSavePath", "."};
+    public static String[] DEFAULT_FORWARD_PRIMER_COLOR = {"defaultForwardPrimerColor", "0x0000ff"};
+    public static String[] DEFAULT_REVERSE_PRIMER_COLOR = {"defaultReversePrimerColor", "0x84b47f"};
+    public static String[] DEFAULT_ABOVE_ANNOTATION_COLOR = {"defaultAboveAnnotationColor", "0xff0000"};
+    public static String[] DEFAULT_BELOW_ANNOTATION_COLOR = {"defaultBelowAnnotationColor", "0xde842a"};
+    public static String[] SHOW_DTM_WARNING = {"showDeltaTmWarning", "1"};
+    public static String[] DTM_WARNING_TEMP = {"deltaTmWarningTemperature", "10"};
+    public static String[] DTM_WARNING_COLOR = {"deltaTmWarningColor", "0xff0000"};
+    public static String[] RECENT_FILES = {"recentFiles", ""};
+
+    public Map<String, String> settings = new HashMap<String, String>();
+
+    public Settings() {
+        load();
+    }
+
+    public String get(String[] keydef) {
+        return get(keydef[0], keydef[1]);
+    }
+
+    public String get(String key, String def) {
+        if(!settings.containsKey(key)) {
+            return def;
+        }
+        return settings.get(key);
+    }
+
+    public float getFloat(String[] keydef) {
+        return getFloat(keydef[0], Float.parseFloat(keydef[1]));
+    }
+
+    public float getFloat(String key, float def) {
+        if(!settings.containsKey(key)) {
+            return def;
+        }
+        return Float.parseFloat(settings.get(key));
+    }
+
+    public boolean getBoolean(String[] keydef) {
+        return getBoolean(keydef[0], Integer.parseInt(keydef[1])!=0);
+    }
+
+    public boolean getBoolean(String key, boolean def) {
+        if(!settings.containsKey(key)) {
+            return def;
+        }
+        return Integer.parseInt(settings.get(key)) != 0;
+    }
+
+    public String[] getStringArray(String key, String[] def) {
+        if(!settings.containsKey(key)) {
+            if(def == null) {
+                String[] res = {};
+                return res;
+            }
+            return def;
+        }
+        String val = settings.get(key);
+        return val.split("\t");
+    }
+
+    public void set(String[] key, String value) {
+        set(key[0], value);
+    }
+
+    public void set(String key, String value) {
+        settings.put(key, value);
+        save();
+    }
+
+    public void set(String[] key, boolean value) {
+        set(key[0], value);
+    }
+    public void set(String key, boolean value) {
+        settings.put(key, Integer.toString(value?1:0));
+        save();
+    }
+
+    public void set(String[] key, int value) {
+        set(key[0], value);
+    }
+
+    public void set(String key, int value) {
+        settings.put(key, Integer.toString(value));
+        save();
+    }
+
+    public void set(String[] key, float value) {
+        set(key[0], value);
+    }
+
+    public void set(String key, float value) {
+        settings.put(key, Float.toString(value));
+        save();
+    }
+
+    public void set(String[] key, double value) {
+        set(key[0], value);
+    }
+
+    public void set(String key, double value) {
+        settings.put(key, Double.toString(value));
+        save();
+    }
+
+    public void set(String[] key, String[] value) {
+        set(key[0], value);
+    }
+
+    public void set(String key, String[] values) {
+        StringBuilder res = new StringBuilder();
+        for(int i=0; i<values.length; i++) {
+            res.append(values[i]);
+            res.append((i!=values.length-1?"\t":""));
+        }
+        settings.put(key, res.toString());
+        save();
+    }
+
+    public final void load() {
+        try {
+            File file = new File(".settings");
+            if(!file.exists())
+                return;
+            BufferedReader input = new BufferedReader(new FileReader(file));
+            while(input.ready()) {
+                String line = input.readLine();
+                String key = line.substring(0, line.indexOf('='));
+                if(key.length() != 0) {
+                    settings.put(key, line.substring(line.indexOf('=')+1).trim());
+                }
+            }
+        }
+        catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "Setting file '.settings' could not be opened for reading. Check permissions.", "Error loading file", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    public void save() {
+        BufferedWriter out = null;
+        try {
+            out = new BufferedWriter(new FileWriter(".settings"));
+        } catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "Settings file '.settings' could not be opened for writing. Check permissions.", "Error saving file", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        try {
+            for(String key : settings.keySet()) {
+                out.write(key);
+                out.write("=");
+                out.write(settings.get(key));
+                out.write("\n");
+            }
+            out.close();
+        } catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "Could not write settings to file. Check disk space.", "Error saving file", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/SizeMenuItem.java b/src/org/rki/sequenceeditor/model/SizeMenuItem.java
new file mode 100644
index 0000000..b4d8844
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/SizeMenuItem.java
@@ -0,0 +1,18 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model;
+
+import javax.swing.JMenuItem;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class SizeMenuItem extends JMenuItem {
+    public SizeMenuItem(String name) {
+        super(name);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/TripletMenuItem.java b/src/org/rki/sequenceeditor/model/TripletMenuItem.java
new file mode 100644
index 0000000..8a45adc
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/TripletMenuItem.java
@@ -0,0 +1,9 @@
+package org.rki.sequenceeditor.model;
+
+import javax.swing.JMenuItem;
+
+public class TripletMenuItem extends JMenuItem {
+    public TripletMenuItem(String name) {
+        super(name);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/filters/BasicFastaFilter.java b/src/org/rki/sequenceeditor/model/filters/BasicFastaFilter.java
new file mode 100644
index 0000000..dcfd328
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/filters/BasicFastaFilter.java
@@ -0,0 +1,77 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model.filters;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.HashMap;
+import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
+import org.rki.sequenceeditor.model.Alignment;
+import org.rki.sequenceeditor.model.GroupKey;
+import org.rki.sequenceeditor.model.Sequence;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+
+public class BasicFastaFilter extends FileFilter implements SaveFilter {
+
+    private String[] _allowedExtensions = {".fas", ".fasta"};
+
+    @Override
+    public boolean accept(File f) {
+        if(f.isDirectory()) {
+            return(true);
+        }
+        String name = f.getName().toLowerCase();
+        for(String ext : _allowedExtensions) {
+            if(name.endsWith(ext))
+                return true;
+        }
+        return(false);
+    }
+
+    @Override
+    public String getDescription() {
+        return("Blank FASTA file");
+    }
+
+    @Override
+    public String getExtension() {
+        return(".fas");
+    }
+
+    @Override
+    public void saveAlignment(Alignment align, String filename) {
+        BufferedWriter out = null;
+        try {
+            out = new BufferedWriter(new FileWriter(filename));
+        } catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "File could not be opened for writing. Check permissions.", "Error saving file", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        boolean hasGroups = align.getGroups().size()>1;
+        try {
+            for(Sequence seq : align.getSequencesAll()) {
+                out.write(">" + seq.name);
+                out.write("\n");
+                out.write(seq.seq);
+                out.write("\n");
+            }
+            out.close();
+        } catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "Could not write to file. Check disk space.", "Error saving file", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+    }
+
+}
diff --git a/src/org/rki/sequenceeditor/model/filters/FastaFilter.java b/src/org/rki/sequenceeditor/model/filters/FastaFilter.java
new file mode 100644
index 0000000..e249a77
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/filters/FastaFilter.java
@@ -0,0 +1,141 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model.filters;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.HashMap;
+import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
+import org.rki.sequenceeditor.model.Alignment;
+import org.rki.sequenceeditor.model.GroupKey;
+import org.rki.sequenceeditor.model.Sequence;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+
+public class FastaFilter extends FileFilter implements SaveFilter, LoadFilter {
+    
+    private String[] _allowedExtensions = {".fas", ".fasta"};
+    
+    @Override
+    public boolean accept(File f) {
+        if(f.isDirectory()) {
+            return(true);
+        }
+        String name = f.getName().toLowerCase();
+        for(String ext : _allowedExtensions) {
+            if(name.endsWith(ext))
+                return true;
+        }
+        return(false);
+    }
+
+    @Override
+    public String getDescription() {
+        return("FASTA file (preserves grouping)");
+    }
+
+    @Override
+    public String getExtension() {
+        return(".fas");
+    }
+
+    @Override
+    public void saveAlignment(Alignment align, String filename) {
+        BufferedWriter out = null;
+        try {
+            out = new BufferedWriter(new FileWriter(filename));
+        } catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "File could not be opened for writing. Check permissions.", "Error saving file", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        boolean hasGroups = align.getGroups().size()>1;
+        try {
+            for(Sequence seq : align.getSequencesAll()) {
+                out.write(">" + seq.name);
+                if(hasGroups) {
+                    out.write("%%" + seq.group.getName() + "%%");
+                }
+                out.write("\n");
+                out.write(seq.seq);
+                out.write("\n");
+            }
+            out.close();
+        } catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "Could not write to file. Check disk space.", "Error saving file", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+    }
+
+    @Override
+    public void loadAlignment(String filename, Alignment align, GroupKey baseGroup) {
+        try {
+            File file = new File(filename);
+            BufferedReader input = new BufferedReader(new FileReader(file));
+            StringBuilder s = new StringBuilder();
+            while(input.ready()) {
+                s.append(input.readLine());
+                s.append("\n");
+            }
+            loadString(s.toString(), align, baseGroup);
+        }
+        catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "File could not be opened for reading. Check permissions.", "Error loading file", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    public void loadString(String s, Alignment align, GroupKey baseGroup) {
+        System.out.println("Loading...");
+        String[] lines = s.split(">");
+        HashMap<String, GroupKey> loadedGroups = new HashMap<String, GroupKey>();
+//        if(!overwrite) {
+            for(GroupKey key : align.getGroups()) {
+                if(!loadedGroups.containsKey(key.getName())) {
+                    loadedGroups.put(key.getName(), key);
+                }
+            }
+//        }
+        for(String line : lines) {
+            if(line.equals("")) continue;
+            String[] vals = line.split("\n");
+            String name = vals[0];
+            vals[0] = "";
+            StringBuilder seqBuilder = new StringBuilder();
+            for(String val : vals) {
+                seqBuilder.append(val.replace("\r", "").replace(" ", ""));
+            }
+            String seq = seqBuilder.toString().toUpperCase();
+            GroupKey group = baseGroup;
+            if(loadedGroups.containsKey(baseGroup.getName())) {
+                group = loadedGroups.get(baseGroup.getName());
+            }
+            // Get the name of the group the sequence belongs to from the name
+            if(name.contains("%%")) {
+                String[] nameVals = name.split("%%");
+                name = nameVals[0];
+                String groupName = nameVals[1];
+                if(loadedGroups.containsKey(groupName)) {
+                    group = loadedGroups.get(groupName);
+                }
+                else {
+                    group = new GroupKey(groupName);
+                    loadedGroups.put(groupName, group);
+                }
+            }
+            align.addSequence(new Sequence(name, seq, group, align));
+        }
+        for(GroupKey group : loadedGroups.values()) {
+            System.out.println(group.getName());
+        }
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/filters/GeneiousFilter.java b/src/org/rki/sequenceeditor/model/filters/GeneiousFilter.java
new file mode 100644
index 0000000..d42ba17
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/filters/GeneiousFilter.java
@@ -0,0 +1,200 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model.filters;
+
+import com.sun.org.apache.xerces.internal.dom.DOMImplementationImpl;
+import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
+import org.rki.sequenceeditor.model.Alignment;
+import org.rki.sequenceeditor.model.Annotation;
+import org.rki.sequenceeditor.model.Sequence;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Rich sequence format filter. See http://www.hku.hk/bruhk/gcgdoc/using_sequences.html
+ * for documentation.
+ * @author dabrowskiw
+ */
+
+public class GeneiousFilter extends FileFilter implements SaveFilter {
+    private String[] _allowedExtensions = {".geneious"};
+    
+    @Override
+    public boolean accept(File f) {
+        if(f.isDirectory()) {
+            return(true);
+        }
+        String name = f.getName().toLowerCase();
+        for(String ext : _allowedExtensions) {
+            if(name.endsWith(ext))
+                return true;
+        }
+        return(false);
+    }
+
+    @Override
+    public String getDescription() {
+        return("Geneious file (preserves annotations and grouping)");
+    }
+
+    @Override
+    public String getExtension() {
+        return(".geneious");
+    }
+
+    @Override
+    public void saveAlignment(Alignment align, String filename) {
+        DOMImplementation impl = DOMImplementationImpl.getDOMImplementation();
+        Document doc = impl.createDocument(null, "geneious", null);
+        Element root = doc.createElement("geneious");
+        root.setAttribute("version", "4.8.3");
+        Element fullDoc = doc.createElement("fullDocument");
+        fullDoc.setAttribute("class", "com.biomatters.geneious.publicapi.implementations.DefaultAlignmentDocument");
+        fullDoc.setAttribute("version", "1.3-11");
+        fullDoc.setAttribute("revisionNumber", "2");
+        fullDoc.setAttribute("geneiousVersion", "4.8.3");
+        fullDoc.setAttribute("isReferenceOnly", "false");
+        root.appendChild(fullDoc);
+        Element hiddenFields = doc.createElement("hiddenFields");
+        Element cacheUrn = doc.createElement("cache_urn");
+        cacheUrn.setAttribute("type", "urn");
+        cacheUrn.setTextContent("urn:local:externally_generated:" + new Integer((int)(10000000*Math.random())).toString());
+        hiddenFields.appendChild(cacheUrn);
+        Element el = doc.createElement("description");
+        el.setTextContent("File generated by RKI-Tools");
+        hiddenFields.appendChild(el);
+        el = doc.createElement("cache_name");
+        el.setTextContent("Alignment file");
+        hiddenFields.appendChild(el);
+        el = doc.createElement("cache_plugin_document_urn");
+        hiddenFields.appendChild(el);
+        fullDoc.appendChild(hiddenFields);
+
+        Element originalElement = doc.createElement("originalElement");
+        Element alignmentDoc = doc.createElement("DefaultAlignmentDocument");
+        el = doc.createElement("alphabet");
+        el.setTextContent("NUCLEOTIDE");
+        alignmentDoc.appendChild(el);
+
+        el = doc.createElement("name");
+        el.setTextContent("Alignment file");
+        alignmentDoc.appendChild(el);
+        Element sequences = doc.createElement("sequences");
+
+        for(Sequence seq : align.getSequencesAll()) {
+            Element sequence = doc.createElement("seq");
+            sequence.setAttribute("type", "DefaultNucleotideSequence");
+            el = doc.createElement("name");
+            el.setTextContent(seq.name);
+            sequence.appendChild(el);
+            el = doc.createElement("description");
+            el.setTextContent("%%" + seq.group.getName() + "%%");
+            sequence.appendChild(el);
+
+            if(seq.below.getAnnotations().size() != 0 || seq.above.getAnnotations().size() != 0) {
+                Element seqAnnos = doc.createElement("sequenceAnnotations");
+                for(Annotation anno : seq.above.getAnnotations()) {
+                    Element annotation = doc.createElement("annotation");
+                    el = doc.createElement("description");
+                    el.setTextContent(anno.text);
+                    annotation.appendChild(el);
+                    el = doc.createElement("type");
+                    el.setTextContent(Integer.toHexString(anno.background.getRGB()).substring(2));
+                    annotation.appendChild(el);
+                    Element intervals = doc.createElement("intervals");
+                    Element interval = doc.createElement("interval");
+
+                    el = doc.createElement("minimumIndex");
+                    el.setTextContent(new Integer(anno.from).toString());
+                    interval.appendChild(el);
+
+                    el = doc.createElement("maximumIndex");
+                    el.setTextContent(new Integer(anno.to).toString());
+                    interval.appendChild(el);
+
+                    el = doc.createElement("direction");
+                    el.setTextContent("leftToRight");
+                    interval.appendChild(el);
+
+
+                    intervals.appendChild(interval);
+                    annotation.appendChild(intervals);
+                    seqAnnos.appendChild(annotation);
+                }
+                for(Annotation anno : seq.below.getAnnotations()) {
+                    Element annotation = doc.createElement("annotation");
+                    el = doc.createElement("description");
+                    el.setTextContent(anno.text);
+                    annotation.appendChild(el);
+                    el = doc.createElement("type");
+                    el.setTextContent(Integer.toHexString(anno.background.getRGB()).substring(2));
+                    annotation.appendChild(el);
+                    Element intervals = doc.createElement("intervals");
+                    Element interval = doc.createElement("interval");
+
+                    el = doc.createElement("minimumIndex");
+                    el.setTextContent(new Integer(anno.from).toString());
+                    interval.appendChild(el);
+
+                    el = doc.createElement("maximumIndex");
+                    el.setTextContent(new Integer(anno.to).toString());
+                    interval.appendChild(el);
+
+                    el = doc.createElement("direction");
+                    el.setTextContent("rightToLeft");
+                    interval.appendChild(el);
+
+
+                    intervals.appendChild(interval);
+                    annotation.appendChild(intervals);
+                    seqAnnos.appendChild(annotation);
+                }
+                sequence.appendChild(seqAnnos);
+            }
+
+
+            el = doc.createElement("charSequence");
+            if(seq.seq.length() < align.getLongestAll()) {
+                el.setAttribute("gapSuffixLength", new Integer(align.getLongestAll()-seq.seq.length()).toString());
+            }
+            el.setTextContent(seq.seq);
+            sequence.appendChild(el);
+            sequences.appendChild(sequence);
+        }
+
+        alignmentDoc.appendChild(sequences);
+        originalElement.appendChild(alignmentDoc);
+        fullDoc.appendChild(originalElement);
+        boolean hasGroups = align.getGroups().size()>1;
+        try {
+            ByteArrayOutputStream bout = new ByteArrayOutputStream();
+            XMLSerializer serializer = new XMLSerializer(bout, null);
+            serializer.serialize(root);
+            ZipOutputStream zout = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(filename)));
+            ZipEntry entry = new ZipEntry(filename);
+            zout.putNextEntry(entry);
+            zout.write(bout.toByteArray());
+            zout.close();
+        } catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "Could not write to file. Check permissions and disk space.", "Error saving file", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+    }
+
+}
diff --git a/src/org/rki/sequenceeditor/model/filters/LoadFilter.java b/src/org/rki/sequenceeditor/model/filters/LoadFilter.java
new file mode 100644
index 0000000..42c3876
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/filters/LoadFilter.java
@@ -0,0 +1,18 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model.filters;
+
+import org.rki.sequenceeditor.model.Alignment;
+import org.rki.sequenceeditor.model.GroupKey;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public interface LoadFilter {
+    public String getExtension();
+    public void loadAlignment(String filename, Alignment align, GroupKey baseGroup);
+}
diff --git a/src/org/rki/sequenceeditor/model/filters/RSFFilter.java b/src/org/rki/sequenceeditor/model/filters/RSFFilter.java
new file mode 100644
index 0000000..cfea618
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/filters/RSFFilter.java
@@ -0,0 +1,281 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model.filters;
+
+import java.awt.Color;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.LinkedList;
+import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
+import org.rki.sequenceeditor.model.Alignment;
+import org.rki.sequenceeditor.model.Annotation;
+import org.rki.sequenceeditor.model.GroupKey;
+import org.rki.sequenceeditor.model.Primer;
+import org.rki.sequenceeditor.model.Sequence;
+
+/**
+ * Rich sequence format filter. See http://www.hku.hk/bruhk/gcgdoc/using_sequences.html
+ * for documentation.
+ * @author dabrowskiw
+ */
+
+public class RSFFilter extends FileFilter implements SaveFilter, LoadFilter {
+    private String[] _allowedExtensions = {".rsf"};
+    
+    private static int STATE_NONE = -1;
+    private static int STATE_ATTRIBUTES = 0;
+    private static int STATE_COMMENT = 1;
+    private static int STATE_FEATURE = 2;
+    private static int STATE_SEQUENCE = 3;
+
+
+    @Override
+    public boolean accept(File f) {
+        if(f.isDirectory()) {
+            return(true);
+        }
+        String name = f.getName().toLowerCase();
+        for(String ext : _allowedExtensions) {
+            if(name.endsWith(ext))
+                return true;
+        }
+        return(false);
+    }
+
+    @Override
+    public String getDescription() {
+        return("Rich Sequence Format (preserves annotations and grouping)");
+    }
+
+    @Override
+    public String getExtension() {
+        return(".rsf");
+    }
+
+    @Override
+    public void saveAlignment(Alignment align, String filename) {
+        BufferedWriter out = null;
+        try {
+            out = new BufferedWriter(new FileWriter(filename));
+        } catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "File could not be opened for writing. Check permissions.", "Error saving file", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+        boolean hasGroups = align.getGroups().size()>1;
+        try {
+            out.write("!!RICH_SEQUENCE 1.0\n");
+            out.write("..\n");
+            for(Sequence seq : align.getSequencesAll()) {
+                out.write("{\n");
+                out.write("name    " + seq.name + "\n");
+                out.write("descrip Sequence exported from RKI-Tools\n");
+                out.write("type    DNA\n");
+                out.write("strands 1\n");
+                if(hasGroups) {
+                    out.write("comments\n    %%" + seq.group.getName() + "%%\n");
+                }
+                for(Annotation anno : seq.above.getAnnotations()) {
+                    writeAnnotation(anno, out);
+                }
+                for(Annotation anno : seq.below.getAnnotations()) {
+                    writeAnnotation(anno, out);
+                }
+                out.write("sequence\n    ");
+                out.write(seq.seq);
+                out.write("\n}\n");
+            }
+            out.close();
+        } catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "Could not write to file. Check disk space.", "Error saving file", JOptionPane.ERROR_MESSAGE);
+            return;
+        }
+    }
+
+    private void writeAnnotation(Annotation anno, BufferedWriter out) throws IOException {
+        String direction = anno.list.above?"right_arrow":"left_arrow";
+        if(anno instanceof Primer) {
+            Primer primer = (Primer)anno;
+            if(primer.isPyro)
+                out.write("feature " + primer.from + " " +primer.to + " 0x" + Integer.toHexString(primer.background.getRGB()).substring(2)+ " " + direction + " t_star ANNOTATION\n    " + primer.text + "%%--%%" + primer.getSequence() + "\n");
+            else
+                out.write("feature " + primer.from + " " +primer.to + " 0x" + Integer.toHexString(primer.background.getRGB()).substring(2)+ " " + direction + " t_diamond ANNOTATION\n    " + primer.text + "%%--%%" + primer.getSequence() + "\n");
+        }
+        else {
+            out.write("feature " + anno.from + " " + anno.to + " 0x" + Integer.toHexString(anno.background.getRGB()).substring(2)+ " " + direction + " t_hash ANNOTATION\n    " + anno.text + "\n");
+        }
+    }
+
+    @Override
+    public void loadAlignment(String filename, Alignment align, GroupKey baseGroup) {
+        try {
+            File file = new File(filename);
+            BufferedReader input = new BufferedReader(new FileReader(file));
+            int headerLine = 0;
+            while(input.ready()) {
+                String line = input.readLine();
+                if(headerLine == 0 && !line.startsWith("!!RICH_SEQUENCE 1.0")) {
+                    JOptionPane.showMessageDialog(null, "File seems not to be in rich sequence format (missing header).", "Error loading file", JOptionPane.ERROR_MESSAGE);
+                    return;
+                }
+                headerLine ++;
+                if(line.startsWith(".."))
+                    break;
+            }
+            HashMap<String, GroupKey> loadedGroups = new HashMap<String, GroupKey>();
+            for(GroupKey key : align.getGroups()) {
+                if(!loadedGroups.containsKey(key.getName())) {
+                    loadedGroups.put(key.getName(), key);
+                }
+            }
+
+            int state = STATE_NONE;
+            Annotation anno = null;
+            LinkedList<Annotation> below = new LinkedList<Annotation>();
+            LinkedList<Annotation> above = new LinkedList<Annotation>();
+            StringBuilder builder = new StringBuilder();
+            String comment = "";
+            String sequence = "";
+            String name = "";
+            boolean annotationBelow = false;
+            while(input.ready()) {
+                String line = input.readLine();
+                if(line.startsWith("{")) {
+                    state = STATE_ATTRIBUTES;
+                    continue;
+                }
+                else if(line.startsWith("}")) {
+                    if(state == STATE_SEQUENCE)
+                        sequence = builder.toString();
+                    if(state == STATE_COMMENT)
+                        comment = builder.toString();
+                    sequence = sequence.trim();
+                    String[] commentDetails = comment.split("%%");
+                    Sequence seq = null;
+                    GroupKey group = baseGroup;
+                    if(commentDetails.length > 1) {
+                        String groupName = commentDetails[1];
+                        if(loadedGroups.containsKey(groupName)) {
+                            group = loadedGroups.get(groupName);
+                        }
+                        else {
+                            group = new GroupKey(groupName);
+                            loadedGroups.put(groupName, group);
+                        }
+                    }
+                    seq = new Sequence(name, sequence, group, align);
+                    for(Annotation a : above) {
+                        seq.above.addAnnotation(a);
+                        a.list = seq.above;
+                    }
+                    for(Annotation a : below) {
+                        seq.below.addAnnotation(a);
+                        a.list = seq.below;
+                    }
+                    align.addSequence(seq);
+                    below = new LinkedList<Annotation>();
+                    above = new LinkedList<Annotation>();
+                    comment = "";
+                    sequence = "";
+                    name = "";
+                }
+                else if(line.startsWith("comments")) {
+                    if(state == STATE_SEQUENCE)
+                        sequence = builder.toString();
+                    state = STATE_COMMENT;
+                    builder = new StringBuilder();
+                    continue;
+                }
+                else if(line.startsWith("sequence")) {
+                    if(state == STATE_COMMENT)
+                        comment = builder.toString();
+                    state = STATE_SEQUENCE;
+                    builder = new StringBuilder();
+                    continue;
+                }
+                else if(line.startsWith("feature")) {
+                    annotationBelow = false;
+                    if(state == STATE_SEQUENCE)
+                        sequence = builder.toString();
+                    if(state == STATE_COMMENT)
+                        comment = builder.toString();
+                    String[] featureData = line.split("\\s");
+                    if(featureData[4].equals("left_arrow"))
+                        annotationBelow = true;
+                    if(featureData[5].equals("t_diamond") || featureData[5].equals("t_star")) {
+                        anno = new Primer(Integer.decode(featureData[1]),
+                            Integer.decode(featureData[2]), Color.decode(featureData[3]), "", !annotationBelow, null);
+                        if(featureData[5].equals("t_star")) {
+                            ((Primer)anno).isPyro = true;
+                        }
+                    }
+                    else {
+                        anno = new Annotation(Integer.decode(featureData[1]),
+                            Integer.decode(featureData[2]), Color.decode(featureData[3]), "", null);
+                    }
+                    state = STATE_FEATURE;
+                    continue;
+                }
+                else if(state == STATE_FEATURE) {
+                    if(anno instanceof Primer) {
+                        String[] primerData = line.split("%%--%%");
+                        Primer primer = (Primer)anno;
+                        primer.text = primerData[0].trim();
+                        primer.loadSequence = primerData[1];
+                    }
+                    else
+                        anno.text = line.trim();
+                    if(annotationBelow)
+                        below.add(anno);
+                    else
+                        above.add(anno);
+                    anno = null;
+                    state = STATE_ATTRIBUTES;
+                    continue;
+                }
+                else if(state == STATE_COMMENT) {
+                    builder.append(line);
+                }
+                else if(state == STATE_SEQUENCE) {
+                    builder.append(line);
+                }
+                else if(line.startsWith("name")) {
+                    name = line.substring(4).trim();
+                }
+            }
+            for(Sequence seq : align.getSequencesAll()) {
+                for(Annotation annotation : seq.above.getAnnotations()) {
+                    if(annotation instanceof Primer) {
+                        finalizePrimer((Primer)annotation);
+                    }
+                }
+                for(Annotation annotation : seq.below.getAnnotations()) {
+                    if(annotation instanceof Primer) {
+                        finalizePrimer((Primer)annotation);
+                    }
+                }
+            }
+        }
+        catch(IOException e) {
+            JOptionPane.showMessageDialog(null, "File could not be opened for reading. Check permissions.", "Error loading file", JOptionPane.ERROR_MESSAGE);
+        }
+    }
+
+    private void finalizePrimer(Primer primer) {
+        char[] loadSequence = primer.loadSequence.toCharArray();
+        for(int pos=0; pos<loadSequence.length; pos++) {
+            primer.lockBase(pos, loadSequence[pos]);
+        }
+        primer.updateScores();
+        primer.updateOpposite();
+        primer.updateTm();
+    }
+}
diff --git a/src/org/rki/sequenceeditor/model/filters/SaveFilter.java b/src/org/rki/sequenceeditor/model/filters/SaveFilter.java
new file mode 100644
index 0000000..ef6a1d3
--- /dev/null
+++ b/src/org/rki/sequenceeditor/model/filters/SaveFilter.java
@@ -0,0 +1,17 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.model.filters;
+
+import org.rki.sequenceeditor.model.Alignment;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public interface SaveFilter {
+    public String getExtension();
+    public void saveAlignment(Alignment align, String filename);
+}
diff --git a/src/org/rki/sequenceeditor/view/AnnotationTextField.java b/src/org/rki/sequenceeditor/view/AnnotationTextField.java
new file mode 100644
index 0000000..665ec0c
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/AnnotationTextField.java
@@ -0,0 +1,17 @@
+package org.rki.sequenceeditor.view;
+
+import javax.swing.JTextField;
+
+public class AnnotationTextField extends JTextField {
+    public boolean correctText = false;
+    public boolean isAdded = false;
+    
+    public AnnotationTextField() {
+        super();
+    }
+    
+    public AnnotationTextField(String name) {
+        super(name);
+    }
+
+}
diff --git a/src/org/rki/sequenceeditor/view/BlingFilter.java b/src/org/rki/sequenceeditor/view/BlingFilter.java
new file mode 100644
index 0000000..7c1ae66
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/BlingFilter.java
@@ -0,0 +1,70 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ColorModel;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class BlingFilter implements BufferedImageOp {
+
+    private int _step;
+
+    public BlingFilter(int step) {
+        _step = step;
+    }
+
+    private void drawGradient(int x, int width, int imageWidth, int imageHeight, Graphics2D g) {
+        for(int i=x-width; i<x+width; i++) {
+//            if(i<0)
+//                continue;
+            float alpha = 0.5f*(1-(float)((i-x)*(i-x))/(float)(width*width));
+            g.setColor(new Color(1.0f, 1.0f, 1.0f, alpha));
+            g.drawLine(i, 0, i-width, imageHeight);
+        }
+    }
+
+    @Override
+    public BufferedImage filter(BufferedImage arg0, BufferedImage arg1) {
+        BufferedImage tmp = new BufferedImage(arg0.getWidth(), arg0.getHeight(), BufferedImage.TYPE_INT_ARGB);
+        Graphics2D g = tmp.createGraphics();
+        g.drawImage(arg0, 0, 0, null);
+//        g.setColor(new Color(0.0f, 1.0f, 0.0f, 0.5f));
+//        g.drawLine(0+_step, 0, 50+_step, 50);
+        drawGradient(_step, arg0.getHeight(), arg0.getWidth(), arg0.getHeight(), g);
+        return tmp;
+    }
+
+    @Override
+    public Rectangle2D getBounds2D(BufferedImage arg0) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public BufferedImage createCompatibleDestImage(BufferedImage arg0, ColorModel arg1) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public Point2D getPoint2D(Point2D arg0, Point2D arg1) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public RenderingHints getRenderingHints() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+}
diff --git a/src/org/rki/sequenceeditor/view/ColorModelMenuItem.java b/src/org/rki/sequenceeditor/view/ColorModelMenuItem.java
new file mode 100644
index 0000000..5a4d902
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/ColorModelMenuItem.java
@@ -0,0 +1,18 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import javax.swing.JMenuItem;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class ColorModelMenuItem extends JMenuItem {
+    public ColorModelMenuItem(String name) {
+        super(name);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/view/Editor.html b/src/org/rki/sequenceeditor/view/Editor.html
new file mode 100644
index 0000000..cba6033
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/Editor.html
@@ -0,0 +1,35 @@
+<HTML>
+<HEAD>
+   <TITLE>Applet HTML Page</TITLE>
+</HEAD>
+<BODY>
+
+
+<!--
+*** GENERATED applet HTML launcher - DO NOT EDIT IN 'BUILD' FOLDER ***
+
+If you need to modify this HTML launcher file (e.g., to add applet parameters), 
+copy it to where your applet class is found in the SRC folder. If you do this, 
+the IDE will use it when you run or debug the applet.
+
+Tip: To exclude an HTML launcher from the JAR file, use exclusion filters in 
+the Packaging page in the Project Properties dialog.
+
+For more information see the online help.
+-->
+
+<H3>Applet HTML Page</H3>
+
+<P>
+<!--<APPLET codebase="classes" code="org/rki/sequenceeditor/view/Editor.class" width=1024 height=768>-->
+<APPLET codebase="classes" code="org/rki/sequenceeditor/view/Editor.class" width=1280 height=1024>
+    <PARAM NAME="baseurl" VALUE="http://10.15.144.146:8000/filestore/">
+    <PARAM NAME="fileId" VALUE="423">
+    <PARAM NAME="username" VALUE="wojtek">
+    
+</APPLET>
+</P>
+
+<HR WIDTH="100%"><FONT SIZE=-1><I>Generated by NetBeans IDE</I></FONT>
+</BODY>
+</HTML>
diff --git a/src/org/rki/sequenceeditor/view/Editor.java b/src/org/rki/sequenceeditor/view/Editor.java
new file mode 100644
index 0000000..93b6af7
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/Editor.java
@@ -0,0 +1,1399 @@
+package org.rki.sequenceeditor.view;
+
+import java.applet.Applet;
+import java.awt.event.AdjustmentEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseWheelEvent;
+import org.rki.sequenceeditor.*;
+import org.rki.sequenceeditor.model.*;
+import java.awt.*;
+import java.awt.event.MouseEvent;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Collection;
+import java.util.LinkedList;
+import javax.swing.JFileChooser;
+import javax.swing.JSplitPane;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import java.util.HashMap;
+import javax.swing.JScrollBar;
+import javax.swing.tree.DefaultMutableTreeNode;
+import org.rki.sequenceeditor.model.filters.FastaFilter;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.rki.sequenceeditor.model.filters.LoadFilter;
+
+public class Editor extends Applet implements EditorInterface {
+    
+    public static String VERSION = "0.9.2";
+    public static int MODE_NORMAL = 0;
+    public static int MODE_EDITING = 1;
+    public static int MODE_MOVESEL = 2;
+    public static int MODE_MOVEANNO = 3;
+    public static int MODE_SELECTING = 4;
+    public static int MODE_SELECTING2 = 5;
+    
+    private static final long serialVersionUID = 1L;
+    private int[] _offset = {0, 0};
+    public int _mouseButton;
+    private double _lw = 12;
+    private int minLineHeight = 8;
+    private int _width = 1024-40;
+    private int _height = 768;
+    private int _movePos = 0;
+    public int consHeight = 10;
+    public int groupSep = 5;
+    public int[] _lastMousePos = {0, 0};
+    public int[] selFrom = {0,0};
+    public int[] selTo = {0,0};
+    public boolean selConsensus = false;
+    public GroupKey consensusGroup = null;
+//    public double[] conservation = null;
+    public int mode = MODE_NORMAL;
+    public MasterSequence masterSequenceAll = null;
+    public HashMap<GroupKey, MasterSequence> masterSequences = new HashMap<GroupKey, MasterSequence>();
+    public Annotation editedAnnotation;
+    public Annotation selectedAnnotation;
+    private SequencePane _seqPane;
+    private NamesPane _namesPane;
+    private JSplitPane _sp;
+    private JScrollBar _scrollBar = new JScrollBar(JScrollBar.VERTICAL);
+    private JScrollBar _hscrollBar = new JScrollBar(JScrollBar.HORIZONTAL);
+    private Alignment _align = new Alignment(null);
+    public SequenceInfo _toolTip = new SequenceInfo();
+//    public JPopupMenu _toolTip = null;
+//    public JMenuItem _toolTipText = null;
+    public int rulerHeight = 17;
+    public int annotationHeight = (int)_lw+4;
+    // Attention! Must be multiple of 3!
+    public int tripletDist = 6;
+    private int _lastSelected = -1;
+    private int[] _lastPos = {0,0};
+    private String _lastSearch = "";
+    private boolean _lastSearchAllowedGaps = false;
+    public GroupKey baseGroup = new GroupKey("All");
+    
+    private LinkedList<int[]> _conservedRegions;
+    private int _conservedRegionsIndex = 0;
+    
+    public String baseUrl;
+    private String fileId;
+    private String username;
+
+    private Settings _settings = new Settings();
+    
+    public Editor() {
+        super();
+    }
+
+    public boolean hasMenu() {
+        return false;
+    }
+
+    public boolean useIUB() {
+        return false;
+    }
+
+    public boolean showSequenceName() {
+        return true;
+    }
+    public String readFromURL(String url) throws MalformedURLException, IOException {
+        System.out.println(url);
+        URL rkitools = new URL(url);
+        URLConnection rc = rkitools.openConnection();
+        BufferedReader rcr = new BufferedReader(new InputStreamReader(rc.getInputStream()));
+        StringBuilder db = new StringBuilder();
+        while(true) {
+            if(!rcr.ready()) {
+                try {
+                    Thread.sleep(1000);
+                } catch(Exception e) {}
+                if(!rcr.ready()) {
+                    break;
+                }
+            }
+            db.append(rcr.readLine());
+            db.append("\n");
+        }
+        String data = db.toString();
+        return data;
+    }
+    
+    private void loadFromRKITools(String url, String fileId, boolean overwrite) {
+        try {
+            String data = readFromURL(url + fileId + "/");
+            loadString(data, overwrite);
+        } catch (MalformedURLException e) {
+            System.out.println("Error:" + e.getMessage() + e.toString());
+            e.printStackTrace();
+        }
+        catch (IOException e) {
+            System.out.println("Error:" + e.getMessage() + e.toString());            
+            e.printStackTrace();
+        }
+        requestFocusInWindow();
+    }
+
+    @Override
+    public boolean isSelectionActive() {
+        return false;
+    }
+
+    @Override
+    public String seqsToString(boolean pureFASTA) {
+        StringBuilder datab = new StringBuilder();
+        for(Sequence s : _align.getSequencesAll()) {
+            datab.append(">" + s.name);
+            if(!pureFASTA) {
+                datab.append("%%" + s.group.getName()+ "%%");
+            }
+            datab.append("\n");
+            datab.append(s.seq);
+            datab.append("\n");
+        }
+        String data = datab.toString();
+        return data;
+    }
+
+    public void saveToRKITools(String name) {
+        if(baseUrl == null || fileId == null) {
+            System.out.println("Oops");
+        }
+        try {
+            System.out.println("Saving...");
+            StringBuilder datab = new StringBuilder();
+            for(Sequence s : _align.getSequencesAll()) {
+                datab.append(">" + s.name + "%%" + s.group.getName()+ "%%" + "\n");
+                datab.append(s.seq);
+                datab.append("\n");
+            }
+            System.out.println("  step 1 done");
+            String data = datab.toString();
+            ClientHttpRequest req = null;
+            if(name == null) {
+                System.out.println("  step 2 done");
+                req = new ClientHttpRequest(baseUrl + "save/" + fileId + "/");
+                req.setParameter("data", data);
+                System.out.println("  step 3 done");
+            }
+            else {
+                System.out.println("  step 4 done");
+                req = new ClientHttpRequest(baseUrl + "save_as/" + fileId + "/");
+                req.setParameter("data", data);
+                req.setParameter("name", name);
+                System.out.println("  step 5 done");
+            }
+            System.out.println("  step 6 done");
+            InputStream is = req.post();
+            System.out.println("  step 7 done");
+/*            InputStreamReader isr = new InputStreamReader(is);
+            BufferedReader reader = new BufferedReader(isr);
+            String res = reader.readLine();
+            if(name != null) {
+                fileId = res.trim();
+            }*/
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+        requestFocusInWindow();
+    }
+
+    @Override
+    public void saveFile() {
+
+    }
+
+    @Override
+    public void saveFileAs() {
+
+    }
+
+    private String getColorOpts() {
+        String colorScheme = "UPGMA";
+        try {
+            colorScheme = readFromURL(baseUrl + "color_scheme/" + username + "/");
+        } catch(Exception e) {
+        }
+        return colorScheme.replace("_", " ");
+    }
+
+    public void setColorOpts(String opts) {
+        try {
+            readFromURL(baseUrl + "set_color_scheme/" + username + "/" + opts.replace(" ", "_") + "/");
+        } catch(Exception e) {
+        }
+    }
+
+    @Override
+    public void init() {
+        _width = getSize().width - 40;
+        _height = getSize().height;
+        System.out.println("AppletViewer version " + VERSION + " loading...");
+        baseUrl = this.getParameter("baseurl");
+        fileId = this.getParameter("fileId");
+        username = this.getParameter("username");
+
+        GridBagLayout layout = new GridBagLayout();
+        this.setLayout(layout);
+        GridBagConstraints constraints = new GridBagConstraints();
+        addFocusListener(this);
+        addKeyListener(this);
+        // The mouse wheel listener must be added to the topmost parent due to this java bug:
+        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6480024
+//        getParent().addMouseWheelListener(this);
+        try {
+            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+        _namesPane = new NamesPane(_offset, this);
+        _seqPane = new SequencePane(_offset, this);
+        _sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, _namesPane, _seqPane);
+        _sp.setPreferredSize(new Dimension(_width, _height));
+        _scrollBar.setPreferredSize(new Dimension(20, _height));
+        String colorOpts = getColorOpts().trim();
+        if(ColorModels.models.containsKey(colorOpts)) {
+            ColorModels.currentModel = colorOpts;
+        }
+        constraints.fill = GridBagConstraints.BOTH;
+        constraints.gridx = 0;
+        constraints.gridy = 0;
+        constraints.gridwidth = 1;
+        constraints.gridheight = 1;
+        constraints.weightx = 1;
+        constraints.weighty = 1;
+        this.add(_sp, constraints);
+        constraints.gridx = 1;
+        constraints.weightx = 0;
+        this.add(_scrollBar, constraints);
+        constraints.gridx = 0;
+        constraints.gridy = 1;
+        constraints.gridwidth = 2;
+        constraints.weighty = 0;
+        this.add(_hscrollBar, constraints);
+        _scrollBar.addAdjustmentListener(this);
+        _hscrollBar.addAdjustmentListener(this);
+        _sp.setDividerLocation(50);
+        SwingUtilities.updateComponentTreeUI(this);
+        if(baseUrl != null && fileId != null) {
+            loadFromRKITools(baseUrl + "download/", fileId, true);
+        }
+        else {
+            Data.loadDefaultAlignment(_align);
+        }
+        updateScrollbar();
+        repaintAll();
+        requestFocusInWindow();
+    }
+
+    public int getAppletWidth() {
+        return(_width);
+    }
+    
+    public int getAppletHeight() {
+        return(_height);
+    }
+    
+    public void updateScrollbar() {
+        _scrollBar.setMaximum(_align.countAll());
+        _scrollBar.setValue(_offset[1]);
+        int max = _align.getLongestAll();
+        _hscrollBar.setMaximum(max);
+        _hscrollBar.setValue(_offset[0]);
+        int extent = (int)(_seqPane.getImageWidth()/_lw);
+        if(extent < max) {
+            _hscrollBar.setVisibleAmount(extent);
+        }
+        else {
+            scrollTo(0, _offset[1]);
+            _hscrollBar.setVisibleAmount(max-1);
+        }
+    }
+
+    @Override
+    public int[] getSelFrom() {
+        return selFrom;
+    }
+
+    @Override
+    public int[] getSelTo() {
+        return selTo;
+    }
+
+    @Override
+    public int getMode() {
+        return mode;
+    }
+
+    @Override
+    public int getConsHeight() {
+        return consHeight;
+    }
+
+    @Override
+    public int getTripletDist() {
+        return tripletDist;
+    }
+
+    @Override
+    public int getAnnotationHeight() {
+        return annotationHeight;
+    }
+
+    @Override
+    public Annotation getEditedAnnotation() {
+        return editedAnnotation;
+    }
+
+    @Override
+    public void setEditedAnnotation(Annotation anno) {
+        editedAnnotation = anno;
+    }
+
+    @Override
+    public void setSelFrom(int index, int value) {
+        selFrom[index] = value;
+    }
+
+    @Override
+    public void setSelTo(int index, int value) {
+        selTo[index] = value;
+    }
+
+    @Override
+    public double getLetterWidth() {
+        return (_lw);
+    }
+    
+    @Override
+    public int getLetterHeight() {
+        if(_lw >= minLineHeight) {
+            return((int)_lw);
+        }
+        return(minLineHeight);
+    }
+    
+    public int getTopOffset() {
+        if(masterSequenceAll == null) {
+            return(rulerHeight);
+        }
+        return(rulerHeight + getLetterHeight() + consHeight + 5);
+    }
+    
+    public int getConsOffset() {
+        return(rulerHeight + getLetterHeight());
+    }
+
+    public void setLetterWidth(int lw) {
+        _lw = lw;
+        annotationHeight = lw+4;
+        repaintAll();
+    }
+
+    public Frame getParentFrame(){ 
+        Container c = this; 
+        while(c != null){ 
+            if (c instanceof Frame) 
+                return (Frame)c; 
+
+            c = c.getParent(); 
+        } 
+        return (Frame)null; 
+    }
+
+    @Override
+    public void setMasterSequence(MasterSequence master, GroupKey group) {
+        MasterSequence masterSeq = new MasterSequence(master);
+        masterSequences.put(group, masterSeq);
+        int allseqs = _align.count(group);
+        int len = masterSeq.seq.length();
+        char[][] seqs = _align.toCharArray(len, group);
+        calcMasterConservation(masterSeq, seqs, allseqs);
+    }
+    
+    @Override
+    public void setMasterSequenceAll(MasterSequence master) {
+        masterSequenceAll = new MasterSequence(master);
+        int allseqs = _align.countAll();
+        int len = master.seq.length();
+        char[][] seqs = _align.toCharArrayAll(len);
+        calcMasterConservation(masterSequenceAll, seqs, allseqs);
+        _seqPane.updateCopyMenues();
+    }
+
+    private void calcMasterConservation(MasterSequence master, char[][] seqs, int allseqs) {
+        char[] masterSeq = master.seq.toCharArray();
+        int len = master.seq.length();
+        master.conservation = new double[len];
+        _conservedRegions = new LinkedList<int[]>();
+        int conslen = 0;
+        for(int i=0; i<len; i++) {
+            int nseq = allseqs;
+            int ident = 0;
+            for(int j=0; j<allseqs; j++) {
+                if(seqs[j][i] == masterSeq[i]) {
+                    ident ++;
+                }
+                if(seqs[j][i] == '\0') {
+                    nseq --;
+                }
+            }
+            master.conservation[i] = (double)ident/(double)nseq;
+            if(master.conservation[i] == 1) {
+                conslen ++;
+            }
+            else if(conslen != 0) {
+                int[] place = {i-conslen, conslen};
+                _conservedRegions.add(place);
+                conslen = 0;
+            }
+        }
+        repaintAll();
+    }
+
+    public void getMasterConsensus() {
+        int longest = _align.getLongestAll();
+        int allseqs = _align.countAll();
+        char[][] seqs = _align.toCharArrayAll(longest);
+        MasterSequence masterSequence = calculateConsensusSequence(longest, allseqs, seqs);
+        setMasterSequenceAll(masterSequence);        
+        _align.calculateHomology(masterSequence);
+    }
+    
+    public void getConsensus(GroupKey group) {
+        int longest = _align.getLongest(group);
+        int allseqs = _align.count(group);
+        char[][] seqs = _align.toCharArray(longest, group);
+        MasterSequence masterSequence = calculateConsensusSequence(longest, allseqs, seqs);
+        masterSequence.group = group;
+        setMasterSequence(masterSequence, group);        
+        _align.calculateHomology(masterSequences.get(group));
+    }
+
+    public void getGroupMasterSequences() {
+        Collection<GroupKey> groups = getAlignment().getGroups();
+        for(GroupKey group : groups) {
+            getConsensus(group);
+        }
+    }
+
+    /**
+     * Finds SNPs in the alignment which can be used to differenciate between the defined sequence groups.
+     */
+    public void findSNPs() {
+        getMasterConsensus();
+        getGroupMasterSequences();
+        int ngroups = masterSequences.size();
+        for(int pos = 0; pos < getAlignment().getLongestAll(); pos ++) {
+            // If the conservation of the master consensus sequence is 100%, then this can not be a SNP
+            if(masterSequenceAll.conservation[pos] == 1)
+                continue;
+            char val = masterSequenceAll.seq.charAt(pos);
+            int differ = 0;
+            for(MasterSequence seq : masterSequences.values()) {
+                if(seq.conservation[pos] != 1) {
+                    differ = -1;
+                    break;
+                }
+                if(seq.seq.charAt(pos) != val)
+                    differ ++;
+            }
+            if(differ != -1) {
+                getAlignment().toggleSnp(pos);
+            }
+        }
+    }
+
+    private MasterSequence calculateConsensusSequence(int longest, int allseqs, char[][] seqs) {
+        char[] bases = new char[5]; //0: A, 1: G, 2: T, 3: C, 4: -
+        char[] consensus = new char[longest];
+        for(int i=0; i<longest; i++) {
+            for(int j=0; j<allseqs; j++) {
+                switch(seqs[j][i]) {
+                    case 'A':
+                        bases[0]++; break;
+                    case 'G':
+                        bases[1]++; break;
+                    case 'T':
+                        bases[2]++; break;
+                    case 'C':
+                        bases[3]++; break;
+                    case '-':
+                        bases[4]++; break;
+                    default:
+                }       
+            }
+            int pos = 4;
+            int max = 0;
+            for(int n=0; n<4; n++) {
+                if(bases[n] > max) {
+                    pos = n;
+                    max = bases[n];
+                }
+                bases[n] = 0;
+            }
+            switch(pos) {
+                case 0:
+                    consensus[i] = 'A'; break;
+                case 1:
+                    consensus[i] = 'G'; break;
+                case 2:
+                    consensus[i] = 'T'; break;
+                case 3:
+                    consensus[i] = 'C'; break;
+                case 4:
+                    consensus[i] = '-'; break;
+                default:
+                    consensus[i] = '-';
+            }
+        }
+        return(new MasterSequence("Consensus (" + allseqs + " sequences)", new String(consensus), baseGroup, _align));
+    }
+    
+    @Override
+    public int getPrimerEditPos() {
+        return 0;
+    }
+
+    @Override
+    public boolean isPrimerTmEnabled() {
+        return false;
+    }
+
+    @Override
+    public boolean isPrimerLengthEnabled() {
+        return false;
+    }
+
+    @Override
+    public Alignment getAlignment() {
+        return (_align);
+    }
+
+    @Override
+    public HashMap<GroupKey, MasterSequence> getMasterSequences() {
+        return masterSequences;
+    }
+
+    @Override
+    public MasterSequence getMasterSequenceAll() {
+        return masterSequenceAll;
+    }
+
+    public void repaintAll() {
+        requestFocus();
+        requestFocusInWindow();
+        requestFocus();
+        _seqPane.redrawAll();
+        _seqPane.repaint();
+        _namesPane.repaint();
+        requestFocusInWindow();
+    }
+
+    @Override
+    public void stop() {
+    }
+
+    private boolean pointInSelection(int[] point) {
+        Position rpoint = getRealPos(point);
+        Rectangle r = new Rectangle(selFrom[0], selFrom[1], selTo[0], selTo[1]);
+        Point p = new Point(rpoint.x, rpoint.y);
+        if(r.contains(p)) {
+            return(true);
+        }
+        return(false);
+    }
+
+    @Override
+    public int getRulerHeight() {
+        return rulerHeight;
+    }
+
+    
+    public int getScreenX(int posx) {
+        double res = (posx-_offset[0])*_lw;
+        if(getAlignment().tripletGrouping != -1) {
+            res += (((getAlignment().tripletGrouping+_offset[0])%3+posx)/3)*tripletDist;
+        }
+        return((int)res);
+    }
+
+    public int getScreenY(int posy, boolean consensus) {
+        int res = getTopOffset();
+        int lh = getLetterHeight();
+        res += lh;
+        for(int i=_offset[1]; i<=posy; i++) {
+            Sequence lastSeq = getAlignment().getSequence(i-1);
+            Sequence seq = getAlignment().getSequence(i);
+            if(seq == null) {
+                break;
+            }
+            if(lastSeq != null && lastSeq.group == seq.group && seq.collapsed) {
+                continue;
+            }
+            if(lastSeq != null) {
+                res += lastSeq.below.levels.size()*annotationHeight;
+                if(lastSeq.group != seq.group) {
+                    res += groupSep;
+                    if(masterSequences.containsKey(seq.group)) {
+                        res += getLetterHeight();
+                        res += getConsOffset();
+                    }
+                }
+            }
+            else if(masterSequences.containsKey(seq.group)) {
+                res += getLetterHeight();
+                res += getConsOffset();
+            }
+            if(consensus && i == posy) {
+                return res;
+            }
+            res += lh;
+            res += seq.above.levels.size()*annotationHeight;
+        }
+        return(res);
+    }
+
+    @Override
+    public int getScreenY(int posy) {
+        return getScreenY(posy, false);
+    }
+
+    @Override
+    public int getScreenYConsensus(int posy) {
+        return getScreenY(posy, true);
+    }
+
+    public int getOffsetY() {
+        return(getScreenY(_offset[1]));
+    }
+    
+    private Annotation onAnnotation(int posX, int posY, LinkedList<LinkedList<Annotation>> levels, int ypos) {
+        ypos -= levels.size()*annotationHeight;
+        Annotation found = null;
+        for(LinkedList<Annotation> level : levels) {
+            ypos += annotationHeight;
+            if(posY <= ypos) {
+                for(Annotation anno : level) {
+                    int[] axp = _seqPane.getAnnotationXpos(anno);
+                    if(posX > axp[0] && posX < axp[1]) {
+                        found = anno;
+                        break;
+                    }
+                }
+                if(found != null) {
+                    break;
+                }        
+            }
+        }
+        return(found);
+    }
+    
+    public Position getRealPos(int[] screenPos) {
+        int[] res = {0, 0};
+        int pos = getLetterHeight();
+        int ypos;
+        Annotation onAnnotation = null;
+        int lh = getLetterHeight();
+        boolean onCollapser = false;
+        boolean onConsensus = false;
+        boolean first = true;
+        GroupKey lastGroup = new GroupKey("__NONAME__");
+        GroupKey onConsensusGroup = null;
+        int numSequences = _align.countAll();
+        for(ypos=_offset[1]; pos < screenPos[1] - getTopOffset() && ypos < numSequences; ypos++) {
+            first = false;
+            if(_align.getSequence(ypos-1) != null) {
+                lastGroup = _align.getSequence(ypos-1).group;
+            }
+            onConsensus = false;
+            onCollapser = false;
+            Sequence seq = _align.getSequence(ypos);
+            Sequence nextSeq = _align.getSequence(ypos + 1);
+            if(nextSeq != null && seq.group != nextSeq.group) {
+                pos += groupSep;
+            }
+            if(lastGroup != seq.group) {
+                if(masterSequences.containsKey(seq.group)) {
+                    pos += getLetterHeight();
+                    pos += getConsOffset();
+                }
+                if(pos >= screenPos[1] - getTopOffset()) {
+                    onConsensus = true;
+                    onConsensusGroup = seq.group;
+                }
+            }
+            if(lastGroup == seq.group && seq.collapsed) {
+                continue;
+            }
+            if(lastGroup != seq.group && screenPos[0] <= 12) {
+                onCollapser = true;
+            }
+            boolean hit = false;
+            if(seq == null) {
+                ypos --;
+                break;
+            }
+            pos += seq.above.levels.size()*annotationHeight;
+            if(pos >= screenPos[1] - getTopOffset()) {
+                onAnnotation = onAnnotation(screenPos[0], screenPos[1] - getTopOffset(), seq.above.levels, pos);
+                hit = true;
+            }
+            pos += lh;
+            if(pos >= screenPos[1] - getTopOffset()) {
+                hit = true;
+            }
+            pos += seq.below.levels.size()*annotationHeight;
+            if(!hit && pos >= screenPos[1] - getTopOffset()) {
+                onAnnotation = onAnnotation(screenPos[0], screenPos[1] - getTopOffset(), seq.below.levels, pos);
+            }
+            if(pos >= screenPos[1] - getTopOffset()) {
+                break;
+            }
+        }
+        res[1] = ypos;
+        if(_align.tripletGrouping == -1) {
+            res[0] = (int)(screenPos[0]/_lw) + _offset[0];
+        }
+        else {
+            res[0] = (int)(((screenPos[0] + (_offset[0]*_lw) + ((_align.tripletGrouping + _offset[0])%3)*tripletDist/3))/(_lw+tripletDist/3));
+        }
+        if(first) {
+            onConsensus = true;
+        }
+        return (new Position(res[0], res[1], onAnnotation!=null, onAnnotation, onCollapser, onConsensus, onConsensusGroup));
+    }
+
+    @Override
+    public void addAnnotation(boolean above, boolean primer) {
+        String text = primer?"Primer":"Annotation";
+        _align.getSequence(selFrom[1]).addAnnotation(above, selFrom[0], selTo[0], text, primer);
+        repaintAll();
+    }
+
+    @Override
+    public boolean isPrimerSequenceActive() {
+        return false;
+    }
+
+    private void unselectAll() {
+        for (Sequence seq : _align.getSequencesAll()) {
+            seq.selected = false;
+        }
+    }
+
+    private void scrollSequences(MouseEvent e) {
+        boolean rep = false;
+        if (Math.abs(_lastMousePos[0] - e.getX()) >= _lw && e.getSource() == _seqPane) {
+            _offset[0] += (_lastMousePos[0] - e.getX()) / _lw;
+            _lastMousePos[0] = e.getX();
+            if (_offset[0] < 0) {
+                _offset[0] = 0;
+            }
+            rep = true;
+        }
+        if (Math.abs(_lastMousePos[1] - e.getY()) >= getLetterHeight()) {
+            _offset[1] += (_lastMousePos[1] - e.getY()) / getLetterHeight();
+            _lastMousePos[1] = e.getY() - (_lastMousePos[1] - e.getY()) % 8;
+            if (_offset[1] < 0) {
+                _offset[1] = 0;
+            }
+            rep = true;
+        }
+        if (rep) {
+            scrollTo(_offset[0], _offset[1]);
+            repaintAll();
+        }
+    }
+
+    private void selectNames(MouseEvent e) {
+        int[] pos = {e.getX(), e.getY()};
+        int from = getRealPos(_lastMousePos).y;
+        int to = getRealPos(pos).y;
+        if (!e.isShiftDown()) {
+            unselectAll();
+        }
+        if (from > to) {
+            int tmp = to;
+            to = from;
+            from = tmp;
+        }
+        for (int i = from; i <= to && i < _align.countAll(); i++) {
+            _align.getSequence(i).selected = true;
+        }
+        repaintAll();
+    }
+
+    private void moveSel(int pos0, int pos1) {
+        // Moving disabled until undo is implemented
+        return;
+/*        for(int i=selFrom[1]; i<selTo[1]; i++) {
+            _align.getSequence(i).movePart(selFrom[0], selTo[0], pos1-pos0);
+        }*/
+    }
+    
+    public void loadString(String s, boolean overwrite) {
+        System.out.println("Loading...");
+        Alignment align = _align;
+        if(overwrite) {
+            align = new Alignment(null);
+        }
+        String[] lines = s.split(">");
+        HashMap<String, GroupKey> loadedGroups = new HashMap<String, GroupKey>();
+        if(!overwrite) {
+            for(GroupKey key : _align.getGroups()) {
+                if(!loadedGroups.containsKey(key.getName())) {
+                    loadedGroups.put(key.getName(), key);
+                }
+            }
+        }
+        for(String line : lines) {
+            if(line.equals("")) continue;
+            String[] vals = line.split("\n");
+            String name = vals[0];
+            vals[0] = "";
+            StringBuilder seqBuilder = new StringBuilder();
+            for(String val : vals) {
+                seqBuilder.append(val.replace("\r", "").replace(" ", ""));
+            }
+            String seq = seqBuilder.toString().toUpperCase();
+            GroupKey group = baseGroup;
+            if(loadedGroups.containsKey(baseGroup.getName())) {
+                group = loadedGroups.get(baseGroup.getName());
+            }
+            // Get the name of the group the sequence belongs to from the name
+            if(name.contains("%%")) {
+                String[] nameVals = name.split("%%");
+                name = nameVals[0];
+                String groupName = nameVals[1];
+                if(loadedGroups.containsKey(groupName)) {
+                    group = loadedGroups.get(groupName);
+                }
+                else {
+                    group = new GroupKey(groupName);
+                    loadedGroups.put(groupName, group);
+                }
+            }
+            align.addSequence(new Sequence(name, seq, group, align));
+        }
+        if(overwrite) {
+            _align = align;
+        }
+        for(GroupKey group : loadedGroups.values()) {
+            System.out.println(group.getName());
+        }
+        _align.sortGroups();
+        _namesPane.updateGroupMenuItems();
+        repaintAll();
+        requestFocusInWindow();
+    }
+
+    private void parseTree(JSONArray data, DefaultMutableTreeNode parent) {
+        try {
+            for(int i = 0; i < data.length(); i ++) {
+                JSONObject cdata = data.getJSONObject(i);
+                RKIFolder folder = new RKIFolder(cdata.getJSONObject("property").getString("name"), cdata.getJSONObject("property").getString("data"));
+                DefaultMutableTreeNode child = new DefaultMutableTreeNode(folder);
+                try {
+                    parseTree(cdata.getJSONArray("children"), child);
+                } catch(Exception e) {}
+                parent.add(child);
+            }
+        } catch(Exception e) {
+        }
+    }
+
+    private DefaultMutableTreeNode parseTree(JSONArray data) {
+        try {
+            JSONObject root = data.getJSONObject(0);
+            RKIFolder folder = new RKIFolder(root.getJSONObject("property").getString("name"), root.getJSONObject("property").getString("data"));
+            DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(folder);
+            parseTree(root.getJSONArray("children"), rootNode);
+            return rootNode;
+        } catch(Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    public boolean loadFileRKI(boolean overwrite) {
+        try {
+            String data = readFromURL(baseUrl + "tree/" + username + "/");
+            JSONArray tree = new JSONArray(data);
+            DefaultMutableTreeNode root = parseTree(tree);
+            RKIFilesDialog dialog = new RKIFilesDialog(this.findParentFrame(), "test", root, this);
+            dialog.setVisible(true);
+            if(dialog.accepted) {
+//                System.out.println(dialog.getSelectedFile().name);
+                loadFromRKITools(baseUrl + "download/", dialog.getSelectedFile().id, overwrite);
+                updateScrollbar();
+            }
+        }
+        catch(Exception e) {
+            System.out.println("booh");
+        }
+        return true;
+    }
+
+    public void loadFile(boolean overwrite) {
+        final JFileChooser fc = new JFileChooser();
+        fc.removeChoosableFileFilter(fc.getAcceptAllFileFilter());
+        fc.addChoosableFileFilter(new FastaFilter());
+        int returnVal = fc.showOpenDialog(this);
+        if (returnVal == JFileChooser.APPROVE_OPTION) {
+            File file = fc.getSelectedFile();
+            try {
+                BufferedReader input = new BufferedReader(new FileReader(file));
+                StringBuilder s = new StringBuilder();
+                while(input.ready()) {
+                    s.append(input.readLine());
+                    s.append("\n");
+                }
+                loadString(s.toString(), overwrite);
+            }
+            catch(Exception e) {
+                System.out.println(e.getMessage());
+            }
+        }
+        masterSequenceAll = null;
+        masterSequences = new HashMap<GroupKey, MasterSequence>();
+        repaintAll();
+        requestFocusInWindow();
+    }
+        
+    public void mouseDragged(MouseEvent e) {
+        requestFocusInWindow();
+        if (_mouseButton == 2) {
+            scrollSequences(e);
+        }
+        else if (_mouseButton == 1 && e.getSource() == _namesPane) {
+            if(mode == MODE_MOVESEL) {
+                int[] screenPos = {e.getX(), e.getY()};
+                Position newPos = getRealPos(screenPos);
+                if(newPos.y != _movePos) {
+                    int dist = newPos.y - _movePos;
+                    _movePos = newPos.y;
+                    _align.moveSelected(dist);
+                    repaintAll();
+                }
+            }
+//            selectNames(e);
+        }
+        else if (_mouseButton == 1 && e.getSource() == _seqPane) {
+            int[] screenPos = {e.getX(), e.getY()};
+            // Moving disabled until undo is implemented
+            if(mode == MODE_MOVESEL && 1==0) {
+                Position newPos = getRealPos(screenPos);
+                int diff = newPos.x - _movePos;
+                if(selFrom[0] + diff < 0 || selFrom[1] + diff < 0)
+                    diff = 0 - Math.min(selFrom[0], selFrom[1]);
+                if(newPos.x != _movePos) {
+                    moveSel(_movePos, newPos.x);
+                    selFrom[0] += diff;
+                    selTo[0] += diff;
+                    _movePos = newPos.x;
+                    repaintAll();
+                }
+            }
+            else if(mode == MODE_MOVEANNO) {
+                Position newPos = getRealPos(screenPos);
+                int diff = newPos.x - _movePos;
+                if(diff != 0) {
+                    selectedAnnotation.from += diff;
+                    selectedAnnotation.to += diff;
+                    _movePos = newPos.x;
+                    _seqPane.repaint();
+                    updateFlowgrams(false);
+                }
+            }
+            else {
+                int[] oldTo = {selTo[0], selTo[1]};
+                Position p = getRealPos(screenPos);
+                selTo[0] = p.x;
+                if(selConsensus) {
+                    if(consensusGroup == null) {
+                        selFrom[1]=0;
+                        selTo[1] = _align.countAll();
+                    }
+                    else {
+                        System.out.println(consensusGroup.getName());
+                        selFrom[1] = _align.getGroupFirst(consensusGroup);
+                        selTo[1] = selFrom[1] + _align.count(consensusGroup);
+                    }
+                }
+                else {
+                    selTo[1] = p.y+1;
+                    if(selTo[1] == selFrom[1]) {
+                        selFrom[1] -= 1;
+                    }
+                }
+                if(oldTo[0] != selTo[0] || oldTo[1] != selTo[1]) {
+                    repaintAll();
+                }
+            }
+        }
+    }
+
+    public SequenceInfo getToolTip() {
+        if(_toolTip == null) {
+            _toolTip = new SequenceInfo();
+            _toolTip.text = "Test";
+        }
+        return(_toolTip);
+    }
+    
+    public void mouseMoved(MouseEvent e) {
+        requestFocusInWindow();
+        if(mode != MODE_EDITING) {
+            int[] screenPos = {e.getX(), e.getY()};
+            Position realPos = getRealPos(screenPos);
+            if(realPos.x != _lastPos[0] || realPos.y != _lastPos[1]) {
+                _seqPane.redrawCursor(realPos.x, realPos.y);
+                _seqPane.repaint();
+                _lastPos[0] = realPos.x;
+                _lastPos[1] = realPos.y;
+            }
+            if(e.getSource() == _seqPane) {
+                _seqPane.seqNum = realPos.y;
+//                _toolTip = getToolTip();
+//                _toolTip.setLocation(_seqPane.getLocationOnScreen().x + e.getX() - 50, _seqPane.getLocationOnScreen().y + e.getY() + 15);
+                if(realPos.onConsensus) {
+                    _seqPane.toolTipText = "Consensus for " + _align.getSequence(realPos.y).group.getName();
+//                    _toolTip.text = "Consensus for " + _align.getSequence(realPos.y).group.getName();
+//                    _toolTipText.setText("Consensus for " + _align.getSequence(realPos.y).group.getName());
+                }
+                else {
+                    _seqPane.toolTipText = _align.getSequence(realPos.y).name;
+//                    _toolTip.text = _align.getSequence(realPos.y).name;
+//                    _toolTipText.setText(_align.getSequence(realPos.y).name);
+                }
+//                _toolTip.setVisible(true);
+//                _toolTip.repaint();
+            }
+        }
+        if(e.getSource() != _seqPane) {
+            getToolTip().setVisible(false);
+        }
+    }
+
+    public void mouseClicked(MouseEvent e) {
+        requestFocusInWindow();
+        if(e.getButton() == 3) {
+            return;
+        }
+        if (e.getSource() == _namesPane) {
+            if (!e.isShiftDown() && !e.isControlDown()) {
+                System.out.println("Unselecting");
+                unselectAll();
+            }
+            int[] pos = {e.getX(), e.getY()};
+            Position realPos = getRealPos(pos);
+            if(realPos.onCollapser) {
+                Sequence selectedSeq = _align.getSequence(realPos.y);
+                selectedSeq.collapsed = !selectedSeq.collapsed;
+                for(Sequence seq : _align.getSequences(selectedSeq.group)) {
+                    seq.collapsed = selectedSeq.collapsed;
+                }
+            }
+            else {
+                if(!e.isShiftDown() || _lastSelected == -1) {
+                    System.out.println("Hello2" + _align.getSequence(realPos.y).selected);
+                    _align.getSequence(realPos.y).selected ^= true;
+                    if(_align.getSequence(realPos.y).selected) {
+                        _lastSelected = realPos.y;                        
+                    }
+                }
+                else {
+                    if(_lastSelected != -1) {
+                        for(int i=Math.min(_lastSelected, realPos.y); i <= Math.max(_lastSelected, realPos.y); i++) {
+                            _align.getSequence(i).selected = true;
+                        }
+                    }
+                }
+            }
+            repaintAll();
+        }
+        else {
+            int[] coords = {e.getX(), e.getY()};
+            Position pos = getRealPos(coords);
+            if(pos.onAnnotation) {
+                editedAnnotation = pos.annotation;
+            }
+            else {
+                if(mode == MODE_SELECTING) {
+                    mode = MODE_EDITING;
+                }
+                else {
+                    mode = MODE_NORMAL;
+                }
+                selFrom[0] = 0;
+                selFrom[1] = 0;
+                selTo[0] = 0;
+                selTo[1] = 0;
+            }
+            _seqPane.repaint();
+        }
+    }
+
+    public void mouseEntered(MouseEvent arg0) {
+        requestFocusInWindow();
+    }
+
+    public void mouseExited(MouseEvent arg0) {
+        getToolTip().setVisible(false);
+    }
+
+    public void mousePressed(MouseEvent e) {
+        requestFocusInWindow();
+        _mouseButton = e.getButton();
+        _lastMousePos[0] = e.getX();
+        _lastMousePos[1] = e.getY();
+        if(_mouseButton == MouseEvent.BUTTON2) {
+            setCursor(new Cursor(Cursor.MOVE_CURSOR));
+        }
+        else if(_mouseButton == MouseEvent.BUTTON1 && e.getSource() == _namesPane) {
+            int[] screenPos = {e.getX(), e.getY()};            
+            Position realPos = getRealPos(screenPos);
+            if(_align.getSequence(realPos.y).selected) {
+                setCursor(new Cursor(Cursor.MOVE_CURSOR));
+                mode = MODE_MOVESEL;
+                _movePos = getRealPos(screenPos).y;
+            }
+        }
+        else if(_mouseButton == MouseEvent.BUTTON1 && e.getSource() == _seqPane) {
+            int[] screenPos = {e.getX(), e.getY()};            
+            Position realPos = getRealPos(screenPos);
+            if(pointInSelection(screenPos)) {
+                mode = MODE_MOVESEL;
+                _movePos = getRealPos(screenPos).x;
+                setCursor(new Cursor(Cursor.MOVE_CURSOR));
+            }
+            else if(realPos.onAnnotation) {
+                mode = MODE_MOVEANNO;
+                _movePos = getRealPos(screenPos).x;
+                selectedAnnotation = realPos.annotation;
+                setCursor(new Cursor(Cursor.MOVE_CURSOR));
+            }
+            else {
+                if(mode == MODE_EDITING) {
+                    mode = MODE_SELECTING2;
+                }
+                else {
+                    mode = MODE_SELECTING;
+                }
+                Position pos = getRealPos(screenPos);
+                selFrom = pos.getCoordinates();
+                selTo = pos.getCoordinates();
+                selConsensus = pos.onConsensus;
+                consensusGroup = pos.consensusGroup;
+            }
+        }
+    }
+
+    public void mouseReleased(MouseEvent arg0) {
+        requestFocusInWindow();
+        setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+        if(mode == MODE_MOVEANNO) {
+            selectedAnnotation.list.resetAnnotations();
+            selectedAnnotation = null;
+            repaintAll();
+        }
+    }
+
+    public void keyTyped(KeyEvent e) {
+        if(e.getKeyChar() == '-') {
+            doZoom(1);
+        }
+        else if(e.getKeyChar() == '+') {
+            doZoom(-1);
+        }
+    }
+
+    public void scrollTo(int x, int y) {
+        _offset[0] = x;
+        _offset[1] = y;
+        _hscrollBar.setValue(x);
+        _scrollBar.setValue(y);
+    }
+    
+    public void searchForSequence(String seq, boolean allowGaps) {
+        int[] pos = _align.findSubSequence(selFrom[1], selTo[0], seq, allowGaps);
+        if(pos[0] != -1) {
+            selFrom[1] = pos[0];
+            selTo[1] = pos[0]+1;
+            selFrom[0] = pos[1];
+            selTo[0] = pos[1] + seq.length();
+            scrollTo(selFrom[0], selFrom[1]);
+            repaintAll();
+        }        
+    }
+    
+    private Frame findParentFrame() {
+        Container c = this;
+        while(c != null) {
+            if(c instanceof Frame) {
+                return((Frame)c);
+            }
+            c = c.getParent();
+        }
+        return((Frame)null);
+    }
+    
+    
+    public void keyPressed(KeyEvent e) {
+        int key = e.getKeyCode();
+        if(key == e.VK_F && (e.getModifiers() & e.CTRL_MASK) != 0 ) {
+            FindDialog d = new FindDialog(findParentFrame());
+            d.setVisible(true);
+            if(d.isAccepted()) {
+//                _lastSearch = d.getSeq().toUpperCase().replaceAll(" ", "");
+                _lastSearch = Sequence.cleanUpSequence(d.getSeq());
+                _lastSearchAllowedGaps = d.allowGaps();
+                searchForSequence(_lastSearch, _lastSearchAllowedGaps);
+            }
+            requestFocusInWindow();
+//            System.out.println("Hello");
+/*            _toolTip.setVisible(false);
+            String sequence = (String)JOptionPane.showInputDialog(this, "Please enter sequence:", "Sequence search",
+                    JOptionPane.PLAIN_MESSAGE, null, null, _lastSearch);
+            if(sequence == null) {
+                return;
+            }
+            _lastSearch = sequence.toUpperCase().replaceAll(" ", "");
+            searchForSequence(_lastSearch);
+            requestFocusInWindow();*/
+        }
+        else if(key == e.VK_F3) {
+            if(!_lastSearch.equals("")) {
+                searchForSequence(_lastSearch, _lastSearchAllowedGaps);
+                requestFocusInWindow();
+            }
+        }
+        else if(mode == MODE_EDITING) {
+            boolean seqChanged = false;
+            if(key == KeyEvent.VK_LEFT) {
+                _lastPos[0] -= 1;
+            }
+            else if(key == KeyEvent.VK_RIGHT) {
+                _lastPos[0] += 1;
+            }
+            else if(key == KeyEvent.VK_UP) {
+                _lastPos[1] -= 1;
+            }
+            else if(key == KeyEvent.VK_DOWN) {
+                _lastPos[1] += 1;
+            }
+            else if(e.getKeyChar() == 'a' || e.getKeyChar() == 'g' || e.getKeyChar() == 't' || e.getKeyChar() == 'c') {
+                _align.getSequence(_lastPos[1]-1).setCharAt(_lastPos[0], Character.toUpperCase(e.getKeyChar()));
+                _lastPos[0] += 1;
+                seqChanged = true;
+            }
+            _seqPane.redrawCursor(_lastPos[0], _lastPos[1]);
+            _seqPane.redrawAll();
+            _seqPane.repaint();
+        }
+        else if(key == KeyEvent.VK_N) {
+            if(_conservedRegionsIndex < _conservedRegions.size() - 1) {
+                _conservedRegionsIndex += 1;
+                scrollTo(_conservedRegions.get(_conservedRegionsIndex)[0], _offset[1]);
+                selFrom[0] = _offset[0];
+                selFrom[1] = 0;
+                selTo[0] = selFrom[0] + _conservedRegions.get(_conservedRegionsIndex)[1];
+                selTo[1] = _align.countAll();
+                repaintAll();
+            }
+        }
+    }
+
+    public void keyReleased(KeyEvent arg0) {
+    }
+
+    public void focusGained(FocusEvent arg0) {
+    }
+
+    public void focusLost(FocusEvent arg0) {
+    }
+    
+    public void doZoom(int direction) {
+        if(direction < 0) {
+            if(_lw == 10 || _lw == 8) {
+                _lw += 2;
+            }
+            else if(_lw < 8) {
+                _lw *= 2;
+            }
+        }
+        else if(direction > 0) {
+            if(_lw == 12 || _lw == 10) {
+                _lw -= 2;
+            }
+            else if(_lw <= 8) {
+                _lw /= 2;
+            }
+        }
+        updateScrollbar();
+        repaintAll();
+    }
+    
+    public void mouseWheelMoved(MouseWheelEvent e) {
+/*        if(!e.isControlDown())
+            return;
+        int notches = e.getWheelRotation();
+        doZoom(notches);*/
+    }
+
+    public void adjustmentValueChanged(AdjustmentEvent e) {
+        if(e.getSource() == _scrollBar) {
+            scrollTo(_offset[0], e.getValue());
+        }
+        else if(e.getSource() == _hscrollBar) {
+            scrollTo(e.getValue(), _offset[1]);
+        }        
+        repaintAll();
+    }
+    @Override
+    public boolean isApplication() {
+        return true;
+    }
+
+    @Override
+    public boolean isSequenceSelected() {
+        if(getSelFrom()[0] == getSelTo()[0] || getSelFrom()[1] == getSelTo()[1])
+            return false;
+        return true;
+    }
+
+    @Override
+    public boolean canAddAnnotation() {
+        return isSequenceSelected() && Math.abs(getSelFrom()[1] - getSelTo()[1]) == 1;
+    }
+
+    @Override
+    public void consensusChange() {
+    }
+
+    @Override
+    public Settings getSettings() {
+        return _settings;
+    }
+
+    @Override
+    public void updateFlowgrams(boolean fromWindow) {
+        findSNPs();
+        _seqPane.updateFlowgrams(fromWindow);
+    }
+
+    @Override
+    public void loadFile(boolean overwrite, LoadFilter filter, String filename) {
+        throw new UnsupportedOperationException("Not supported in app (you should never see this, kill Wojtek).");
+    }
+}
diff --git a/src/org/rki/sequenceeditor/view/EditorApp.java b/src/org/rki/sequenceeditor/view/EditorApp.java
new file mode 100644
index 0000000..feb8fd4
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/EditorApp.java
@@ -0,0 +1,1728 @@
+package org.rki.sequenceeditor.view;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.AdjustmentEvent;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseWheelEvent;
+import org.rki.sequenceeditor.model.*;
+import java.awt.*;
+import java.awt.datatransfer.Clipboard;
+import java.awt.event.MouseEvent;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Collection;
+import java.util.LinkedList;
+import javax.swing.JFileChooser;
+import javax.swing.JSplitPane;
+import java.util.HashMap;
+import java.util.ResourceBundle;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollBar;
+import javax.swing.filechooser.FileFilter;
+import javax.swing.tree.DefaultMutableTreeNode;
+import org.rki.sequenceeditor.model.filters.FastaFilter;
+import org.rki.sequenceeditor.model.filters.RSFFilter;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import java.awt.Toolkit;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.ActionListener;
+import javax.swing.ToolTipManager;
+import org.rki.sequenceeditor.model.filters.BasicFastaFilter;
+import org.rki.sequenceeditor.model.filters.GeneiousFilter;
+import org.rki.sequenceeditor.model.filters.LoadFilter;
+import org.rki.sequenceeditor.model.filters.SaveFilter;
+
+public class EditorApp implements EditorInterface {
+
+    final static ResourceBundle rb = ResourceBundle.getBundle("version");
+
+    public static String VERSION = "0.9.2";
+    public String BUILD = "";
+    public static int MODE_NORMAL = 0;
+    public static int MODE_EDITING = 1;
+    public static int MODE_MOVESEL = 2;
+    public static int MODE_MOVEANNO = 3;
+    public static int MODE_RESIZEANNO_E = 4;
+    public static int MODE_RESIZEANNO_W = 5;
+    public static int MODE_SELECTING = 6;
+    public static int MODE_SELECTING2 = 7;
+
+    public static int MODE_RESIZESEL_E = 8;
+    public static int MODE_RESIZESEL_W = 9;
+    public static int MODE_RESIZESEL_N = 10;
+    public static int MODE_RESIZESEL_S = 11;
+
+    public static int SELECTION_RESIZE_BORDER = 4;
+
+    public static FileFilter[] allFileFilters = {(FileFilter)(new BasicFastaFilter()),
+            (FileFilter)(new FastaFilter()), (FileFilter)(new GeneiousFilter()),
+            (FileFilter)(new RSFFilter())};
+
+    private EditorWindow _window;
+    public Settings settings;
+    private static final long serialVersionUID = 1L;
+    private int[] _offset = {0, 0};
+    public int _mouseButton;
+    private double _lw = 12;
+    private int minLineHeight = 8;
+    private int _width = 1024-40;
+    private int _height = 768;
+    private int[] _movePos = {0, 0};
+    public int consHeight = 10;
+    public int groupSep = 5;
+    public int[] _lastMousePos = {0, 0};
+    public int[] selFrom = {0,0};
+    public int[] selTo = {0,0};
+    public boolean selConsensus = false;
+    public GroupKey consensusGroup = null;
+//    public double[] conservation = null;
+    public int mode = MODE_NORMAL;
+    public Annotation editedAnnotation;
+    public Annotation selectedAnnotation;
+    private SequencePane _seqPane;
+    private NamesPane _namesPane;
+    private JSplitPane _sp;
+    private JScrollBar _scrollBar = new JScrollBar(JScrollBar.VERTICAL);
+    private JScrollBar _hscrollBar = new JScrollBar(JScrollBar.HORIZONTAL);
+    private Alignment _align = new Alignment(settings);
+    public SequenceInfo _toolTip = new SequenceInfo();
+//    public JPopupMenu _toolTip = null;
+//    public JMenuItem _toolTipText = null;
+    public int rulerHeight = 17;
+    public int annotationHeight = (int)_lw+4;
+    // Attention! Must be multiple of 3!
+    public int tripletDist = 6;
+    private int _lastSelected = -1;
+    private int[] _lastPos = {0,0};
+    private String _lastSearch = "";
+    private boolean _lastSearchAllowedGaps = false;
+    public GroupKey baseGroup = new GroupKey("All");
+    private String _filename = "";
+    private String _fullFilename = "";
+    private FileFilter _loadFilter = null;
+
+    private LinkedList<int[]> _conservedRegions;
+    private int _conservedRegionsIndex = 0;
+    private boolean _selectionActive = false;
+
+    public String baseUrl;
+    private String fileId;
+    private String username;
+
+    private int _primerEditPos = 0;
+
+    public boolean hasMasterSequence = false;
+    public boolean hasGroupMasterSequences = false;
+
+    public EditorApp() {
+        super();
+        init();
+    }
+
+    @Override
+    public boolean hasMenu() {
+        return true;
+    }
+
+    public void loadFile(final JFileChooser fc, boolean overwrite) {
+        if(overwrite) {
+            hasMasterSequence = false;
+            hasGroupMasterSequences = false;
+        }
+        settings.set(Settings.LAST_LOAD_PATH, fc.getSelectedFile().getAbsolutePath());
+        _fullFilename = fc.getSelectedFile().getAbsolutePath();
+        _loadFilter = fc.getFileFilter();
+        _window.setTitle(_filename);
+        LoadFilter filter = (LoadFilter) (fc.getFileFilter());
+        String filename = fc.getSelectedFile().getAbsolutePath();
+        LinkedList<String> recentFiles = new LinkedList<String>();
+        boolean addFile = true;
+        for(String recentFile : settings.getStringArray(Settings.RECENT_FILES[0], null)) {
+            recentFiles.add(recentFile);
+            if(recentFile.split("\\|")[0].equals(filename)) {
+                addFile = false;
+                break;
+            }
+        }
+        if(addFile) {
+            recentFiles.addFirst(filename + "|" + filter.getClass().getName());
+            while(recentFiles.size() > 10) {
+                recentFiles.removeLast();
+            }
+            String[] recentFilesArr = {};
+            settings.set(Settings.RECENT_FILES, recentFiles.toArray(recentFilesArr));
+            resetRecentFiles();
+        }
+        loadFile(overwrite, filter, filename);
+    }
+
+    public void resetRecentFiles() {
+        _window.recentMenu.removeAll();
+        for(String recentFile : settings.getStringArray(Settings.RECENT_FILES[0], null)) {
+            String[] data = recentFile.split("\\|");
+            for(FileFilter filter : allFileFilters) {
+                if(filter instanceof LoadFilter && filter.getClass().getName().equals(data[1])) {
+                    JMenuItem jm = new RecentMenuItem(data[0], (LoadFilter)filter);
+                    jm.addActionListener(new ActionListener() {
+                        @Override
+                        public void actionPerformed(ActionEvent e) {
+                            if(e.getSource() instanceof RecentMenuItem) {
+                                RecentMenuItem mi = (RecentMenuItem)e.getSource();
+                                loadFile(true, mi.loadFilter, mi.filename);
+                            }
+                        }
+                    });
+                    _window.recentMenu.add(jm);
+                    break;
+                }
+            }
+        }
+    }
+
+    public void loadFile(boolean overwrite, LoadFilter filter, String filename) {
+        if (overwrite) {
+            _align = new Alignment(settings);
+        }
+        filter.loadAlignment(filename, _align, baseGroup);
+        _window.setTitle(_filename + "(" + _align.countAll() + " sequences)");
+        _align.sortGroups();
+        _namesPane.updateGroupMenuItems();
+        _align.masterSequenceAll = null;
+        _align.masterSequences = new HashMap<GroupKey, MasterSequence>();
+        _seqPane.setParent(this);
+        _seqPane.sequenceLoaded();
+        scrollTo(0, 0);
+        repaintAll();
+    }
+
+    @Override
+    public boolean useIUB() {
+        return settings.getBoolean(Settings.DISPLAY_IUB);
+    }
+
+    @Override
+    public boolean showSequenceName() {
+        return settings.getBoolean(Settings.DISPLAY_SEQUENCE_NAME);
+    }
+
+    public void groupIdenticalSequences() {
+        _namesPane.groupIdenticalSequences();
+    }
+
+    public String readFromURL(String url) throws MalformedURLException, IOException {
+        URL rkitools = new URL(url);
+        URLConnection rc = rkitools.openConnection();
+        BufferedReader rcr = new BufferedReader(new InputStreamReader(rc.getInputStream()));
+        StringBuilder db = new StringBuilder();
+        while(true) {
+            if(!rcr.ready()) {
+                try {
+                    Thread.sleep(1000);
+                } catch(Exception e) {}
+                if(!rcr.ready()) {
+                    break;
+                }
+            }
+            db.append(rcr.readLine());
+            db.append("\n");
+        }
+        String data = db.toString();
+        return data;
+    }
+
+    private void loadFromRKITools(String url, String fileId, boolean overwrite) {
+        try {
+            String data = readFromURL(url + fileId + "/");
+            loadString(data, overwrite);
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+        catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public boolean isSelectionActive() {
+        return _selectionActive;
+    }
+
+    @Override
+    public String seqsToString(boolean pureFASTA) {
+        StringBuilder datab = new StringBuilder();
+        for(Sequence s : _align.getSequencesAll()) {
+            datab.append(">");
+            datab.append(s.name);
+            if(!pureFASTA) {
+                datab.append("%%");
+                datab.append(s.group.getName());
+                datab.append("%%");
+                int anno_counter = 0;
+                StringBuilder annotations = new StringBuilder();
+                for(Annotation anno : s.above.getAnnotations()) {
+                    anno_counter ++;
+                }
+            }
+            datab.append("\n");
+            datab.append(s.seq);
+            datab.append("\n");
+        }
+        String data = datab.toString();
+        return data;
+    }
+
+    @Override
+    public void saveToRKITools(String name) {
+        if(baseUrl == null || fileId == null) {
+        }
+        try {
+            StringBuilder datab = new StringBuilder();
+            for(Sequence s : _align.getSequencesAll()) {
+                datab.append(">");
+                datab.append(s.name);
+                datab.append("%%");
+                datab.append(s.group.getName());
+                datab.append("%%\n");
+                datab.append(s.seq);
+                datab.append("\n");
+            }
+            String data = datab.toString();
+            ClientHttpRequest req = null;
+            if(name == null) {
+                req = new ClientHttpRequest(baseUrl + "save/" + fileId + "/");
+                req.setParameter("data", data);
+            }
+            else {
+                req = new ClientHttpRequest(baseUrl + "save_as/" + fileId + "/");
+                req.setParameter("data", data);
+                req.setParameter("name", name);
+            }
+            InputStream is = req.post();
+/*            InputStreamReader isr = new InputStreamReader(is);
+            BufferedReader reader = new BufferedReader(isr);
+            String res = reader.readLine();
+            if(name != null) {
+                fileId = res.trim();
+            }*/
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void saveFile() {
+        if(!_fullFilename.equals("") && _loadFilter != null && _loadFilter instanceof SaveFilter) {
+            ((SaveFilter)_loadFilter).saveAlignment(_align, _fullFilename);
+        }
+    }
+
+    @Override
+    public void saveFileAs() {
+        final JFileChooser fc = new JFileChooser(settings.get(Settings.LAST_SAVE_PATH));
+        fc.removeChoosableFileFilter(fc.getAcceptAllFileFilter());
+        for(FileFilter filter : allFileFilters) {
+            if(filter instanceof SaveFilter) {
+                fc.addChoosableFileFilter(filter);
+            }
+        }
+        int returnVal = fc.showOpenDialog(_window);
+        if (returnVal == JFileChooser.APPROVE_OPTION) {
+            settings.set(Settings.LAST_SAVE_PATH, fc.getSelectedFile().getAbsolutePath());
+            String filename = fc.getSelectedFile().getAbsolutePath();
+            SaveFilter chosenFilter = (SaveFilter)(fc.getFileFilter());
+            if(!filename.endsWith(chosenFilter.getExtension())) {
+                filename += chosenFilter.getExtension();
+            }
+            chosenFilter.saveAlignment(_align, filename);
+            _window.setTitle(filename + "(" + _align.countAll() + " sequences)");
+        }
+    }
+
+    private String getColorOpts() {
+        String colorScheme = "UPGMA";
+        try {
+            colorScheme = readFromURL(baseUrl + "color_scheme/" + username + "/");
+        } catch(Exception e) {
+        }
+        return colorScheme.replace("_", " ");
+    }
+
+    @Override
+    public void setColorOpts(String opts) {
+        try {
+            readFromURL(baseUrl + "set_color_scheme/" + username + "/" + opts.replace(" ", "_") + "/");
+        } catch(Exception e) {
+        }
+    }
+
+    private void init() {
+//        setPreferredSize(new Dimension(1024, 768));
+//        pack();
+        try {
+            BUILD = rb.getString("BUILD").replace(",", "");
+        } catch(Exception e) {}
+        ToolTipManager.sharedInstance().setInitialDelay(0);
+        settings = new Settings();
+        _align.setSettings(settings);
+        _window = new EditorWindow();
+        _window.setApp(this);
+        _window.setVisible(true);
+        _window.namesPane1.setParent(this);
+        _window.namesPane1.setOffset(_offset);
+        _window.messageLabel.setText("Welcome to mPSQed " + VERSION + ", build " + BUILD);
+        _namesPane = _window.namesPane1;
+        _seqPane = _window.sequencePane1;
+        _seqPane.setOffset(_offset);
+        baseUrl = "";
+        fileId = "";
+        username = "";
+
+        _window.addFocusListener(this);
+        _window.addKeyListener(this);
+
+        _seqPane.addMouseMotionListener(this);
+        _seqPane.addMouseListener(this);
+        _seqPane.addKeyListener(this);
+        for (String name : ColorModels.models.keySet()) {
+            JMenuItem jm = new ColorModelMenuItem(name);
+            jm.addActionListener(_seqPane);
+            _window.colorModelMenu.add(jm);
+        }
+        resetRecentFiles();
+    }
+
+    @Override
+    public int getAppletWidth() {
+        return(_width);
+    }
+
+    @Override
+    public int getAppletHeight() {
+        return(_height);
+    }
+
+    public void scrollHorizontal(int x) {
+        scrollTo(x, _offset[1]);
+    }
+
+    public void scrollVertical(int y) {
+        scrollTo(_offset[0], y);
+    }
+
+    public void updateScrollbar() {
+        _window.verticalScrollBar.setMaximum(_align.countAll());
+        _window.verticalScrollBar.setValue(_offset[1]);
+        int max = _align.getLongestAll();
+        _window.horizontalScrollBar.setMaximum(max);
+        _window.horizontalScrollBar.setValue(_offset[0]);
+        int extent = (int)(_seqPane.getWidth()/_lw);
+        if(extent < max) {
+            _window.horizontalScrollBar.setVisibleAmount(extent);
+        }
+        else {
+            scrollTo(0, _offset[1]);
+            _window.horizontalScrollBar.setVisibleAmount(max-1);
+        }
+    }
+
+    @Override
+    public double getLetterWidth() {
+        return (_lw);
+    }
+
+    @Override
+    public int getLetterHeight() {
+        if(_lw >= minLineHeight) {
+            return((int)_lw);
+        }
+        return(minLineHeight);
+    }
+
+    @Override
+    public int getTopOffset() {
+        if(_align.masterSequenceAll == null) {
+            return(rulerHeight);
+        }
+        return(rulerHeight + getLetterHeight() + consHeight + 5);
+    }
+
+    @Override
+    public int getConsOffset() {
+        return(rulerHeight + getLetterHeight());
+    }
+
+    @Override
+    public void setLetterWidth(int lw) {
+        _lw = lw;
+        annotationHeight = lw+4;
+        repaintAll();
+    }
+
+    @Override
+    public Frame getParentFrame(){
+        return (Frame)null;
+    }
+
+    @Override
+    public void setMasterSequence(MasterSequence masterSeq, GroupKey group) {
+//        MasterSequence masterSeq = new MasterSequence(master);
+        _align.masterSequences.put(group, masterSeq);
+        int allseqs = _align.count(group);
+        int len = masterSeq.seq.length();
+        char[][] seqs = _align.toCharArray(len, group);
+        calcMasterConservation(masterSeq, seqs, allseqs);
+    }
+
+    @Override
+    public void setMasterSequenceAll(MasterSequence master) {
+        _align.masterSequenceAll = master;
+        int allseqs = _align.countAll();
+        int len = _align.masterSequenceAll.seq.length();
+        char[][] seqs = _align.toCharArrayAll(len);
+        calcMasterConservation(_align.masterSequenceAll, seqs, allseqs);
+        _seqPane.updateCopyMenues();
+    }
+
+    private void calcMasterConservation(MasterSequence master, char[][] seqs, int allseqs) {
+        char[] masterSeq = master.seq.toCharArray();
+        int len = master.seq.length();
+        master.conservation = new double[len];
+        _conservedRegions = new LinkedList<int[]>();
+        int conslen = 0;
+        for(int i=0; i<len; i++) {
+            int nseq = allseqs;
+            int ident = 0;
+            for(int j=0; j<allseqs; j++) {
+                if(seqs[j][i] == masterSeq[i]) {
+                    ident ++;
+                }
+                if(seqs[j][i] == '\0') {
+                    nseq --;
+                }
+            }
+            master.conservation[i] = (double)ident/(double)nseq;
+            if(master.conservation[i] == 1) {
+                conslen ++;
+            }
+            else if(conslen != 0) {
+                int[] place = {i-conslen, conslen};
+                _conservedRegions.add(place);
+                conslen = 0;
+            }
+        }
+        repaintAll();
+    }
+
+    @Override
+    public void getMasterConsensus() {
+        int longest = _align.getLongestAll();
+        int allseqs = _align.countAll();
+        char[][] seqs = _align.toCharArrayAll(longest);
+        MasterSequence masterSequence = calculateConsensusSequence(longest, allseqs, seqs);
+        setMasterSequenceAll(masterSequence);
+        _align.calculateHomology(masterSequence);
+        hasMasterSequence = true;
+    }
+
+    @Override
+    public void getConsensus(GroupKey group) {
+        int longest = _align.getLongest(group);
+        int allseqs = _align.count(group);
+        char[][] seqs = _align.toCharArray(longest, group);
+        MasterSequence masterSequence = calculateConsensusSequence(longest, allseqs, seqs);
+        masterSequence.group = group;
+        setMasterSequence(masterSequence, group);
+        _align.calculateHomology(_align.masterSequences.get(group));
+    }
+
+    @Override
+    public void getGroupMasterSequences() {
+        Collection<GroupKey> groups = getAlignment().getGroups();
+        for(GroupKey group : groups) {
+            getConsensus(group);
+        }
+        hasGroupMasterSequences = true;
+    }
+
+    public void copyMasterConsensusSequence() {
+        _seqPane.copyMasterConsensusSequence();
+    }
+
+    public void copyGroupConsensusSequence() {
+        _seqPane.copyGroupConsensusSequence();
+    }
+
+    @Override
+    public boolean isSequenceSelected() {
+        if(getSelFrom()[0] == getSelTo()[0] || getSelFrom()[1] == getSelTo()[1])
+            return false;
+        return true;
+    }
+
+    @Override
+    public boolean canAddAnnotation() {
+        return isSequenceSelected() && Math.abs(getSelFrom()[1] - getSelTo()[1]) == 1;
+    }
+
+    /**
+     * Finds SNPs in the alignment which can be used to differenciate between the defined sequence groups.
+     */
+    @Override
+    public void findSNPs() {
+        getMasterConsensus();
+        getGroupMasterSequences();
+        int ngroups = _align.masterSequences.size();
+        for(int pos = 0; pos < getAlignment().getLongestAll(); pos ++) {
+            // If the conservation of the master consensus sequence is 100%, then this can not be a SNP
+            if(_align.masterSequenceAll.conservation[pos] == 1)
+                continue;
+            char val = _align.masterSequenceAll.seq.charAt(pos);
+            int differ = 0;
+            for(MasterSequence seq : _align.masterSequences.values()) {
+                if(seq.conservation[pos] != 1) {
+                    differ = -1;
+                    break;
+                }
+                if(seq.seq.charAt(pos) != val)
+                    differ ++;
+            }
+            if(differ != -1) {
+                getAlignment().setSnp(pos);
+            }
+        }
+    }
+
+    private MasterSequence calculateConsensusSequence(int longest, int allseqs, char[][] seqs) {
+        char[] bases = new char[5]; //0: A, 1: G, 2: T, 3: C, 4: -
+        char[] consensus = new char[longest];
+        char[] IUBconsensus = new char[longest];
+        for(int i=0; i<longest; i++) {
+            bases = new char[5];
+            for(int j=0; j<allseqs; j++) {
+                switch(seqs[j][i]) {
+                    case 'A':
+                        bases[0]++; break;
+                    case 'G':
+                        bases[1]++; break;
+                    case 'T':
+                        bases[2]++; break;
+                    case 'C':
+                        bases[3]++; break;
+                    case '-':
+                        bases[4]++; break;
+                    default:
+                }
+            }
+            if(bases[0]==0 && bases[1] == 0 && bases[2] == 0 && bases[3] == 0)
+                IUBconsensus[i] = '-';
+            else if(bases[0] != 0 && bases[1] == 0 && bases[2] == 0 && bases[3] == 0)
+                IUBconsensus[i] = 'A';
+            else if(bases[0] == 0 && bases[1] != 0 && bases[2] == 0 && bases[3] == 0)
+                IUBconsensus[i] = 'G';
+            else if(bases[0] == 0 && bases[1] == 0 && bases[2] != 0 && bases[3] == 0)
+                IUBconsensus[i] = 'T';
+            else if(bases[0] == 0 && bases[1] == 0 && bases[2] == 0 && bases[3] != 0)
+                IUBconsensus[i] = 'C';
+            else if(bases[0] != 0 && bases[1] != 0 && bases[2] == 0 && bases[3] == 0)
+                IUBconsensus[i] = 'R';
+            else if(bases[0] == 0 && bases[1] == 0 && bases[2] != 0 && bases[3] != 0)
+                IUBconsensus[i] = 'Y';
+            else if(bases[0] != 0 && bases[1] == 0 && bases[2] == 0 && bases[3] != 0)
+                IUBconsensus[i] = 'M';
+            else if(bases[0] == 0 && bases[1] != 0 && bases[2] != 0 && bases[3] == 0)
+                IUBconsensus[i] = 'K';
+            else if(bases[0] != 0 && bases[1] == 0 && bases[2] != 0 && bases[3] == 0)
+                IUBconsensus[i] = 'W';
+            else if(bases[0] == 0 && bases[1] != 0 && bases[2] == 0 && bases[3] != 0)
+                IUBconsensus[i] = 'S';
+            else if(bases[0] == 0 && bases[1] != 0 && bases[2] != 0 && bases[3] != 0)
+                IUBconsensus[i] = 'B';
+            else if(bases[0] != 0 && bases[1] != 0 && bases[2] != 0 && bases[3] == 0)
+                IUBconsensus[i] = 'D';
+            else if(bases[0] != 0 && bases[1] == 0 && bases[2] != 0 && bases[3] != 0)
+                IUBconsensus[i] = 'H';
+            else if(bases[0] != 0 && bases[1] != 0 && bases[2] == 0 && bases[3] != 0)
+                IUBconsensus[i] = 'V';
+            else if(bases[0] != 0 && bases[1] != 0 && bases[2] != 0 && bases[3] != 0)
+                IUBconsensus[i] = 'N';
+
+            int pos = 4;
+            int max = 0;
+            for(int n=0; n<4; n++) {
+                if(bases[n] > max) {
+                    pos = n;
+                    max = bases[n];
+                }
+                bases[n] = 0;
+            }
+            switch(pos) {
+                case 0:
+                    consensus[i] = 'A'; break;
+                case 1:
+                    consensus[i] = 'G'; break;
+                case 2:
+                    consensus[i] = 'T'; break;
+                case 3:
+                    consensus[i] = 'C'; break;
+                case 4:
+                    consensus[i] = '-'; break;
+                default:
+                    consensus[i] = '-';
+            }
+        }
+        MasterSequence res = new MasterSequence("Consensus (" + allseqs + " sequences)", new String(consensus), baseGroup, _align);
+        res.IUB = new Sequence("IUB Consensus", new String(IUBconsensus), baseGroup, _align);
+        return(res);
+    }
+
+    @Override
+    public int getPrimerEditPos() {
+        return _primerEditPos;
+    }
+
+    @Override
+    public Alignment getAlignment() {
+        return (_align);
+    }
+
+    @Override
+    public HashMap<GroupKey, MasterSequence> getMasterSequences() {
+        return _align.masterSequences;
+    }
+
+    @Override
+    public MasterSequence getMasterSequenceAll() {
+        return _align.masterSequenceAll;
+    }
+
+    @Override
+    public void repaintAll() {
+        _seqPane.redrawAll();
+        _seqPane.repaint();
+        _namesPane.repaint();
+    }
+
+    private void setSelectionResize(boolean setMode, boolean setCursor, int[] point) {
+        Cursor c = new Cursor(Cursor.DEFAULT_CURSOR);
+        int newmode = MODE_MOVESEL;
+        if(point[0] <= getScreenX(selFrom[0])+SELECTION_RESIZE_BORDER) {
+            c = new Cursor(Cursor.W_RESIZE_CURSOR);
+            newmode = MODE_RESIZESEL_W;
+        }
+        else if(point[0] >= getScreenX(selTo[0])-SELECTION_RESIZE_BORDER) {
+            c = new Cursor(Cursor.E_RESIZE_CURSOR);
+            newmode = MODE_RESIZESEL_E;
+        }
+        else if(point[1] <= getScreenY(selFrom[1]-1)+SELECTION_RESIZE_BORDER) {
+            c = new Cursor(Cursor.N_RESIZE_CURSOR);
+            newmode = MODE_RESIZESEL_N;
+        }
+        else if(point[1] >= getScreenY(selTo[1]-1)-SELECTION_RESIZE_BORDER) {
+            c = new Cursor(Cursor.S_RESIZE_CURSOR);
+            newmode = MODE_RESIZESEL_S;
+        }
+        if(setMode)
+            mode = newmode;
+        if(setCursor)
+            _window.setCursor(c);
+    }
+
+    private boolean pointInSelection(int[] point) {
+        Position rpoint = getRealPos(point);
+        Rectangle r = new Rectangle(selFrom[0], selFrom[1], selTo[0]-selFrom[0], selTo[1]-selFrom[1]);
+        Point p = new Point(rpoint.x, rpoint.y);
+        if(r.contains(p)) {
+            return(true);
+        }
+        return(false);
+    }
+
+    @Override
+    public int getRulerHeight() {
+        return rulerHeight;
+    }
+
+    @Override
+    public int[] getSelFrom() {
+        return selFrom;
+    }
+
+    @Override
+    public int[] getSelTo() {
+        return selTo;
+    }
+
+    @Override
+    public int getMode() {
+        return mode;
+    }
+
+    @Override
+    public int getConsHeight() {
+        return consHeight;
+    }
+
+    @Override
+    public int getTripletDist() {
+        return tripletDist;
+    }
+
+    @Override
+    public int getAnnotationHeight() {
+        return annotationHeight;
+    }
+
+    @Override
+    public Annotation getEditedAnnotation() {
+        return editedAnnotation;
+    }
+
+    @Override
+    public void setEditedAnnotation(Annotation anno) {
+        editedAnnotation = anno;
+    }
+
+    @Override
+    public void setSelFrom(int index, int value) {
+        selFrom[index] = value;
+    }
+
+    @Override
+    public void setSelTo(int index, int value) {
+        selTo[index] = value;
+    }
+
+    @Override
+    public int getScreenX(int posx) {
+        double res = (posx-_offset[0])*_lw;
+        if(getAlignment().tripletGrouping != -1) {
+            res += (Math.ceil((double)(posx-getAlignment().tripletGrouping)/3.0))*tripletDist;
+        }
+        return((int)res);
+    }
+
+    public int getScreenY(int posy, boolean consensus) {
+        int res = getTopOffset();
+        int lh = getLetterHeight();
+        res += lh;
+        for(int i=_offset[1]; i<=posy; i++) {
+            Sequence lastSeq = getAlignment().getSequence(i-1);
+            Sequence seq = getAlignment().getSequence(i);
+            if(seq == null) {
+                break;
+            }
+            if(lastSeq != null && lastSeq.group == seq.group && seq.collapsed) {
+                continue;
+            }
+            if(lastSeq != null) {
+                res += lastSeq.below.levels.size()*annotationHeight;
+                if(lastSeq.group != seq.group) {
+                    res += groupSep;
+                    if(_align.masterSequences.containsKey(seq.group)) {
+                        res += getLetterHeight();
+                        res += getConsOffset();
+                    }
+                }
+            }
+            else if(_align.masterSequences.containsKey(seq.group)) {
+                res += getLetterHeight();
+                res += getConsOffset();
+            }
+            res += lh;
+            if(consensus && i == posy) {
+                return res;
+            }
+            res += seq.above.levels.size()*annotationHeight;
+        }
+        return(res);
+    }
+
+    @Override
+    public int getScreenY(int posy) {
+        return getScreenY(posy, false);
+    }
+
+    @Override
+    public int getScreenYConsensus(int posy) {
+        return getScreenY(posy, true);
+    }
+
+    @Override
+    public int getOffsetY() {
+        return(getScreenY(_offset[1]));
+    }
+
+    private Annotation onAnnotation(int posX, int posY, LinkedList<LinkedList<Annotation>> levels, int ypos) {
+        ypos -= levels.size()*annotationHeight;
+        Annotation found = null;
+        for(LinkedList<Annotation> level : levels) {
+            ypos += annotationHeight;
+            if(posY <= ypos && posY >= ypos - annotationHeight) {
+                for(Annotation anno : level) {
+                    int[] axp = _seqPane.getAnnotationXpos(anno);
+                    if(posX > axp[0] && posX < axp[1]) {
+                        found = anno;
+                        break;
+                    }
+                }
+                if(found != null) {
+                    break;
+                }
+            }
+        }
+        return(found);
+    }
+
+    @Override
+    public Position getRealPos(int[] screenPos) {
+        int[] res = {0, 0};
+        int pos = getLetterHeight();
+        int ypos;
+        Annotation onAnnotation = null;
+        int lh = getLetterHeight();
+        boolean onCollapser = false;
+        boolean onConsensus = false;
+        boolean first = true;
+        GroupKey lastGroup = new GroupKey("__NONAME__");
+        GroupKey onConsensusGroup = null;
+        int numSequences = _align.countAll();
+        for(ypos=_offset[1]; pos < screenPos[1] - getTopOffset() && ypos < numSequences; ypos++) {
+            first = false;
+            if(_align.getSequence(ypos-1) != null) {
+                lastGroup = _align.getSequence(ypos-1).group;
+            }
+            onConsensus = false;
+            onCollapser = false;
+            Sequence seq = _align.getSequence(ypos);
+            Sequence nextSeq = _align.getSequence(ypos + 1);
+            if(nextSeq != null && seq.group != nextSeq.group) {
+                pos += groupSep;
+            }
+            if(lastGroup != seq.group) {
+                if(_align.masterSequences.containsKey(seq.group)) {
+                    pos += getLetterHeight();
+                    pos += getConsOffset();
+                }
+                if(pos >= screenPos[1] - getTopOffset()) {
+                    onConsensus = true;
+                    onConsensusGroup = seq.group;
+                }
+            }
+            if(lastGroup == seq.group && seq.collapsed) {
+                continue;
+            }
+            if(lastGroup != seq.group && screenPos[0] <= 12) {
+                onCollapser = true;
+            }
+            boolean hit = false;
+            if(seq == null) {
+                ypos --;
+                break;
+            }
+            pos += seq.above.levels.size()*annotationHeight;
+            if(pos >= screenPos[1] - getTopOffset()) {
+                onAnnotation = onAnnotation(screenPos[0], screenPos[1] - getTopOffset(), seq.above.levels, pos);
+                hit = true;
+            }
+            pos += lh;
+            if(pos >= screenPos[1] - getTopOffset()) {
+                hit = true;
+            }
+            pos += seq.below.levels.size()*annotationHeight;
+            if(!hit && pos >= screenPos[1] - getTopOffset()) {
+                onAnnotation = onAnnotation(screenPos[0], screenPos[1] - getTopOffset(), seq.below.levels, pos);
+            }
+            if(pos >= screenPos[1] - getTopOffset()) {
+                break;
+            }
+        }
+        res[1] = ypos;
+        if(_align.tripletGrouping == -1) {
+            res[0] = (int)(screenPos[0]/_lw) + _offset[0];
+        }
+        else {
+            res[0] = (int)(((screenPos[0] + (_offset[0]*_lw) + ((_align.tripletGrouping + _offset[0])%3)*tripletDist/3))/(_lw+tripletDist/3));
+        }
+        if(first) {
+            onConsensus = true;
+        }
+        return (new Position(res[0], res[1], onAnnotation!=null, onAnnotation, onCollapser, onConsensus, onConsensusGroup));
+    }
+
+    @Override
+    public void addAnnotation(boolean above, boolean primer) {
+        String text = primer?"Primer":"Annotation";
+        _align.getSequence(selFrom[1]).addAnnotation(above, selFrom[0], selTo[0], text, primer);
+        repaintAll();
+    }
+
+    @Override
+    public boolean isPrimerSequenceActive() {
+        return !settings.getBoolean(Settings.DISPLAY_PRIMER_NAME);
+    }
+
+    @Override
+    public boolean isPrimerTmEnabled() {
+        return settings.getBoolean(Settings.DISPLAY_PRIMER_TEMPERATURE);
+    }
+
+    @Override
+    public boolean isPrimerLengthEnabled() {
+        return settings.getBoolean(Settings.DISPLAY_PRIMER_LENGTH);
+    }
+
+
+    private void unselectAll() {
+        for (Sequence seq : _align.getSequencesAll()) {
+            seq.selected = false;
+        }
+    }
+
+    private void scrollSequences(MouseEvent e) {
+        boolean rep = false;
+        int newx = _offset[0];
+        int newy = _offset[1];
+        if (Math.abs(_lastMousePos[0] - e.getX()) >= _lw && e.getSource() == _seqPane) {
+            newx = (int)(_offset[0] + (_lastMousePos[0] - e.getX()) / _lw);
+            _lastMousePos[0] = e.getX();
+            if (newx < 0) {
+                newx = 0;
+            }
+            rep = true;
+        }
+        if (Math.abs(_lastMousePos[1] - e.getY()) >= getLetterHeight()) {
+            newy = _offset[1] + (_lastMousePos[1] - e.getY()) / getLetterHeight();
+            _lastMousePos[1] = e.getY() - (_lastMousePos[1] - e.getY()) % 8;
+            if (newy < 0) {
+                newy = 0;
+            }
+            rep = true;
+        }
+        if (rep) {
+            scrollTo(newx, newy);
+//            repaintAll();
+        }
+    }
+
+    private void selectNames(MouseEvent e) {
+        int[] pos = {e.getX(), e.getY()};
+        int from = getRealPos(_lastMousePos).y;
+        int to = getRealPos(pos).y;
+        if (!e.isShiftDown()) {
+            unselectAll();
+        }
+        if (from > to) {
+            int tmp = to;
+            to = from;
+            from = tmp;
+        }
+        for (int i = from; i <= to && i < _align.countAll(); i++) {
+            _align.getSequence(i).selected = true;
+        }
+        repaintAll();
+    }
+
+    private void moveSel(int pos0, int pos1) {
+        // Moving disabled until undo is implemented
+/*        for(int i=selFrom[1]; i<selTo[1]; i++) {
+            _align.getSequence(i).movePart(selFrom[0], selTo[0], pos1-pos0);
+        }*/
+    }
+
+    public void loadString(String s, boolean overwrite) {
+        Alignment align = _align;
+        if(overwrite) {
+            align = new Alignment(settings);
+        }
+        String[] lines = s.split(">");
+        HashMap<String, GroupKey> loadedGroups = new HashMap<String, GroupKey>();
+        if(!overwrite) {
+            for(GroupKey key : _align.getGroups()) {
+                if(!loadedGroups.containsKey(key.getName())) {
+                    loadedGroups.put(key.getName(), key);
+                }
+            }
+        }
+        for(String line : lines) {
+            if(line.equals("")) continue;
+            String[] vals = line.split("\n");
+            String name = vals[0];
+            vals[0] = "";
+            StringBuilder seqBuilder = new StringBuilder();
+            for(String val : vals) {
+                seqBuilder.append(val.replace("\r", "").replace(" ", ""));
+            }
+            String seq = seqBuilder.toString().toUpperCase();
+            GroupKey group = baseGroup;
+            if(loadedGroups.containsKey(baseGroup.getName())) {
+                group = loadedGroups.get(baseGroup.getName());
+            }
+            // Get the name of the group the sequence belongs to from the name
+            if(name.contains("%%")) {
+                String[] nameVals = name.split("%%");
+                name = nameVals[0];
+                String groupName = nameVals[1];
+                if(loadedGroups.containsKey(groupName)) {
+                    group = loadedGroups.get(groupName);
+                }
+                else {
+                    group = new GroupKey(groupName);
+                    loadedGroups.put(groupName, group);
+                }
+            }
+            align.addSequence(new Sequence(name, seq, group, _align));
+        }
+        if(overwrite) {
+            _align = align;
+        }
+        _window.setTitle(_filename + "(" + _align.countAll() + " sequences)");
+        _align.sortGroups();
+        _namesPane.updateGroupMenuItems();
+        repaintAll();
+    }
+
+    private void parseTree(JSONArray data, DefaultMutableTreeNode parent) {
+        try {
+            for(int i = 0; i < data.length(); i ++) {
+                JSONObject cdata = data.getJSONObject(i);
+                RKIFolder folder = new RKIFolder(cdata.getJSONObject("property").getString("name"), cdata.getJSONObject("property").getString("data"));
+                DefaultMutableTreeNode child = new DefaultMutableTreeNode(folder);
+                try {
+                    parseTree(cdata.getJSONArray("children"), child);
+                } catch(Exception e) {}
+                parent.add(child);
+            }
+        } catch(Exception e) {
+        }
+    }
+
+    private DefaultMutableTreeNode parseTree(JSONArray data) {
+        try {
+            JSONObject root = data.getJSONObject(0);
+            RKIFolder folder = new RKIFolder(root.getJSONObject("property").getString("name"), root.getJSONObject("property").getString("data"));
+            DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(folder);
+            parseTree(root.getJSONArray("children"), rootNode);
+            return rootNode;
+        } catch(Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    @Override
+    public boolean loadFileRKI(boolean overwrite) {
+        return false;
+    }
+
+    @Override
+    public void loadFile(boolean overwrite) {
+        final JFileChooser fc = new JFileChooser(settings.get(Settings.LAST_LOAD_PATH));
+        fc.removeChoosableFileFilter(fc.getAcceptAllFileFilter());
+        for(FileFilter filter : allFileFilters) {
+            if(filter instanceof LoadFilter) {
+                fc.addChoosableFileFilter(filter);
+            }
+        }
+        int returnVal = fc.showOpenDialog(_window);
+        if (returnVal == JFileChooser.APPROVE_OPTION) {
+            _filename = fc.getSelectedFile().getName();
+            loadFile(fc, overwrite);
+        }
+    }
+
+    @Override
+    public void mouseDragged(MouseEvent e) {
+        if (_mouseButton == 2) {
+            scrollSequences(e);
+        }
+        else if (_mouseButton == 1 && e.getSource() == _namesPane) {
+            if(mode == MODE_MOVESEL) {
+                int[] screenPos = {e.getX(), e.getY()};
+                Position newPos = getRealPos(screenPos);
+                if(newPos.y != _movePos[1]) {
+                    int dist = newPos.y - _movePos[1];
+                    _movePos[1] = newPos.y;
+                    _align.moveSelected(dist);
+                    repaintAll();
+                }
+            }
+//            selectNames(e);
+        }
+        else if (_mouseButton == 1 && e.getSource() == _seqPane && editedAnnotation == null) {
+            int[] screenPos = {e.getX(), e.getY()};
+            if(mode == MODE_MOVESEL) {
+                Position newPos = getRealPos(screenPos);
+                if(newPos.x != _movePos[0]) {
+                    int diff = newPos.x - _movePos[0];
+                    if(selFrom[0] + diff >= 0 && selTo[0] + diff <= _align.getLongestAll()) {
+                        selFrom[0] += diff;
+                        selTo[0] += diff;
+                    }
+                    _movePos[0] = newPos.x;
+                    repaintAll();
+                }
+                if(newPos.y != _movePos[1]) {
+                    int diff = newPos.y - _movePos[1];
+                    if(selFrom[1] + diff >= 0 && selTo[1] + diff <= _align.countAll()) {
+                        selFrom[1] += diff;
+                        selTo[1] += diff;
+                    }
+                    _movePos[1] = newPos.y;
+                    repaintAll();
+                }
+            }
+            else if(mode == MODE_RESIZESEL_E || mode == MODE_RESIZESEL_W || mode == MODE_RESIZESEL_N || mode == MODE_RESIZESEL_S) {
+                Position newPos = getRealPos(screenPos);
+                int diffx = newPos.x - _movePos[0];
+                int diffy = newPos.y - _movePos[1];
+                if(diffx != 0) {
+                    if(mode == MODE_RESIZESEL_E) {
+                        selTo[0] += diffx;
+                    }
+                    if(mode == MODE_RESIZESEL_W) {
+                        selFrom[0] += diffx;
+                    }
+                    _movePos[0] = newPos.x;
+                    _seqPane.repaint();
+                }
+                if(diffy != 0) {
+                    if(mode == MODE_RESIZESEL_S) {
+                        selTo[1] += diffy;
+                    }
+                    if(mode == MODE_RESIZESEL_N) {
+                        selFrom[1] += diffy;
+                    }
+                    _movePos[1] = newPos.y;
+                    _seqPane.repaint();
+                }
+            }
+            else if(mode == MODE_MOVEANNO || mode == MODE_RESIZEANNO_E || mode == MODE_RESIZEANNO_W) {
+                Position newPos = getRealPos(screenPos);
+                int diff = newPos.x - _movePos[0];
+                if(diff != 0) {
+                    if(mode == MODE_RESIZEANNO_E || mode == MODE_MOVEANNO) {
+                        selectedAnnotation.to += diff;
+                    }
+                    if(mode == MODE_RESIZEANNO_W || mode == MODE_MOVEANNO) {
+                        selectedAnnotation.from += diff;
+                    }
+                    _movePos[0] = newPos.x;
+                    if(selectedAnnotation.from < 0)
+                        selectedAnnotation.from = 0;
+                    if(selectedAnnotation.to >= _align.getLongestAll())
+                        selectedAnnotation.from = _align.getLongestAll()-selectedAnnotation.from-1;
+                    if(selectedAnnotation instanceof Primer) {
+                        ((Primer)(selectedAnnotation)).updateScores();
+                        selectedAnnotation.list.sequence.updateProducts();
+                    }
+                    _seqPane.repaint();
+                    updateFlowgrams(false);
+                }
+            }
+            else {
+                int[] oldTo = {selTo[0], selTo[1]};
+                Position p = getRealPos(screenPos);
+                selTo[0] = p.x;
+                if(selConsensus) {
+                    if(consensusGroup == null) {
+                        selFrom[1]=0;
+                        selTo[1] = _align.countAll();
+                    }
+                    else {
+                        selFrom[1] = _align.getGroupFirst(consensusGroup);
+                        selTo[1] = selFrom[1] + _align.count(consensusGroup);
+                    }
+                }
+                else {
+                    selTo[1] = p.y+1;
+                    if(selTo[1] == selFrom[1]) {
+                        selFrom[1] -= 1;
+                    }
+                }
+                if(oldTo[0] != selTo[0] || oldTo[1] != selTo[1]) {
+                    repaintAll();
+                }
+            }
+        }
+    }
+
+    public SequenceInfo getToolTip() {
+        if(_toolTip == null) {
+            _toolTip = new SequenceInfo();
+            _toolTip.text = "Test";
+        }
+        return(_toolTip);
+    }
+
+    @Override
+    public void mouseMoved(MouseEvent e) {
+        if(mode != MODE_EDITING) {
+            int[] screenPos = {e.getX(), e.getY()};
+            Position realPos = getRealPos(screenPos);
+            if(realPos.x != _lastPos[0] || realPos.y != _lastPos[1]) {
+                _seqPane.redrawCursor(realPos.x, realPos.y);
+                _seqPane.repaint();
+                _lastPos[0] = realPos.x;
+                _lastPos[1] = realPos.y;
+            }
+            if(e.getSource() == _seqPane || e.getSource() == _namesPane) {
+                _seqPane.seqNum = realPos.y;
+                if(realPos.onConsensus) {
+                    if(_align.getSequence(realPos.y) == null) {
+                        return;
+                    }
+                    _seqPane.toolTipText = "Consensus for " + _align.getSequence(realPos.y).group.getName();
+                    _window.messageLabel.setText(_seqPane.toolTipText);
+                }
+                else {
+                    if(_align.getSequence(realPos.y) == null) {
+                        return;
+                    }
+                    _seqPane.toolTipText = _align.getSequence(realPos.y).name;
+                    _window.messageLabel.setText(_seqPane.toolTipText);
+                }
+                if(realPos.onAnnotation) {
+                    if(realPos.x < realPos.annotation.from+1) {
+                        _window.setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
+                    }
+                    else if(realPos.x >= realPos.annotation.to-1) {
+                        _window.setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
+                    }
+                    else {
+                        _window.setCursor(new Cursor(Cursor.TEXT_CURSOR));
+                    }
+                    _selectionActive = false;
+                }
+                else if(pointInSelection(screenPos)) {
+                    setSelectionResize(false, true, screenPos);
+                    _selectionActive = true;
+                }
+                else {
+                    _selectionActive = false;
+                    _window.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+                }
+            }
+        }
+        if(e.getSource() != _seqPane) {
+            getToolTip().setVisible(false);
+        }
+    }
+
+    @Override
+    public void mouseClicked(MouseEvent e) {
+        if(e.getButton() == 3) {
+            return;
+        }
+        if (e.getSource() == _namesPane) {
+            if (!e.isShiftDown() && !e.isControlDown()) {
+                unselectAll();
+            }
+            int[] pos = {e.getX(), e.getY()};
+            Position realPos = getRealPos(pos);
+            if(realPos.onCollapser) {
+                Sequence selectedSeq = _align.getSequence(realPos.y);
+                selectedSeq.collapsed = !selectedSeq.collapsed;
+                for(Sequence seq : _align.getSequences(selectedSeq.group)) {
+                    seq.collapsed = selectedSeq.collapsed;
+                }
+            }
+            else {
+                if(!e.isShiftDown() || _lastSelected == -1) {
+                    if(_align.getSequence(realPos.y) == null)
+                        return;
+                    _align.getSequence(realPos.y).selected ^= true;
+                    if(_align.getSequence(realPos.y).selected) {
+                        _lastSelected = realPos.y;
+                    }
+                }
+                else {
+                    if(_lastSelected != -1) {
+                        for(int i=Math.min(_lastSelected, realPos.y); i <= Math.max(_lastSelected, realPos.y); i++) {
+                            _align.getSequence(i).selected = true;
+                        }
+                    }
+                }
+            }
+            repaintAll();
+        }
+        else {
+            int[] coords = {e.getX(), e.getY()};
+            Position pos = getRealPos(coords);
+            if(pos.onAnnotation) {
+                editedAnnotation = pos.annotation;
+                if(editedAnnotation instanceof Primer && isPrimerSequenceActive()) {
+                    _primerEditPos = pos.x - editedAnnotation.from;
+                }
+            }
+            else if(editedAnnotation == null) {
+                if(mode == MODE_SELECTING) {
+                    mode = MODE_EDITING;
+                }
+                else {
+                    mode = MODE_NORMAL;
+                }
+                selFrom[0] = 0;
+                selFrom[1] = 0;
+                selTo[0] = 0;
+                selTo[1] = 0;
+            }
+            _seqPane.repaint();
+        }
+    }
+
+    @Override
+    public void mouseEntered(MouseEvent arg0) {
+    }
+
+    @Override
+    public void mouseExited(MouseEvent arg0) {
+        getToolTip().setVisible(false);
+    }
+
+    @Override
+    public void mousePressed(MouseEvent e) {
+        _mouseButton = e.getButton();
+        _lastMousePos[0] = e.getX();
+        _lastMousePos[1] = e.getY();
+        if(_mouseButton == MouseEvent.BUTTON2) {
+            _window.setCursor(new Cursor(Cursor.MOVE_CURSOR));
+        }
+        else if(_mouseButton == MouseEvent.BUTTON1 && e.getSource() == _namesPane) {
+            int[] screenPos = {e.getX(), e.getY()};
+            Position realPos = getRealPos(screenPos);
+            if(_align.getSequence(realPos.y) == null)
+                return;
+            if(_align.getSequence(realPos.y).selected) {
+                _window.setCursor(new Cursor(Cursor.MOVE_CURSOR));
+                mode = MODE_MOVESEL;
+                _movePos[0] = getRealPos(screenPos).x;
+                _movePos[1] = getRealPos(screenPos).y;
+            }
+        }
+        else if(_mouseButton == MouseEvent.BUTTON1 && e.getSource() == _seqPane && editedAnnotation == null) {
+            int[] screenPos = {e.getX(), e.getY()};
+            Position realPos = getRealPos(screenPos);
+            if(pointInSelection(screenPos)) {
+                setSelectionResize(true, false, screenPos);
+//                mode = MODE_MOVESEL;
+                _movePos[0] = getRealPos(screenPos).x;
+                _movePos[1] = getRealPos(screenPos).y;
+                _window.setCursor(new Cursor(Cursor.MOVE_CURSOR));
+                editedAnnotation = null;
+            }
+            else if(realPos.onAnnotation) {
+                if(realPos.x < realPos.annotation.from+1) {
+                    mode = MODE_RESIZEANNO_W;
+                }
+                else if(realPos.x >= realPos.annotation.to-1) {
+                    mode = MODE_RESIZEANNO_E;
+                }
+                else {
+                    mode = MODE_MOVEANNO;
+                    _window.setCursor(new Cursor(Cursor.MOVE_CURSOR));
+                }
+                editedAnnotation = null;
+                _movePos[0] = getRealPos(screenPos).x;
+                _movePos[1] = getRealPos(screenPos).y;
+                selectedAnnotation = realPos.annotation;
+            }
+            else {
+                if(mode == MODE_EDITING) {
+                    mode = MODE_SELECTING2;
+                    editedAnnotation = null;
+                }
+                else {
+                    mode = MODE_SELECTING;
+                    editedAnnotation = null;
+                }
+                Position pos = getRealPos(screenPos);
+                selFrom = pos.getCoordinates();
+                selTo = pos.getCoordinates();
+                selConsensus = pos.onConsensus;
+                consensusGroup = pos.consensusGroup;
+            }
+        }
+    }
+
+    @Override
+    public void mouseReleased(MouseEvent arg0) {
+        _window.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+        if(mode == MODE_MOVEANNO || mode == MODE_RESIZEANNO_E || mode == MODE_RESIZEANNO_W) {
+            if(selectedAnnotation != null) {
+                selectedAnnotation.list.resetAnnotations();
+                selectedAnnotation.list.sequence.updateProducts();
+                selectedAnnotation = null;
+                repaintAll();
+            }
+        }
+    }
+
+    @Override
+    public void keyTyped(KeyEvent e) {
+        if(mode!=MODE_EDITING) {
+            if(e.getKeyChar() == '-') {
+                doZoom(1);
+            }
+            else if(e.getKeyChar() == '+') {
+                doZoom(-1);
+            }
+        }
+    }
+
+    public void scrollTo(int x, int y) {
+        if(_offset[0] == x && _offset[1] == y) {
+            repaintAll();
+            return;
+        }
+        _offset[0] = x;
+        _offset[1] = y;
+        updateScrollbar();
+        repaintAll();
+//        _hscrollBar.setValue(x);
+//        _scrollBar.setValue(y);
+    }
+
+    public void searchForSequence(String seq, boolean allowGaps) {
+        int[] pos = _align.findSubSequence(selFrom[1], selTo[0], seq, allowGaps);
+        if(pos[0] != -1) {
+            selFrom[1] = pos[0];
+            selTo[1] = pos[0]+1;
+            selFrom[0] = pos[1];
+            selTo[0] = pos[1] + pos[2];
+            scrollTo(selFrom[0], selFrom[1]);
+            repaintAll();
+        }
+        else if(selFrom[0] == 0 && selTo[0] == 0 && selFrom[1] == 0 && selTo[1] == 0) {
+            JOptionPane.showMessageDialog(null, "Sequence not found.", "Sequence not found", JOptionPane.WARNING_MESSAGE);
+        }
+        else {
+            String[] opts = {"Yes", "No"};
+            int res = JOptionPane.showOptionDialog(null, "Sequence not found. Start again from beginning?", "Sequence not found", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, opts, opts[0]);
+            if(res==0) {
+                selFrom[0] = 0;
+                selFrom[1] = 0;
+                selTo[0] = 0;
+                selTo[1] = 0;
+                repaintAll();
+                searchForSequence(seq, allowGaps);
+            }
+        }
+    }
+
+    public void copySequence(boolean withName) {
+        _seqPane.copySequences(withName);
+    }
+
+    private Frame findParentFrame() {
+        return((Frame)null);
+    }
+
+
+    @Override
+    public void keyPressed(KeyEvent e) {
+        int key = e.getKeyCode();
+        if(key == KeyEvent.VK_F && (e.getModifiers() & KeyEvent.CTRL_MASK) != 0 ) {
+            FindDialog d = new FindDialog(findParentFrame());
+            d.setText(_lastSearch);
+            d.allowGaps(_lastSearchAllowedGaps);
+            d.setVisible(true);
+            if(d.isAccepted()) {
+                _lastSearch = Sequence.cleanUpSequence(d.getSeq());
+                _lastSearchAllowedGaps = d.allowGaps();
+                mode = MODE_NORMAL;
+                searchForSequence(_lastSearch, _lastSearchAllowedGaps);
+            }
+        }
+        else if(key == KeyEvent.VK_C && (e.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
+            Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
+            StringBuilder seqStringBuilder = new StringBuilder();
+            for(int i=getSelFrom()[1]; i<getSelTo()[1]; i++) {
+                Sequence seq = getAlignment().getSequence(i);
+                seqStringBuilder.append(seq.seq.substring(getSelFrom()[0], getSelTo()[0]));
+                seqStringBuilder.append("\n");
+            }
+            StringSelection contents = new StringSelection(seqStringBuilder.toString());
+            clip.setContents(contents, null);
+
+        }
+        else if(key == KeyEvent.VK_F3) {
+            if(!_lastSearch.equals("")) {
+                mode = MODE_NORMAL;
+                searchForSequence(_lastSearch, _lastSearchAllowedGaps);
+            }
+        }
+        else if(mode == MODE_EDITING) {
+            boolean seqChanged = false;
+            if(key == KeyEvent.VK_LEFT) {
+                _lastPos[0] -= 1;
+            }
+            else if(key == KeyEvent.VK_RIGHT) {
+                _lastPos[0] += 1;
+            }
+            else if(key == KeyEvent.VK_UP && _lastPos[1] >= 1) {
+                _lastPos[1] -= 1;
+            }
+            else if(key == KeyEvent.VK_DOWN && _lastPos[1] < _align.countAll()-1) {
+                _lastPos[1] += 1;
+            }
+            else if(charIsInAlphabet(e.getKeyChar())) {
+                _align.getSequence(_lastPos[1]).setCharAt(_lastPos[0], Character.toUpperCase(e.getKeyChar()));
+                _lastPos[0] += 1;
+                seqChanged = true;
+            }
+            consensusChange();
+            _seqPane.redrawCursor(_lastPos[0], _lastPos[1]);
+            _seqPane.redrawAll();
+            _seqPane.repaint();
+        }
+        else if(editedAnnotation instanceof Primer && editedAnnotation != null) {
+            Primer primer = (Primer)editedAnnotation;
+            char k = e.getKeyChar();
+            if(key == KeyEvent.VK_LEFT && _primerEditPos != 0) {
+                _primerEditPos -= 1;
+            }
+            else if(key == KeyEvent.VK_RIGHT && _primerEditPos+1 < primer.getSequence().length()) {
+                _primerEditPos += 1;
+            }
+            else if(charIsInAlphabet(k)) {
+                primer.lockBase(_primerEditPos, Character.toUpperCase(e.getKeyChar()));
+                if(_primerEditPos+1 < primer.getSequence().length())
+                    _primerEditPos += 1;
+                primer.updateScores();
+            }
+            repaintAll();
+        }
+        else if(key == KeyEvent.VK_N) {
+            if(_conservedRegionsIndex < _conservedRegions.size() - 1) {
+                _conservedRegionsIndex += 1;
+                scrollTo(_conservedRegions.get(_conservedRegionsIndex)[0], _offset[1]);
+                selFrom[0] = _offset[0];
+                selFrom[1] = 0;
+                selTo[0] = selFrom[0] + _conservedRegions.get(_conservedRegionsIndex)[1];
+                selTo[1] = _align.countAll();
+                repaintAll();
+            }
+        }
+    }
+
+    @Override
+    public void consensusChange() {
+        if(_window.keepConsensusUpdated.isSelected()) {
+            if(hasMasterSequence)
+                getMasterConsensus();
+            if(hasGroupMasterSequences)
+                getGroupMasterSequences();
+        }
+    }
+
+    private boolean charIsInAlphabet(char oc) {
+        char c = Character.toLowerCase(oc);
+        if(c == 'a' || c == 'g' || c == 't' || c == 'c' || c == '-' || c == 'r' || c == 'y' ||
+                c == 'm' || c == 'k' || c == 'w' || c == 's' || c == 'b' || c == 'd' ||
+                c == 'h' || c == 'v' || c == 'n') {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void keyReleased(KeyEvent arg0) {
+    }
+
+    @Override
+    public void focusGained(FocusEvent arg0) {
+    }
+
+    @Override
+    public void focusLost(FocusEvent arg0) {
+    }
+
+    public void doZoom(int direction) {
+        if(direction < 0) {
+            if(_lw == 10 || _lw == 8) {
+                _lw += 2;
+            }
+            else if(_lw < 8) {
+                _lw *= 2;
+            }
+        }
+        else if(direction > 0) {
+            if(_lw == 12 || _lw == 10) {
+                _lw -= 2;
+            }
+            else if(_lw <= 8) {
+                _lw /= 2;
+            }
+        }
+        updateScrollbar();
+        repaintAll();
+    }
+
+    @Override
+    public void mouseWheelMoved(MouseWheelEvent e) {
+        int notches = e.getWheelRotation();
+        if(e.isControlDown()) {
+            doZoom(notches);
+        }
+        else if(e.isShiftDown()) {
+            if(_offset[0] + notches >= 0 && _offset[0] + notches < _align.getLongestAll())
+                scrollHorizontal(_offset[0] + notches);
+        }
+        else {
+            if(_offset[1] + notches >= 0 && _offset[1] + notches < _align.countAll())
+                scrollVertical(_offset[1] + notches);
+        }
+    }
+
+    @Override
+    public void adjustmentValueChanged(AdjustmentEvent e) {
+        if(e.getSource() == _scrollBar) {
+            scrollTo(_offset[0], e.getValue());
+        }
+        else if(e.getSource() == _hscrollBar) {
+            scrollTo(e.getValue(), _offset[1]);
+        }
+        repaintAll();
+    }
+
+    @Override
+    public boolean isApplication() {
+        return true;
+    }
+
+    public void settingsClicked() {
+        new OptionsFrame(this).setVisible(true);
+    }
+
+    public void updatePrimerTMs() {
+        for(Sequence seq : _align.getSequencesAll()) {
+            for(Annotation anno : seq.above.getAnnotations()) {
+                if(anno instanceof Primer)
+                    ((Primer)anno).updateTm();
+            }
+            for(Annotation anno : seq.below.getAnnotations()) {
+                if(anno instanceof Primer)
+                    ((Primer)anno).updateTm();
+            }
+        }
+        repaintAll();
+    }
+
+    @Override
+    public Settings getSettings() {
+        return settings;
+    }
+
+    @Override
+    public void updateFlowgrams(boolean fromWindow) {
+        _seqPane.updateFlowgrams(fromWindow);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/view/EditorInterface.java b/src/org/rki/sequenceeditor/view/EditorInterface.java
new file mode 100644
index 0000000..cfa0012
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/EditorInterface.java
@@ -0,0 +1,107 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.Frame;
+import java.awt.event.AdjustmentListener;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.util.HashMap;
+import org.rki.sequenceeditor.model.Alignment;
+import org.rki.sequenceeditor.model.Annotation;
+import org.rki.sequenceeditor.model.GroupKey;
+import org.rki.sequenceeditor.model.MasterSequence;
+import org.rki.sequenceeditor.model.Position;
+import org.rki.sequenceeditor.model.Sequence;
+import org.rki.sequenceeditor.model.Settings;
+import org.rki.sequenceeditor.model.filters.LoadFilter;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public interface EditorInterface extends MouseMotionListener, MouseListener, KeyListener, FocusListener, AdjustmentListener {
+    public boolean isApplication();
+    public boolean hasMenu();
+    public boolean showSequenceName();
+    public boolean useIUB();
+
+    public int getAppletWidth();
+    public int getAppletHeight();
+    public Alignment getAlignment();
+    public int getLetterHeight();
+    public double getLetterWidth();
+    public int getConsOffset();
+    public int getOffsetY();
+    public int getTopOffset();
+
+    public int getTripletDist();
+    public int getConsHeight();
+
+    public int getScreenY(int pos);
+    public int getScreenYConsensus(int pos);
+    public int getScreenX(int pos);
+    public int getRulerHeight();
+
+    public Position getRealPos(int[] screenPos);
+    public void setMasterSequence(MasterSequence master, GroupKey group);
+    public void setMasterSequenceAll(MasterSequence master);
+
+    public void repaintAll();
+
+    public void getMasterConsensus();
+    public void getGroupMasterSequences();
+    public void getConsensus(GroupKey group);
+
+    public int[] getSelFrom();
+    public int[] getSelTo();
+
+    public int getMode();
+
+    public int getAnnotationHeight();
+
+    public Annotation getEditedAnnotation();
+    public void setEditedAnnotation(Annotation anno);
+    public HashMap<GroupKey, MasterSequence> getMasterSequences();
+    public MasterSequence getMasterSequenceAll();
+    public Frame getParentFrame();
+
+    public void loadFile(boolean replace);
+    public boolean loadFileRKI(boolean replace);
+    public void saveToRKITools(String name);
+    public void saveFile();
+    public void saveFileAs();
+    public String seqsToString(boolean pureFASTA);
+    public void findSNPs();
+    public void addAnnotation(boolean above, boolean primer);
+    public void setColorOpts(String name);
+    public void setLetterWidth(int size);
+    public void setSelFrom(int index, int value);
+    public void setSelTo(int index, int value);
+
+    public void mouseWheelMoved(MouseWheelEvent e);
+
+    public boolean isSelectionActive();
+    public boolean isPrimerSequenceActive();
+    public boolean isPrimerTmEnabled();
+    public boolean isPrimerLengthEnabled();
+
+    public int getPrimerEditPos();
+
+    public boolean canAddAnnotation();
+    public boolean isSequenceSelected();
+
+    public void consensusChange();
+
+    public Settings getSettings();
+
+    public void updateFlowgrams(boolean fromWindow);
+
+    public void loadFile(boolean overwrite, LoadFilter filter, String filename);
+}
diff --git a/src/org/rki/sequenceeditor/view/EditorWindow.form b/src/org/rki/sequenceeditor/view/EditorWindow.form
new file mode 100644
index 0000000..14cf269
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/EditorWindow.form
@@ -0,0 +1,723 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <NonVisualComponents>
+    <Menu class="javax.swing.JMenuBar" name="jMenuBar1">
+      <SubComponents>
+        <Menu class="javax.swing.JMenu" name="jMenu1">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="File" noResource="true"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="menuLoadFile">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+O"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Load file" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuLoadFileActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="menuAppendFromFile">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+A"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Append from file" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuAppendFromFileActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="menuSaveItem">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+S"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Save" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuSaveItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="menuSaveAsItem">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Shift+Ctrl+S"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Save as" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="menuSaveAsItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <Menu class="javax.swing.JMenu" name="recentMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Open recent" noResource="true"/>
+              </Properties>
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+              </AuxValues>
+            </Menu>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="jMenu2">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Edit" noResource="true"/>
+          </Properties>
+          <Events>
+            <EventHandler event="menuSelected" listener="javax.swing.event.MenuListener" parameters="javax.swing.event.MenuEvent" handler="jMenu2MenuSelected"/>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenu2ActionPerformed"/>
+          </Events>
+          <SubComponents>
+            <Menu class="javax.swing.JMenu" name="copyMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Copy" noResource="true"/>
+              </Properties>
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+              </AuxValues>
+              <SubComponents>
+                <MenuItem class="javax.swing.JMenuItem" name="sequenceCopyMenu">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Sequences" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sequenceCopyMenuActionPerformed"/>
+                  </Events>
+                  <AuxValues>
+                    <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+                  </AuxValues>
+                </MenuItem>
+                <MenuItem class="javax.swing.JMenuItem" name="sequenceWithNameCopyMenu">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Sequences with names" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sequenceWithNameCopyMenuActionPerformed"/>
+                  </Events>
+                  <AuxValues>
+                    <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+                  </AuxValues>
+                </MenuItem>
+                <MenuItem class="javax.swing.JMenuItem" name="masterConsensusCopyMenu">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Master consensus sequence" noResource="true"/>
+                    <Property name="enabled" type="boolean" value="false"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="masterConsensusCopyMenuActionPerformed"/>
+                  </Events>
+                  <AuxValues>
+                    <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+                  </AuxValues>
+                </MenuItem>
+                <MenuItem class="javax.swing.JMenuItem" name="groupConsensusCopyMenu">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="Group consensus sequence" noResource="true"/>
+                    <Property name="enabled" type="boolean" value="false"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="groupConsensusCopyMenuActionPerformed"/>
+                  </Events>
+                  <AuxValues>
+                    <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+                  </AuxValues>
+                </MenuItem>
+              </SubComponents>
+            </Menu>
+            <MenuItem class="javax.swing.JMenuItem" name="settingsMenuItem">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Settings" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="settingsMenuItemActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="jMenu5">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="View" noResource="true"/>
+          </Properties>
+          <SubComponents>
+            <Menu class="javax.swing.JMenu" name="colorModelMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Color Model" noResource="true"/>
+              </Properties>
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+              </AuxValues>
+            </Menu>
+            <Menu class="javax.swing.JMenu" name="jMenu6">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Text size" noResource="true"/>
+              </Properties>
+              <SubComponents>
+                <MenuItem class="javax.swing.JMenuItem" name="jMenuItem3">
+                  <Properties>
+                    <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                      <KeyStroke key="Shift+Ctrl+1"/>
+                    </Property>
+                    <Property name="text" type="java.lang.String" value="1 pt" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem3ActionPerformed"/>
+                  </Events>
+                </MenuItem>
+                <MenuItem class="javax.swing.JMenuItem" name="jMenuItem4">
+                  <Properties>
+                    <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                      <KeyStroke key="Shift+Ctrl+2"/>
+                    </Property>
+                    <Property name="text" type="java.lang.String" value="2 pt" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem4ActionPerformed"/>
+                  </Events>
+                </MenuItem>
+                <MenuItem class="javax.swing.JMenuItem" name="jMenuItem5">
+                  <Properties>
+                    <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                      <KeyStroke key="Shift+Ctrl+3"/>
+                    </Property>
+                    <Property name="text" type="java.lang.String" value="4 pt" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem5ActionPerformed"/>
+                  </Events>
+                </MenuItem>
+                <MenuItem class="javax.swing.JMenuItem" name="jMenuItem6">
+                  <Properties>
+                    <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                      <KeyStroke key="Shift+Ctrl+4"/>
+                    </Property>
+                    <Property name="text" type="java.lang.String" value="8 pt" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem6ActionPerformed"/>
+                  </Events>
+                </MenuItem>
+                <MenuItem class="javax.swing.JMenuItem" name="jMenuItem7">
+                  <Properties>
+                    <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                      <KeyStroke key="Shift+Ctrl+5"/>
+                    </Property>
+                    <Property name="text" type="java.lang.String" value="10 pt" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem7ActionPerformed"/>
+                  </Events>
+                </MenuItem>
+                <MenuItem class="javax.swing.JMenuItem" name="jMenuItem8">
+                  <Properties>
+                    <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                      <KeyStroke key="Shift+Ctrl+6"/>
+                    </Property>
+                    <Property name="text" type="java.lang.String" value="12 pt" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem8ActionPerformed"/>
+                  </Events>
+                </MenuItem>
+              </SubComponents>
+            </Menu>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem9">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+PLUS"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Zoom in" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem9ActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem10">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+MINUS"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Zoom out" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem10ActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="jMenu3">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Analyze" noResource="true"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="calcMasterConsensus">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Calculate master consensus" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="calcMasterConsensusActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="calcGroupConsensus">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+G"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Calculate gruop consensus" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="calcGroupConsensusActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JCheckBoxMenuItem" name="keepConsensusUpdated">
+              <Properties>
+                <Property name="selected" type="boolean" value="true"/>
+                <Property name="text" type="java.lang.String" value="Keep consensus up to date" noResource="true"/>
+              </Properties>
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+              </AuxValues>
+            </MenuItem>
+            <MenuItem class="javax.swing.JSeparator" name="jSeparator1">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="groupIdentical">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Group identical sequences" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="groupIdenticalActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <Menu class="javax.swing.JMenu" name="jMenu4">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Sort sequences" noResource="true"/>
+              </Properties>
+              <SubComponents>
+                <MenuItem class="javax.swing.JMenuItem" name="sortByName">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="By name" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sortByNameActionPerformed"/>
+                  </Events>
+                </MenuItem>
+                <MenuItem class="javax.swing.JMenuItem" name="sortByIdentity">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="By degree of identity" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sortByIdentityActionPerformed"/>
+                  </Events>
+                </MenuItem>
+                <MenuItem class="javax.swing.JMenuItem" name="sortBySelectionIdentity">
+                  <Properties>
+                    <Property name="text" type="java.lang.String" value="By degree of identity in selection" noResource="true"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sortBySelectionIdentityActionPerformed"/>
+                  </Events>
+                </MenuItem>
+              </SubComponents>
+            </Menu>
+            <MenuItem class="javax.swing.JPopupMenu$Separator" name="jSeparator2">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem1">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+I"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Find all SNPs" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem1ActionPerformed"/>
+              </Events>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem2">
+              <Properties>
+                <Property name="accelerator" type="javax.swing.KeyStroke" editor="org.netbeans.modules.form.editors.KeyStrokeEditor">
+                  <KeyStroke key="Ctrl+R"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="Show predicted flowgrams" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem2ActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="jMenu7">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Help" noResource="true"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="jMenuItem11">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Contents" noResource="true"/>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="jMenuItem11ActionPerformed"/>
+              </Events>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+      </SubComponents>
+    </Menu>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="3"/>
+    <Property name="title" type="java.lang.String" value="mPSQed" noResource="true"/>
+    <Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
+      <Color blue="fe" green="fe" red="fe" type="rgb"/>
+    </Property>
+    <Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
+      <Color blue="ff" green="ff" id="white" palette="1" red="ff" type="palette"/>
+    </Property>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="menuBar" type="java.lang.String" value="jMenuBar1"/>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="statusBar" alignment="1" max="32767" attributes="0"/>
+          <Component id="displayPanel" alignment="0" max="32767" attributes="0"/>
+          <Component id="jToolBar1" alignment="0" pref="947" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <Component id="jToolBar1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="displayPanel" max="32767" attributes="0"/>
+              <EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
+              <Component id="statusBar" min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="statusBar">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
+            <EtchetBorder/>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Component id="messageLabel" alignment="0" pref="943" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Component id="messageLabel" min="-2" max="-2" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JLabel" name="messageLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="RKI Sequence editor loading..." noResource="true"/>
+          </Properties>
+          <AuxValues>
+            <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+          </AuxValues>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="displayPanel">
+      <Properties>
+        <Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
+          <Color blue="fe" green="fe" red="fe" type="rgb"/>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Component id="jSplitPane1" alignment="0" pref="947" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Component id="jSplitPane1" alignment="0" pref="535" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Container class="javax.swing.JSplitPane" name="jSplitPane1">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout"/>
+          <SubComponents>
+            <Container class="org.rki.sequenceeditor.view.NamesPane" name="namesPane1">
+              <Properties>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[100, 0]"/>
+                </Property>
+              </Properties>
+              <AuxValues>
+                <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+              </AuxValues>
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+                  <JSplitPaneConstraints position="left"/>
+                </Constraint>
+              </Constraints>
+
+              <Layout>
+                <DimensionLayout dim="0">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <EmptySpace min="0" pref="100" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+                <DimensionLayout dim="1">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <EmptySpace min="0" pref="535" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+              </Layout>
+            </Container>
+            <Container class="javax.swing.JPanel" name="jPanel1">
+              <Constraints>
+                <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JSplitPaneSupportLayout$JSplitPaneConstraintsDescription">
+                  <JSplitPaneConstraints position="right"/>
+                </Constraint>
+              </Constraints>
+
+              <Layout>
+                <DimensionLayout dim="0">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" attributes="0">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Component id="sequencePane1" max="32767" attributes="0"/>
+                              <Component id="horizontalScrollBar" alignment="1" pref="827" max="32767" attributes="0"/>
+                          </Group>
+                          <EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
+                          <Component id="verticalScrollBar" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+                </DimensionLayout>
+                <DimensionLayout dim="1">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" alignment="1" attributes="0">
+                          <Component id="sequencePane1" max="32767" attributes="0"/>
+                          <EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
+                          <Component id="horizontalScrollBar" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <Component id="verticalScrollBar" alignment="0" pref="535" max="32767" attributes="0"/>
+                  </Group>
+                </DimensionLayout>
+              </Layout>
+              <SubComponents>
+                <Container class="org.rki.sequenceeditor.view.SequencePane" name="sequencePane1">
+                  <Events>
+                    <EventHandler event="componentResized" listener="java.awt.event.ComponentListener" parameters="java.awt.event.ComponentEvent" handler="sequencePane1ComponentResized"/>
+                  </Events>
+                  <AuxValues>
+                    <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+                  </AuxValues>
+
+                  <Layout>
+                    <DimensionLayout dim="0">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <EmptySpace min="0" pref="827" max="32767" attributes="0"/>
+                      </Group>
+                    </DimensionLayout>
+                    <DimensionLayout dim="1">
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <EmptySpace min="0" pref="520" max="32767" attributes="0"/>
+                      </Group>
+                    </DimensionLayout>
+                  </Layout>
+                </Container>
+                <Component class="javax.swing.JScrollBar" name="horizontalScrollBar">
+                  <Properties>
+                    <Property name="orientation" type="int" value="0"/>
+                    <Property name="focusable" type="boolean" value="false"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="adjustmentValueChanged" listener="java.awt.event.AdjustmentListener" parameters="java.awt.event.AdjustmentEvent" handler="horizontalScrollBarAdjustmentValueChanged"/>
+                  </Events>
+                  <AuxValues>
+                    <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+                  </AuxValues>
+                </Component>
+                <Component class="javax.swing.JScrollBar" name="verticalScrollBar">
+                  <Properties>
+                    <Property name="focusable" type="boolean" value="false"/>
+                  </Properties>
+                  <Events>
+                    <EventHandler event="adjustmentValueChanged" listener="java.awt.event.AdjustmentListener" parameters="java.awt.event.AdjustmentEvent" handler="verticalScrollBarAdjustmentValueChanged"/>
+                  </Events>
+                  <AuxValues>
+                    <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+                  </AuxValues>
+                </Component>
+              </SubComponents>
+            </Container>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JToolBar" name="jToolBar1">
+      <Properties>
+        <Property name="rollover" type="boolean" value="true"/>
+      </Properties>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JToggleButton" name="IUBButton">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/non-IUB.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Use IUB for consensus sequence" noResource="true"/>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="null"/>
+            </Property>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[-3, -3, -3, -3]"/>
+            </Property>
+            <Property name="selectedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/IUB.png"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="IUBButtonActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JToggleButton" name="primerDisplayButton">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/primer_display.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Display primer sequence instead of name" noResource="true"/>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="null"/>
+            </Property>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[-3, -3, -3, -3]"/>
+            </Property>
+            <Property name="pressedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/primer_sequence_display.png"/>
+            </Property>
+            <Property name="selectedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/primer_sequence_display.png"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="primerDisplayButtonActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JToggleButton" name="primerTemperatureDisplayButton">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/primer_temperature_display.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Display primer melting temperature" noResource="true"/>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="null"/>
+            </Property>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[-3, -3, -3, -3]"/>
+            </Property>
+            <Property name="pressedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/primer_no_temperature_display.png"/>
+            </Property>
+            <Property name="selectedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/primer_no_temperature_display.png"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="primerTemperatureDisplayButtonActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JToggleButton" name="primerLengthDisplayButton">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/primer_length_display.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="Display primer length" noResource="true"/>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="null"/>
+            </Property>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[-3, -3, -3, -3]"/>
+            </Property>
+            <Property name="pressedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/primer_no_length_display.png"/>
+            </Property>
+            <Property name="selectedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/primer_no_length_display.png"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="primerLengthDisplayButtonActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JToggleButton" name="sequenceNameButton">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/no_sequence_name.png"/>
+            </Property>
+            <Property name="selected" type="boolean" value="true"/>
+            <Property name="toolTipText" type="java.lang.String" value="Display name of sequence unter mouse" noResource="true"/>
+            <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+              <Border info="null"/>
+            </Property>
+            <Property name="doubleBuffered" type="boolean" value="true"/>
+            <Property name="focusable" type="boolean" value="false"/>
+            <Property name="horizontalTextPosition" type="int" value="0"/>
+            <Property name="iconTextGap" type="int" value="0"/>
+            <Property name="inheritsPopupMenu" type="boolean" value="true"/>
+            <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
+              <Insets value="[-3, -3, -3, 2]"/>
+            </Property>
+            <Property name="pressedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/sequence_name.png"/>
+            </Property>
+            <Property name="selectedIcon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/sequence_name.png"/>
+            </Property>
+            <Property name="verticalTextPosition" type="int" value="3"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="sequenceNameButtonActionPerformed"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/src/org/rki/sequenceeditor/view/EditorWindow.java b/src/org/rki/sequenceeditor/view/EditorWindow.java
new file mode 100644
index 0000000..c7fb1d6
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/EditorWindow.java
@@ -0,0 +1,871 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/*
+ * EditorWindow.java
+ *
+ * Created on Aug 31, 2009, 10:29:01 AM
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.net.URL;
+import javax.help.HelpSet;
+import javax.help.JHelp;
+import javax.swing.JFrame;
+import org.rki.sequenceeditor.model.Settings;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class EditorWindow extends javax.swing.JFrame {
+
+    private EditorApp _app;
+
+    /** Creates new form EditorWindow */
+    public EditorWindow() {
+        initComponents();
+    }
+
+    public void setApp(EditorApp app) {
+        _app = app;
+        initMenus();
+    }
+
+    private void initMenus() {
+        primerLengthDisplayButton.setSelected(!_app.settings.getBoolean(Settings.DISPLAY_PRIMER_LENGTH));
+        primerTemperatureDisplayButton.setSelected(!_app.settings.getBoolean(Settings.DISPLAY_PRIMER_TEMPERATURE));
+        IUBButton.setSelected(_app.settings.getBoolean(Settings.DISPLAY_IUB));
+        sequenceNameButton.setSelected(_app.settings.getBoolean(Settings.DISPLAY_SEQUENCE_NAME));
+        primerDisplayButton.setSelected(_app.settings.getBoolean(Settings.DISPLAY_PRIMER_NAME));
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        statusBar = new javax.swing.JPanel();
+        messageLabel = new javax.swing.JLabel();
+        displayPanel = new javax.swing.JPanel();
+        jSplitPane1 = new javax.swing.JSplitPane();
+        namesPane1 = new org.rki.sequenceeditor.view.NamesPane();
+        jPanel1 = new javax.swing.JPanel();
+        sequencePane1 = new org.rki.sequenceeditor.view.SequencePane();
+        horizontalScrollBar = new javax.swing.JScrollBar();
+        verticalScrollBar = new javax.swing.JScrollBar();
+        jToolBar1 = new javax.swing.JToolBar();
+        IUBButton = new javax.swing.JToggleButton();
+        primerDisplayButton = new javax.swing.JToggleButton();
+        primerTemperatureDisplayButton = new javax.swing.JToggleButton();
+        primerLengthDisplayButton = new javax.swing.JToggleButton();
+        sequenceNameButton = new javax.swing.JToggleButton();
+        jMenuBar1 = new javax.swing.JMenuBar();
+        jMenu1 = new javax.swing.JMenu();
+        menuLoadFile = new javax.swing.JMenuItem();
+        menuAppendFromFile = new javax.swing.JMenuItem();
+        menuSaveItem = new javax.swing.JMenuItem();
+        menuSaveAsItem = new javax.swing.JMenuItem();
+        recentMenu = new javax.swing.JMenu();
+        jMenu2 = new javax.swing.JMenu();
+        copyMenu = new javax.swing.JMenu();
+        sequenceCopyMenu = new javax.swing.JMenuItem();
+        sequenceWithNameCopyMenu = new javax.swing.JMenuItem();
+        masterConsensusCopyMenu = new javax.swing.JMenuItem();
+        groupConsensusCopyMenu = new javax.swing.JMenuItem();
+        settingsMenuItem = new javax.swing.JMenuItem();
+        jMenu5 = new javax.swing.JMenu();
+        colorModelMenu = new javax.swing.JMenu();
+        jMenu6 = new javax.swing.JMenu();
+        jMenuItem3 = new javax.swing.JMenuItem();
+        jMenuItem4 = new javax.swing.JMenuItem();
+        jMenuItem5 = new javax.swing.JMenuItem();
+        jMenuItem6 = new javax.swing.JMenuItem();
+        jMenuItem7 = new javax.swing.JMenuItem();
+        jMenuItem8 = new javax.swing.JMenuItem();
+        jMenuItem9 = new javax.swing.JMenuItem();
+        jMenuItem10 = new javax.swing.JMenuItem();
+        jMenu3 = new javax.swing.JMenu();
+        calcMasterConsensus = new javax.swing.JMenuItem();
+        calcGroupConsensus = new javax.swing.JMenuItem();
+        keepConsensusUpdated = new javax.swing.JCheckBoxMenuItem();
+        jSeparator1 = new javax.swing.JSeparator();
+        groupIdentical = new javax.swing.JMenuItem();
+        jMenu4 = new javax.swing.JMenu();
+        sortByName = new javax.swing.JMenuItem();
+        sortByIdentity = new javax.swing.JMenuItem();
+        sortBySelectionIdentity = new javax.swing.JMenuItem();
+        jSeparator2 = new javax.swing.JPopupMenu.Separator();
+        jMenuItem1 = new javax.swing.JMenuItem();
+        jMenuItem2 = new javax.swing.JMenuItem();
+        jMenu7 = new javax.swing.JMenu();
+        jMenuItem11 = new javax.swing.JMenuItem();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+        setTitle("mPSQed"); // NOI18N
+        setBackground(new java.awt.Color(254, 254, 254));
+        setForeground(java.awt.Color.white);
+
+        statusBar.setBorder(javax.swing.BorderFactory.createEtchedBorder());
+
+        messageLabel.setText("RKI Sequence editor loading..."); // NOI18N
+
+        javax.swing.GroupLayout statusBarLayout = new javax.swing.GroupLayout(statusBar);
+        statusBar.setLayout(statusBarLayout);
+        statusBarLayout.setHorizontalGroup(
+            statusBarLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(messageLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 943, Short.MAX_VALUE)
+        );
+        statusBarLayout.setVerticalGroup(
+            statusBarLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(messageLabel)
+        );
+
+        displayPanel.setBackground(new java.awt.Color(254, 254, 254));
+
+        namesPane1.setMinimumSize(new java.awt.Dimension(100, 0));
+
+        javax.swing.GroupLayout namesPane1Layout = new javax.swing.GroupLayout(namesPane1);
+        namesPane1.setLayout(namesPane1Layout);
+        namesPane1Layout.setHorizontalGroup(
+            namesPane1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 100, Short.MAX_VALUE)
+        );
+        namesPane1Layout.setVerticalGroup(
+            namesPane1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 535, Short.MAX_VALUE)
+        );
+
+        jSplitPane1.setLeftComponent(namesPane1);
+
+        sequencePane1.addComponentListener(new java.awt.event.ComponentAdapter() {
+            public void componentResized(java.awt.event.ComponentEvent evt) {
+                sequencePane1ComponentResized(evt);
+            }
+        });
+
+        javax.swing.GroupLayout sequencePane1Layout = new javax.swing.GroupLayout(sequencePane1);
+        sequencePane1.setLayout(sequencePane1Layout);
+        sequencePane1Layout.setHorizontalGroup(
+            sequencePane1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 827, Short.MAX_VALUE)
+        );
+        sequencePane1Layout.setVerticalGroup(
+            sequencePane1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 520, Short.MAX_VALUE)
+        );
+
+        horizontalScrollBar.setOrientation(javax.swing.JScrollBar.HORIZONTAL);
+        horizontalScrollBar.setFocusable(false);
+        horizontalScrollBar.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
+            public void adjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {
+                horizontalScrollBarAdjustmentValueChanged(evt);
+            }
+        });
+
+        verticalScrollBar.setFocusable(false);
+        verticalScrollBar.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
+            public void adjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {
+                verticalScrollBarAdjustmentValueChanged(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(sequencePane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(horizontalScrollBar, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 827, Short.MAX_VALUE))
+                .addGap(0, 0, 0)
+                .addComponent(verticalScrollBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+                .addComponent(sequencePane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addGap(0, 0, 0)
+                .addComponent(horizontalScrollBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+            .addComponent(verticalScrollBar, javax.swing.GroupLayout.DEFAULT_SIZE, 535, Short.MAX_VALUE)
+        );
+
+        jSplitPane1.setRightComponent(jPanel1);
+
+        javax.swing.GroupLayout displayPanelLayout = new javax.swing.GroupLayout(displayPanel);
+        displayPanel.setLayout(displayPanelLayout);
+        displayPanelLayout.setHorizontalGroup(
+            displayPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 947, Short.MAX_VALUE)
+        );
+        displayPanelLayout.setVerticalGroup(
+            displayPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 535, Short.MAX_VALUE)
+        );
+
+        jToolBar1.setRollover(true);
+
+        IUBButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/non-IUB.png"))); // NOI18N
+        IUBButton.setToolTipText("Use IUB for consensus sequence"); // NOI18N
+        IUBButton.setBorder(null);
+        IUBButton.setFocusable(false);
+        IUBButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        IUBButton.setMargin(new java.awt.Insets(-3, -3, -3, -3));
+        IUBButton.setSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/IUB.png"))); // NOI18N
+        IUBButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        IUBButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                IUBButtonActionPerformed(evt);
+            }
+        });
+        jToolBar1.add(IUBButton);
+
+        primerDisplayButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/primer_display.png"))); // NOI18N
+        primerDisplayButton.setToolTipText("Display primer sequence instead of name"); // NOI18N
+        primerDisplayButton.setBorder(null);
+        primerDisplayButton.setFocusable(false);
+        primerDisplayButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        primerDisplayButton.setMargin(new java.awt.Insets(-3, -3, -3, -3));
+        primerDisplayButton.setPressedIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/primer_sequence_display.png"))); // NOI18N
+        primerDisplayButton.setSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/primer_sequence_display.png"))); // NOI18N
+        primerDisplayButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        primerDisplayButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                primerDisplayButtonActionPerformed(evt);
+            }
+        });
+        jToolBar1.add(primerDisplayButton);
+
+        primerTemperatureDisplayButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/primer_temperature_display.png"))); // NOI18N
+        primerTemperatureDisplayButton.setToolTipText("Display primer melting temperature"); // NOI18N
+        primerTemperatureDisplayButton.setBorder(null);
+        primerTemperatureDisplayButton.setFocusable(false);
+        primerTemperatureDisplayButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        primerTemperatureDisplayButton.setMargin(new java.awt.Insets(-3, -3, -3, -3));
+        primerTemperatureDisplayButton.setPressedIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/primer_no_temperature_display.png"))); // NOI18N
+        primerTemperatureDisplayButton.setSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/primer_no_temperature_display.png"))); // NOI18N
+        primerTemperatureDisplayButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        primerTemperatureDisplayButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                primerTemperatureDisplayButtonActionPerformed(evt);
+            }
+        });
+        jToolBar1.add(primerTemperatureDisplayButton);
+
+        primerLengthDisplayButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/primer_length_display.png"))); // NOI18N
+        primerLengthDisplayButton.setToolTipText("Display primer length"); // NOI18N
+        primerLengthDisplayButton.setBorder(null);
+        primerLengthDisplayButton.setFocusable(false);
+        primerLengthDisplayButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        primerLengthDisplayButton.setMargin(new java.awt.Insets(-3, -3, -3, -3));
+        primerLengthDisplayButton.setPressedIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/primer_no_length_display.png"))); // NOI18N
+        primerLengthDisplayButton.setSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/primer_no_length_display.png"))); // NOI18N
+        primerLengthDisplayButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        primerLengthDisplayButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                primerLengthDisplayButtonActionPerformed(evt);
+            }
+        });
+        jToolBar1.add(primerLengthDisplayButton);
+
+        sequenceNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/no_sequence_name.png"))); // NOI18N
+        sequenceNameButton.setSelected(true);
+        sequenceNameButton.setToolTipText("Display name of sequence unter mouse"); // NOI18N
+        sequenceNameButton.setBorder(null);
+        sequenceNameButton.setDoubleBuffered(true);
+        sequenceNameButton.setFocusable(false);
+        sequenceNameButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
+        sequenceNameButton.setIconTextGap(0);
+        sequenceNameButton.setInheritsPopupMenu(true);
+        sequenceNameButton.setMargin(new java.awt.Insets(-3, -3, -3, 2));
+        sequenceNameButton.setPressedIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/sequence_name.png"))); // NOI18N
+        sequenceNameButton.setSelectedIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/sequence_name.png"))); // NOI18N
+        sequenceNameButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
+        sequenceNameButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                sequenceNameButtonActionPerformed(evt);
+            }
+        });
+        jToolBar1.add(sequenceNameButton);
+
+        jMenu1.setText("File"); // NOI18N
+
+        menuLoadFile.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
+        menuLoadFile.setText("Load file"); // NOI18N
+        menuLoadFile.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                menuLoadFileActionPerformed(evt);
+            }
+        });
+        jMenu1.add(menuLoadFile);
+
+        menuAppendFromFile.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.event.InputEvent.CTRL_MASK));
+        menuAppendFromFile.setText("Append from file"); // NOI18N
+        menuAppendFromFile.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                menuAppendFromFileActionPerformed(evt);
+            }
+        });
+        jMenu1.add(menuAppendFromFile);
+
+        menuSaveItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
+        menuSaveItem.setText("Save"); // NOI18N
+        menuSaveItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                menuSaveItemActionPerformed(evt);
+            }
+        });
+        jMenu1.add(menuSaveItem);
+
+        menuSaveAsItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
+        menuSaveAsItem.setText("Save as"); // NOI18N
+        menuSaveAsItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                menuSaveAsItemActionPerformed(evt);
+            }
+        });
+        jMenu1.add(menuSaveAsItem);
+
+        recentMenu.setText("Open recent"); // NOI18N
+        jMenu1.add(recentMenu);
+
+        jMenuBar1.add(jMenu1);
+
+        jMenu2.setText("Edit"); // NOI18N
+        jMenu2.addMenuListener(new javax.swing.event.MenuListener() {
+            public void menuCanceled(javax.swing.event.MenuEvent evt) {
+            }
+            public void menuDeselected(javax.swing.event.MenuEvent evt) {
+            }
+            public void menuSelected(javax.swing.event.MenuEvent evt) {
+                jMenu2MenuSelected(evt);
+            }
+        });
+        jMenu2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenu2ActionPerformed(evt);
+            }
+        });
+
+        copyMenu.setText("Copy"); // NOI18N
+
+        sequenceCopyMenu.setText("Sequences"); // NOI18N
+        sequenceCopyMenu.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                sequenceCopyMenuActionPerformed(evt);
+            }
+        });
+        copyMenu.add(sequenceCopyMenu);
+
+        sequenceWithNameCopyMenu.setText("Sequences with names"); // NOI18N
+        sequenceWithNameCopyMenu.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                sequenceWithNameCopyMenuActionPerformed(evt);
+            }
+        });
+        copyMenu.add(sequenceWithNameCopyMenu);
+
+        masterConsensusCopyMenu.setText("Master consensus sequence"); // NOI18N
+        masterConsensusCopyMenu.setEnabled(false);
+        masterConsensusCopyMenu.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                masterConsensusCopyMenuActionPerformed(evt);
+            }
+        });
+        copyMenu.add(masterConsensusCopyMenu);
+
+        groupConsensusCopyMenu.setText("Group consensus sequence"); // NOI18N
+        groupConsensusCopyMenu.setEnabled(false);
+        groupConsensusCopyMenu.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                groupConsensusCopyMenuActionPerformed(evt);
+            }
+        });
+        copyMenu.add(groupConsensusCopyMenu);
+
+        jMenu2.add(copyMenu);
+
+        settingsMenuItem.setText("Settings"); // NOI18N
+        settingsMenuItem.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                settingsMenuItemActionPerformed(evt);
+            }
+        });
+        jMenu2.add(settingsMenuItem);
+
+        jMenuBar1.add(jMenu2);
+
+        jMenu5.setText("View"); // NOI18N
+
+        colorModelMenu.setText("Color Model"); // NOI18N
+        jMenu5.add(colorModelMenu);
+
+        jMenu6.setText("Text size"); // NOI18N
+
+        jMenuItem3.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_1, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
+        jMenuItem3.setText("1 pt"); // NOI18N
+        jMenuItem3.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem3ActionPerformed(evt);
+            }
+        });
+        jMenu6.add(jMenuItem3);
+
+        jMenuItem4.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_2, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
+        jMenuItem4.setText("2 pt"); // NOI18N
+        jMenuItem4.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem4ActionPerformed(evt);
+            }
+        });
+        jMenu6.add(jMenuItem4);
+
+        jMenuItem5.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_3, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
+        jMenuItem5.setText("4 pt"); // NOI18N
+        jMenuItem5.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem5ActionPerformed(evt);
+            }
+        });
+        jMenu6.add(jMenuItem5);
+
+        jMenuItem6.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_4, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
+        jMenuItem6.setText("8 pt"); // NOI18N
+        jMenuItem6.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem6ActionPerformed(evt);
+            }
+        });
+        jMenu6.add(jMenuItem6);
+
+        jMenuItem7.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_5, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
+        jMenuItem7.setText("10 pt"); // NOI18N
+        jMenuItem7.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem7ActionPerformed(evt);
+            }
+        });
+        jMenu6.add(jMenuItem7);
+
+        jMenuItem8.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_6, java.awt.event.InputEvent.SHIFT_MASK | java.awt.event.InputEvent.CTRL_MASK));
+        jMenuItem8.setText("12 pt"); // NOI18N
+        jMenuItem8.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem8ActionPerformed(evt);
+            }
+        });
+        jMenu6.add(jMenuItem8);
+
+        jMenu5.add(jMenu6);
+
+        jMenuItem9.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_PLUS, java.awt.event.InputEvent.CTRL_MASK));
+        jMenuItem9.setText("Zoom in"); // NOI18N
+        jMenuItem9.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem9ActionPerformed(evt);
+            }
+        });
+        jMenu5.add(jMenuItem9);
+
+        jMenuItem10.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_MINUS, java.awt.event.InputEvent.CTRL_MASK));
+        jMenuItem10.setText("Zoom out"); // NOI18N
+        jMenuItem10.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem10ActionPerformed(evt);
+            }
+        });
+        jMenu5.add(jMenuItem10);
+
+        jMenuBar1.add(jMenu5);
+
+        jMenu3.setText("Analyze"); // NOI18N
+
+        calcMasterConsensus.setText("Calculate master consensus"); // NOI18N
+        calcMasterConsensus.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                calcMasterConsensusActionPerformed(evt);
+            }
+        });
+        jMenu3.add(calcMasterConsensus);
+
+        calcGroupConsensus.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_G, java.awt.event.InputEvent.CTRL_MASK));
+        calcGroupConsensus.setText("Calculate gruop consensus"); // NOI18N
+        calcGroupConsensus.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                calcGroupConsensusActionPerformed(evt);
+            }
+        });
+        jMenu3.add(calcGroupConsensus);
+
+        keepConsensusUpdated.setSelected(true);
+        keepConsensusUpdated.setText("Keep consensus up to date"); // NOI18N
+        jMenu3.add(keepConsensusUpdated);
+        jMenu3.add(jSeparator1);
+
+        groupIdentical.setText("Group identical sequences"); // NOI18N
+        groupIdentical.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                groupIdenticalActionPerformed(evt);
+            }
+        });
+        jMenu3.add(groupIdentical);
+
+        jMenu4.setText("Sort sequences"); // NOI18N
+
+        sortByName.setText("By name"); // NOI18N
+        sortByName.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                sortByNameActionPerformed(evt);
+            }
+        });
+        jMenu4.add(sortByName);
+
+        sortByIdentity.setText("By degree of identity"); // NOI18N
+        sortByIdentity.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                sortByIdentityActionPerformed(evt);
+            }
+        });
+        jMenu4.add(sortByIdentity);
+
+        sortBySelectionIdentity.setText("By degree of identity in selection"); // NOI18N
+        sortBySelectionIdentity.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                sortBySelectionIdentityActionPerformed(evt);
+            }
+        });
+        jMenu4.add(sortBySelectionIdentity);
+
+        jMenu3.add(jMenu4);
+        jMenu3.add(jSeparator2);
+
+        jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_I, java.awt.event.InputEvent.CTRL_MASK));
+        jMenuItem1.setText("Find all SNPs"); // NOI18N
+        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem1ActionPerformed(evt);
+            }
+        });
+        jMenu3.add(jMenuItem1);
+
+        jMenuItem2.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_R, java.awt.event.InputEvent.CTRL_MASK));
+        jMenuItem2.setText("Show predicted flowgrams"); // NOI18N
+        jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem2ActionPerformed(evt);
+            }
+        });
+        jMenu3.add(jMenuItem2);
+
+        jMenuBar1.add(jMenu3);
+
+        jMenu7.setText("Help"); // NOI18N
+
+        jMenuItem11.setText("Contents"); // NOI18N
+        jMenuItem11.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                jMenuItem11ActionPerformed(evt);
+            }
+        });
+        jMenu7.add(jMenuItem11);
+
+        jMenuBar1.add(jMenu7);
+
+        setJMenuBar(jMenuBar1);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(statusBar, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+            .addComponent(displayPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+            .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 947, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(displayPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addGap(0, 0, 0)
+                .addComponent(statusBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void menuLoadFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuLoadFileActionPerformed
+        if(_app == null)
+            return;
+        _app.loadFile(true);
+    }//GEN-LAST:event_menuLoadFileActionPerformed
+
+    private void sequencePane1ComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_sequencePane1ComponentResized
+        sequencePane1.resized();
+    }//GEN-LAST:event_sequencePane1ComponentResized
+
+    private void horizontalScrollBarAdjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {//GEN-FIRST:event_horizontalScrollBarAdjustmentValueChanged
+        if(_app == null)
+            return;
+        _app.scrollHorizontal(horizontalScrollBar.getValue());
+    }//GEN-LAST:event_horizontalScrollBarAdjustmentValueChanged
+
+    private void verticalScrollBarAdjustmentValueChanged(java.awt.event.AdjustmentEvent evt) {//GEN-FIRST:event_verticalScrollBarAdjustmentValueChanged
+        if(_app == null)
+            return;
+        _app.scrollVertical(verticalScrollBar.getValue());
+    }//GEN-LAST:event_verticalScrollBarAdjustmentValueChanged
+
+    private void calcMasterConsensusActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_calcMasterConsensusActionPerformed
+        if(_app == null)
+            return;
+        _app.getMasterConsensus();
+    }//GEN-LAST:event_calcMasterConsensusActionPerformed
+
+    private void calcGroupConsensusActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_calcGroupConsensusActionPerformed
+        if(_app == null)
+            return;
+        _app.getGroupMasterSequences();
+        _app.repaintAll();
+    }//GEN-LAST:event_calcGroupConsensusActionPerformed
+
+    private void groupIdenticalActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_groupIdenticalActionPerformed
+        if(_app == null) {
+            return;
+        }
+        _app.groupIdenticalSequences();
+    }//GEN-LAST:event_groupIdenticalActionPerformed
+
+    private void sortByNameActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sortByNameActionPerformed
+        if(_app == null) {
+            return;
+        }
+        _app.getAlignment().sortByName();
+        _app.repaintAll();
+    }//GEN-LAST:event_sortByNameActionPerformed
+
+    private void sortByIdentityActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sortByIdentityActionPerformed
+        if(_app == null) {
+            return;
+        }
+        _app.getAlignment().sortByHomology();
+        _app.repaintAll();
+    }//GEN-LAST:event_sortByIdentityActionPerformed
+
+    private void sortBySelectionIdentityActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sortBySelectionIdentityActionPerformed
+        if(_app == null) {
+            return;
+        }
+        _app.getAlignment().sortByHomology(_app.getSelFrom()[0], _app.getSelTo()[0]);
+        _app.repaintAll();
+    }//GEN-LAST:event_sortBySelectionIdentityActionPerformed
+
+    private void menuAppendFromFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuAppendFromFileActionPerformed
+        if(_app == null)
+            return;
+        _app.loadFile(false);
+    }//GEN-LAST:event_menuAppendFromFileActionPerformed
+
+    private void menuSaveItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuSaveItemActionPerformed
+        _app.saveFile();
+    }//GEN-LAST:event_menuSaveItemActionPerformed
+
+    private void IUBButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_IUBButtonActionPerformed
+        _app.settings.set(Settings.DISPLAY_IUB, IUBButton.isSelected());
+        _app.repaintAll();
+    }//GEN-LAST:event_IUBButtonActionPerformed
+
+    private void menuSaveAsItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuSaveAsItemActionPerformed
+        _app.saveFileAs();
+    }//GEN-LAST:event_menuSaveAsItemActionPerformed
+
+    private void primerDisplayButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_primerDisplayButtonActionPerformed
+        _app.settings.set(Settings.DISPLAY_PRIMER_NAME, primerDisplayButton.isSelected());
+        _app.repaintAll();
+    }//GEN-LAST:event_primerDisplayButtonActionPerformed
+
+    private void primerTemperatureDisplayButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_primerTemperatureDisplayButtonActionPerformed
+        _app.settings.set(Settings.DISPLAY_PRIMER_TEMPERATURE, !primerTemperatureDisplayButton.isSelected());
+        _app.repaintAll();
+    }//GEN-LAST:event_primerTemperatureDisplayButtonActionPerformed
+
+    private void primerLengthDisplayButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_primerLengthDisplayButtonActionPerformed
+        _app.settings.set(Settings.DISPLAY_PRIMER_LENGTH, !primerLengthDisplayButton.isSelected());
+        _app.repaintAll();
+    }//GEN-LAST:event_primerLengthDisplayButtonActionPerformed
+
+    private void sequenceCopyMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sequenceCopyMenuActionPerformed
+        _app.copySequence(false);
+    }//GEN-LAST:event_sequenceCopyMenuActionPerformed
+
+    private void sequenceWithNameCopyMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sequenceWithNameCopyMenuActionPerformed
+        _app.copySequence(true);
+    }//GEN-LAST:event_sequenceWithNameCopyMenuActionPerformed
+
+    private void masterConsensusCopyMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_masterConsensusCopyMenuActionPerformed
+        _app.copyMasterConsensusSequence();
+    }//GEN-LAST:event_masterConsensusCopyMenuActionPerformed
+
+    private void groupConsensusCopyMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_groupConsensusCopyMenuActionPerformed
+        _app.copyGroupConsensusSequence();
+    }//GEN-LAST:event_groupConsensusCopyMenuActionPerformed
+
+    private void jMenu2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenu2ActionPerformed
+        if(_app.isSequenceSelected()) {
+            sequenceCopyMenu.setEnabled(true);
+            sequenceWithNameCopyMenu.setEnabled(true);
+        }
+        else {
+            sequenceCopyMenu.setEnabled(false);
+            sequenceWithNameCopyMenu.setEnabled(false);
+        }
+        if(_app.hasMasterSequence)
+            masterConsensusCopyMenu.setEnabled(true);
+        else
+            masterConsensusCopyMenu.setEnabled(false);
+        if(_app.hasGroupMasterSequences)
+            groupConsensusCopyMenu.setEnabled(true);
+        else
+            groupConsensusCopyMenu.setEnabled(false);
+    }//GEN-LAST:event_jMenu2ActionPerformed
+
+    private void jMenu2MenuSelected(javax.swing.event.MenuEvent evt) {//GEN-FIRST:event_jMenu2MenuSelected
+        jMenu2ActionPerformed(null);
+    }//GEN-LAST:event_jMenu2MenuSelected
+
+    private void settingsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_settingsMenuItemActionPerformed
+        _app.settingsClicked();
+    }//GEN-LAST:event_settingsMenuItemActionPerformed
+
+    private void sequenceNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sequenceNameButtonActionPerformed
+        _app.settings.set(Settings.DISPLAY_SEQUENCE_NAME, sequenceNameButton.isSelected());
+        _app.repaintAll();
+    }//GEN-LAST:event_sequenceNameButtonActionPerformed
+
+    private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed
+        _app.findSNPs();
+    }//GEN-LAST:event_jMenuItem1ActionPerformed
+
+    private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed
+        _app.updateFlowgrams(true);
+    }//GEN-LAST:event_jMenuItem2ActionPerformed
+
+    private void jMenuItem9ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem9ActionPerformed
+        _app.doZoom(-1);
+    }//GEN-LAST:event_jMenuItem9ActionPerformed
+
+    private void jMenuItem10ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem10ActionPerformed
+        _app.doZoom(1);
+    }//GEN-LAST:event_jMenuItem10ActionPerformed
+
+    private void jMenuItem3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem3ActionPerformed
+        _app.setLetterWidth(1);
+    }//GEN-LAST:event_jMenuItem3ActionPerformed
+
+    private void jMenuItem4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem4ActionPerformed
+        _app.setLetterWidth(2);
+    }//GEN-LAST:event_jMenuItem4ActionPerformed
+
+    private void jMenuItem5ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem5ActionPerformed
+        _app.setLetterWidth(4);
+    }//GEN-LAST:event_jMenuItem5ActionPerformed
+
+    private void jMenuItem6ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem6ActionPerformed
+        _app.setLetterWidth(8);
+    }//GEN-LAST:event_jMenuItem6ActionPerformed
+
+    private void jMenuItem7ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem7ActionPerformed
+        _app.setLetterWidth(10);
+    }//GEN-LAST:event_jMenuItem7ActionPerformed
+
+    private void jMenuItem8ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem8ActionPerformed
+        _app.setLetterWidth(12);
+    }//GEN-LAST:event_jMenuItem8ActionPerformed
+
+    private void jMenuItem11ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem11ActionPerformed
+        JHelp helpViewer = null;
+	try {
+	      ClassLoader cl = EditorApp.class.getClassLoader();
+	      URL url = HelpSet.findHelpSet(cl, "main.hs");
+	      helpViewer = new JHelp(new HelpSet(cl, url));
+	      // Darzustellendes Kapitel festlegen, ID muss im XML existieren!
+	      helpViewer.setCurrentID("Simple.Introduction");
+	} catch (Exception e) {
+	      System.err.println("API Help Set not found");
+	}
+
+	JFrame frame = new JFrame();
+	frame.setTitle("mPSQed help");
+	frame.setSize(800,600);
+	frame.getContentPane().add(helpViewer);
+	frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
+	frame.setVisible(true);
+    }//GEN-LAST:event_jMenuItem11ActionPerformed
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JToggleButton IUBButton;
+    private javax.swing.JMenuItem calcGroupConsensus;
+    private javax.swing.JMenuItem calcMasterConsensus;
+    public javax.swing.JMenu colorModelMenu;
+    public javax.swing.JMenu copyMenu;
+    private javax.swing.JPanel displayPanel;
+    public javax.swing.JMenuItem groupConsensusCopyMenu;
+    private javax.swing.JMenuItem groupIdentical;
+    public javax.swing.JScrollBar horizontalScrollBar;
+    private javax.swing.JMenu jMenu1;
+    private javax.swing.JMenu jMenu2;
+    private javax.swing.JMenu jMenu3;
+    private javax.swing.JMenu jMenu4;
+    private javax.swing.JMenu jMenu5;
+    private javax.swing.JMenu jMenu6;
+    private javax.swing.JMenu jMenu7;
+    private javax.swing.JMenuBar jMenuBar1;
+    private javax.swing.JMenuItem jMenuItem1;
+    private javax.swing.JMenuItem jMenuItem10;
+    private javax.swing.JMenuItem jMenuItem11;
+    private javax.swing.JMenuItem jMenuItem2;
+    private javax.swing.JMenuItem jMenuItem3;
+    private javax.swing.JMenuItem jMenuItem4;
+    private javax.swing.JMenuItem jMenuItem5;
+    private javax.swing.JMenuItem jMenuItem6;
+    private javax.swing.JMenuItem jMenuItem7;
+    private javax.swing.JMenuItem jMenuItem8;
+    private javax.swing.JMenuItem jMenuItem9;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JSeparator jSeparator1;
+    private javax.swing.JPopupMenu.Separator jSeparator2;
+    private javax.swing.JSplitPane jSplitPane1;
+    private javax.swing.JToolBar jToolBar1;
+    public javax.swing.JCheckBoxMenuItem keepConsensusUpdated;
+    public javax.swing.JMenuItem masterConsensusCopyMenu;
+    private javax.swing.JMenuItem menuAppendFromFile;
+    private javax.swing.JMenuItem menuLoadFile;
+    private javax.swing.JMenuItem menuSaveAsItem;
+    private javax.swing.JMenuItem menuSaveItem;
+    public javax.swing.JLabel messageLabel;
+    public org.rki.sequenceeditor.view.NamesPane namesPane1;
+    private javax.swing.JToggleButton primerDisplayButton;
+    private javax.swing.JToggleButton primerLengthDisplayButton;
+    private javax.swing.JToggleButton primerTemperatureDisplayButton;
+    public javax.swing.JMenu recentMenu;
+    public javax.swing.JMenuItem sequenceCopyMenu;
+    private javax.swing.JToggleButton sequenceNameButton;
+    public org.rki.sequenceeditor.view.SequencePane sequencePane1;
+    public javax.swing.JMenuItem sequenceWithNameCopyMenu;
+    private javax.swing.JMenuItem settingsMenuItem;
+    private javax.swing.JMenuItem sortByIdentity;
+    private javax.swing.JMenuItem sortByName;
+    private javax.swing.JMenuItem sortBySelectionIdentity;
+    private javax.swing.JPanel statusBar;
+    public javax.swing.JScrollBar verticalScrollBar;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/src/org/rki/sequenceeditor/view/FindDialog.java b/src/org/rki/sequenceeditor/view/FindDialog.java
new file mode 100644
index 0000000..9e76a64
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/FindDialog.java
@@ -0,0 +1,99 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.BorderLayout;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import org.rki.sequenceeditor.model.Sequence;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class FindDialog extends JDialog implements ActionListener {
+    private JLabel _titleText = new JLabel("Please enter sequence");
+    private JTextField _seq = new JTextField();
+    private JButton _ok = new JButton("OK");
+    private JButton _cancel = new JButton("Cancel");
+    private JButton _revert = new JButton("Reverse complement");
+    private JCheckBox _allowGaps = new JCheckBox("Allow gaps");
+    private boolean _accepted = false;
+    
+    public FindDialog(Frame parent) {
+        super(parent, true);
+        init();
+        pack();
+    }
+
+    public void setText(String text) {
+        _seq.setText(text);
+    }
+
+    public void allowGaps(boolean allow) {
+        _allowGaps.setSelected(allow);
+    }
+
+    public void reset() {
+        _seq.setText("");
+        _accepted = false;
+    }
+    
+    private void init() {
+        BorderLayout layout = new BorderLayout();
+        getContentPane().setLayout(layout);
+        getContentPane().add(_titleText, BorderLayout.NORTH);
+        getContentPane().add(_seq, BorderLayout.CENTER);
+        JPanel buttonPanel = new JPanel();
+        buttonPanel.add(_allowGaps);
+        buttonPanel.add(_ok);
+        buttonPanel.add(_cancel);
+        buttonPanel.add(_revert);
+        _ok.addActionListener(this);
+        _cancel.addActionListener(this);
+        _revert.addActionListener(this);
+        getContentPane().add(buttonPanel, BorderLayout.SOUTH);
+    }
+    
+    public boolean isAccepted() {
+        return(_accepted);
+    }
+    
+    public String getSeq() {
+        return(_seq.getText());
+    }
+
+    public boolean allowGaps() {
+        return _allowGaps.isSelected();
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        if(e.getSource() == _ok) {
+            _accepted = true;
+            hideSelf();
+        }
+        else if(e.getSource() == _cancel) {
+            _accepted = false;
+            hideSelf();
+        }
+        else if(e.getSource() == _revert) {
+            String seq = Sequence.cleanUpSequence(_seq.getText());
+            seq = Sequence.invert(seq);
+            _seq.setText(seq);
+        }
+    }
+    
+    private void hideSelf() {
+        this.setVisible(false);
+    }
+}
diff --git a/src/org/rki/sequenceeditor/view/FlowFrame.form b/src/org/rki/sequenceeditor/view/FlowFrame.form
new file mode 100644
index 0000000..b81d751
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/FlowFrame.form
@@ -0,0 +1,146 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <Properties>
+    <Property name="title" type="java.lang.String" value="Predicted Flowgrams"/>
+    <Property name="alwaysOnTop" type="boolean" value="true"/>
+    <Property name="focusable" type="boolean" value="false"/>
+    <Property name="focusableWindowState" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="focusGained" listener="java.awt.event.FocusListener" parameters="java.awt.event.FocusEvent" handler="formFocusGained"/>
+  </Events>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Component id="jPanel1" alignment="1" max="32767" attributes="0"/>
+          <Component id="flowPanel" alignment="0" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="jPanel1" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="flowPanel" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="org.rki.sequenceeditor.view.FlowPanel" name="flowPanel">
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+      </AuxValues>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <EmptySpace min="0" pref="419" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <EmptySpace min="0" pref="258" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+    </Container>
+    <Container class="javax.swing.JPanel" name="jPanel1">
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="S_flowgramLength" min="-2" pref="37" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="L_maxFlowLength" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                  <EmptySpace pref="241" max="32767" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Component id="jLabel4" alignment="1" pref="20" max="32767" attributes="1"/>
+                      <Group type="103" alignment="0" groupAlignment="3" attributes="0">
+                          <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="S_flowgramLength" alignment="3" max="32767" attributes="1"/>
+                          <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="L_maxFlowLength" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+                  <EmptySpace min="-2" max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JLabel" name="jLabel4">
+          <Properties>
+            <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+              <Image iconType="3" name="/icons/help.png"/>
+            </Property>
+            <Property name="toolTipText" type="java.lang.String" value="<html>&#xa;The flowgram can only be calculated for regions in which<br>&#xa;each group is fully conserved. In order to increase the<br>&#xa;maximum flowgram length, split non-conserved groups<br>&#xa;accordingly.&#xa;</html>"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="L_maxFlowLength">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="na"/>
+          </Properties>
+          <AuxValues>
+            <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+          </AuxValues>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel2">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="/"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JSpinner" name="S_flowgramLength">
+          <Properties>
+            <Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
+              <SpinnerModel initial="10" minimum="0" numberType="java.lang.Integer" stepSize="1" type="number"/>
+            </Property>
+          </Properties>
+          <Events>
+            <EventHandler event="inputMethodTextChanged" listener="java.awt.event.InputMethodListener" parameters="java.awt.event.InputMethodEvent" handler="S_flowgramLengthInputMethodTextChanged"/>
+            <EventHandler event="propertyChange" listener="java.beans.PropertyChangeListener" parameters="java.beans.PropertyChangeEvent" handler="S_flowgramLengthPropertyChange"/>
+          </Events>
+          <AuxValues>
+            <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/>
+          </AuxValues>
+        </Component>
+        <Component class="javax.swing.JLabel" name="jLabel1">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Flowgram length"/>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/src/org/rki/sequenceeditor/view/FlowFrame.java b/src/org/rki/sequenceeditor/view/FlowFrame.java
new file mode 100644
index 0000000..4ff420e
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/FlowFrame.java
@@ -0,0 +1,200 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/*
+ * FlowFrame.java
+ *
+ * Created on 15.06.2010, 11:34:18
+ */
+
+package org.rki.sequenceeditor.view;
+
+import javax.swing.SpinnerNumberModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class FlowFrame extends javax.swing.JFrame implements ChangeListener {
+
+    private SequencePane _parent = null;
+    private int maxLength = 10;
+
+    /** Creates new form FlowFrame */
+    public FlowFrame() {
+        initComponents();
+        S_flowgramLength.getModel().addChangeListener(this);
+    }
+
+    public void setParent(SequencePane parent) {
+        _parent = parent;
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        flowPanel = new org.rki.sequenceeditor.view.FlowPanel();
+        jPanel1 = new javax.swing.JPanel();
+        jLabel4 = new javax.swing.JLabel();
+        L_maxFlowLength = new javax.swing.JLabel();
+        jLabel2 = new javax.swing.JLabel();
+        S_flowgramLength = new javax.swing.JSpinner();
+        jLabel1 = new javax.swing.JLabel();
+
+        setTitle("Predicted Flowgrams");
+        setAlwaysOnTop(true);
+        setFocusable(false);
+        setFocusableWindowState(false);
+        addFocusListener(new java.awt.event.FocusAdapter() {
+            public void focusGained(java.awt.event.FocusEvent evt) {
+                formFocusGained(evt);
+            }
+        });
+
+        javax.swing.GroupLayout flowPanelLayout = new javax.swing.GroupLayout(flowPanel);
+        flowPanel.setLayout(flowPanelLayout);
+        flowPanelLayout.setHorizontalGroup(
+            flowPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 419, Short.MAX_VALUE)
+        );
+        flowPanelLayout.setVerticalGroup(
+            flowPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 258, Short.MAX_VALUE)
+        );
+
+        jLabel4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/help.png"))); // NOI18N
+        jLabel4.setToolTipText("<html>\nThe flowgram can only be calculated for regions in which<br>\neach group is fully conserved. In order to increase the<br>\nmaximum flowgram length, split non-conserved groups<br>\naccordingly.\n</html>");
+
+        L_maxFlowLength.setText("na");
+
+        jLabel2.setText("/");
+
+        S_flowgramLength.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(10), Integer.valueOf(0), null, Integer.valueOf(1)));
+        S_flowgramLength.addInputMethodListener(new java.awt.event.InputMethodListener() {
+            public void caretPositionChanged(java.awt.event.InputMethodEvent evt) {
+            }
+            public void inputMethodTextChanged(java.awt.event.InputMethodEvent evt) {
+                S_flowgramLengthInputMethodTextChanged(evt);
+            }
+        });
+        S_flowgramLength.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
+            public void propertyChange(java.beans.PropertyChangeEvent evt) {
+                S_flowgramLengthPropertyChange(evt);
+            }
+        });
+
+        jLabel1.setText("Flowgram length");
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(jLabel1)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(S_flowgramLength, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jLabel2)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(L_maxFlowLength)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jLabel4)
+                .addContainerGap(241, Short.MAX_VALUE))
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(jLabel4, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 20, Short.MAX_VALUE)
+                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(jLabel1)
+                        .addComponent(S_flowgramLength)
+                        .addComponent(jLabel2)
+                        .addComponent(L_maxFlowLength)))
+                .addContainerGap())
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+            .addComponent(flowPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(flowPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void S_flowgramLengthPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_S_flowgramLengthPropertyChange
+        flowPanel.length = ((SpinnerNumberModel)S_flowgramLength.getModel()).getNumber().intValue();
+        if(flowPanel.length > maxLength) {
+            flowPanel.length = maxLength;
+            S_flowgramLength.setValue(maxLength);
+        }
+        flowPanel.recalc();
+        flowPanel.repaint();
+    }//GEN-LAST:event_S_flowgramLengthPropertyChange
+
+    private void S_flowgramLengthInputMethodTextChanged(java.awt.event.InputMethodEvent evt) {//GEN-FIRST:event_S_flowgramLengthInputMethodTextChanged
+
+    }//GEN-LAST:event_S_flowgramLengthInputMethodTextChanged
+
+    private void formFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_formFocusGained
+        _parent.requestFocusInWindow();
+    }//GEN-LAST:event_formFocusGained
+
+    /**
+    * @param args the command line arguments
+    */
+    public static void main(String args[]) {
+        java.awt.EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                new FlowFrame().setVisible(true);
+            }
+        });
+    }
+
+    public void setMaxLength(int ml) {
+        maxLength = ml;
+        L_maxFlowLength.setText(Integer.toString(ml));
+        if(((SpinnerNumberModel)S_flowgramLength.getModel()).getNumber().intValue() > ml) {
+            S_flowgramLength.setValue(ml);
+        }
+    }
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    public javax.swing.JLabel L_maxFlowLength;
+    public javax.swing.JSpinner S_flowgramLength;
+    public org.rki.sequenceeditor.view.FlowPanel flowPanel;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JPanel jPanel1;
+    // End of variables declaration//GEN-END:variables
+
+    @Override
+    public void stateChanged(ChangeEvent e) {
+        S_flowgramLengthPropertyChange(null);
+    }
+
+}
diff --git a/src/org/rki/sequenceeditor/view/FlowPanel.java b/src/org/rki/sequenceeditor/view/FlowPanel.java
new file mode 100644
index 0000000..f0da597
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/FlowPanel.java
@@ -0,0 +1,123 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import javax.swing.JPanel;
+import org.rki.sequenceeditor.model.Flowgram;
+import org.rki.sequenceeditor.model.MasterSequence;
+import org.rki.sequenceeditor.model.Primer;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class FlowPanel extends JPanel{
+
+    private EditorInterface _parent;
+    private Collection<Primer> _primers;
+    private LinkedList<Flowgram> _fgrams = new LinkedList<Flowgram>();
+    private HashMap<Flowgram, LinkedList<Flowgram>> _identical = new HashMap<Flowgram, LinkedList<Flowgram>>();
+    public int length;
+
+    public FlowPanel() {
+        super();
+        _parent = null;
+    }
+
+    public FlowPanel(EditorInterface parent) {
+        super();
+        _parent = parent;
+        setPreferredSize(new Dimension(600, 600));
+    }
+
+    public void setParent(EditorInterface parent) {
+        _parent = parent;
+    }
+
+    public void recalc() {
+        if(_parent == null)
+            return;
+        LinkedList<Flowgram> flows = new LinkedList<Flowgram>();
+        _identical.clear();
+        _fgrams.clear();
+        _primers = _parent.getAlignment().getPyroPrimers();
+        for(MasterSequence seq : _parent.getMasterSequences().values()) {
+            Flowgram flow = null;
+            for(Primer primer : _primers) {
+                if(flow == null) {
+                    flow = primer.getFlowgram(seq, length, seq.group.getName());
+                }
+                else {
+                    flow.add(primer.getFlowgram(seq, length, seq.group.getName()));
+                }
+            }
+            flows.add(flow);
+        }
+        for(Flowgram flow : flows) {
+            if(_identical.containsKey(flow)) {
+                LinkedList<Flowgram> idlist = _identical.get(flow);
+                idlist.add(flow);
+                _identical.put(flow, idlist);
+            }
+            else {
+                _identical.put(flow, new LinkedList<Flowgram>());
+            }
+        }
+        for(Flowgram flow : _identical.keySet()) {
+            _fgrams.add(flow);
+        }
+        Collections.sort(_fgrams);
+    }
+
+    @Override
+    public void paint(Graphics g) {
+        g.setColor(Color.WHITE);
+        g.fillRect(0, 0, getWidth(), getHeight());
+        if(_parent == null) {
+            return;
+        }
+        g.setFont(new Font("Courier", 0, 12));
+        if(_primers.isEmpty()) {
+            g.setColor(Color.BLACK);
+            g.drawString("No pyrosequencing primers.", 5, 15);
+            g.drawString("Please create at least one:", 5, 30);
+            g.drawString("- Select part of a single sequence", 15, 45);
+            g.drawString("- Right click and select 'Add Primer->Forward'", 15, 60);
+            g.drawString("- Right click the primer", 15, 75);
+            g.drawString("- Select 'is pyrosequencing primer'", 15, 90);
+            return;
+        }
+        g.setColor(Color.BLACK);
+        g.drawString(Integer.toString(_primers.size()) + " Primer" + (_primers.size()==1?"":"s"), 5, 15);
+        int pos = 1;
+        int offset = 0;
+        for(Flowgram flow : _fgrams) {
+            offset += flow.draw(g, 10, 50*pos+offset, _identical.get(flow));
+            pos ++;
+        }
+/*        int npos = 0;
+        g.setColor(Color.BLACK);
+        for(Flowgram flow : _fgrams) {
+            StringBuilder groupb = new StringBuilder();
+            groupb.append(flow.getName());
+            for(Flowgram f : _identical.get(flow)) {
+                groupb.append(", ");
+                groupb.append(f.getName());
+            }
+            g.drawString(groupb.toString(), 10, 50*pos + 10*npos);
+            npos ++;
+        }*/
+    }
+
+}
diff --git a/src/org/rki/sequenceeditor/view/FlowViewer.java b/src/org/rki/sequenceeditor/view/FlowViewer.java
new file mode 100644
index 0000000..686a49f
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/FlowViewer.java
@@ -0,0 +1,51 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class FlowViewer extends JFrame implements ChangeListener {
+    private FlowPanel _flowPanel;
+    private JSpinner _spinner = new JSpinner();
+
+    public FlowViewer(EditorInterface parent) {
+        super();
+        JPanel settings = new JPanel();
+        settings.setLayout(new GridBagLayout());
+        _spinner.setValue(20);
+        _spinner.addChangeListener(this);
+        settings.add(new JLabel("Flowgram length"));
+        settings.add(_spinner);
+        _flowPanel = new FlowPanel(parent);
+        _flowPanel.length = 20;
+        setLayout(new BorderLayout());
+        add(settings, BorderLayout.NORTH);
+        add(_flowPanel, BorderLayout.CENTER);
+        setSize(600, 600);
+        setVisible(false);
+    }
+
+    public void stateChanged(ChangeEvent e) {
+        if(e.getSource() == _spinner) {
+            _flowPanel.length = Integer.parseInt(_spinner.getValue().toString());
+            repaint();
+        }
+    }
+
+}
diff --git a/src/org/rki/sequenceeditor/view/GroupMenuItem.java b/src/org/rki/sequenceeditor/view/GroupMenuItem.java
new file mode 100644
index 0000000..7627131
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/GroupMenuItem.java
@@ -0,0 +1,27 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import javax.swing.JMenuItem;
+import org.rki.sequenceeditor.model.GroupKey;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class GroupMenuItem extends JMenuItem {
+    public GroupKey group;
+    
+    public GroupMenuItem() {
+        super();
+    }
+    
+    public GroupMenuItem(String text, GroupKey group) {
+        super(text);
+        this.group = group;
+    }
+    
+}
diff --git a/src/org/rki/sequenceeditor/view/IntDocument.java b/src/org/rki/sequenceeditor/view/IntDocument.java
new file mode 100644
index 0000000..d9b7a58
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/IntDocument.java
@@ -0,0 +1,29 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.PlainDocument;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class IntDocument extends PlainDocument {
+    @Override
+    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
+        if(str==null)
+            return;
+        StringBuilder res = new StringBuilder();
+        for(char c : str.toCharArray()) {
+            if(c >= 48 && c <= 57) {
+                res.append(c);
+            }
+        }
+        super.insertString(offs, res.toString(), a);
+    }
+}
\ No newline at end of file
diff --git a/src/org/rki/sequenceeditor/view/Main.java b/src/org/rki/sequenceeditor/view/Main.java
new file mode 100644
index 0000000..e773afa
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/Main.java
@@ -0,0 +1,30 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class Main {
+    public static void main(String[] argv) {
+        try {
+            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+        } catch (UnsupportedLookAndFeelException e) {
+            // handle exception
+        } catch (ClassNotFoundException e) {
+            // handle exception
+        } catch (InstantiationException e) {
+            // handle exception
+        } catch (IllegalAccessException e) {
+            // handle exception
+        }
+        EditorApp app = new EditorApp();
+    }
+}
diff --git a/src/org/rki/sequenceeditor/view/NamesPane.java b/src/org/rki/sequenceeditor/view/NamesPane.java
new file mode 100644
index 0000000..dc3565b
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/NamesPane.java
@@ -0,0 +1,400 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import org.rki.sequenceeditor.model.Alignment;
+import org.rki.sequenceeditor.model.GroupKey;
+import org.rki.sequenceeditor.model.MasterSequence;
+import org.rki.sequenceeditor.model.Sequence;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class NamesPane extends JPanel implements ActionListener, MouseListener {
+    private static final String INVERT = "Invert selected sequences";
+    
+    private boolean _menusInitialized = false;
+    private EditorInterface _parent;
+    private int[] _offset;
+    private int[] _menuPos = {0, 0};
+    private JPopupMenu _menu = new JPopupMenu();
+    private JMenuItem _invert;
+    private JMenuItem _setMaster;
+    private JMenuItem _getConsensus;
+    private JMenuItem _deleteSelected;
+    private JMenuItem _getGroupConsensus = new JMenuItem("Calculate group consensus sequences");
+    private JMenu _sortMenu = new JMenu("Sort sequences");
+    private JMenuItem _sortByHomology = new JMenuItem("By degree of identity");
+    private JMenuItem _sortBySelectionHomology = new JMenuItem("By degree of identity within selection");
+    private JMenuItem _sortByName = new JMenuItem("By name");
+    private JMenuItem _createGroup = new JMenuItem("Set as group");
+    private JMenuItem _collapseGroup = new JMenuItem("Collapse group");
+    private JMenu _addToGroup = new JMenu("Add sequence to group");
+    private JMenuItem _groupIdentical = new JMenuItem("Group identical sequences");
+    private ArrayList<GroupMenuItem> _groupMenuItems = new ArrayList<GroupMenuItem>();
+
+    public NamesPane() {
+        super();
+        int[] off = {0, 0};
+        init(off, null);
+    }
+    
+    public NamesPane(int[] offset, EditorInterface parent) {
+        super();
+        init(offset, parent);
+    }
+
+    private void init(int[] offset, EditorInterface parent) {
+        setParent(parent);
+        _offset = offset;
+    }
+
+    private void setupMenus() {
+        if(_menusInitialized)
+            return;
+
+        _invert = new JMenuItem(INVERT);
+        _setMaster = new JMenuItem("Set master sequence");
+        _getConsensus = new JMenuItem("Calculate master consensus sequence");
+        _deleteSelected = new JMenuItem("Delete selected sequences");
+        _invert.addActionListener(this);
+        _setMaster.addActionListener(this);
+        _getConsensus.addActionListener(this);
+        _deleteSelected.addActionListener(this);
+        _sortByName.addActionListener(this);
+        _sortByHomology.addActionListener(this);
+        _sortBySelectionHomology.addActionListener(this);
+        _createGroup.addActionListener(this);
+        _collapseGroup.addActionListener(this);
+        _getGroupConsensus.addActionListener(this);
+        _addToGroup.addActionListener(this);
+        _groupIdentical.addActionListener(this);
+        _sortMenu.add(_sortByHomology);
+        _sortMenu.add(_sortBySelectionHomology);
+        _sortMenu.add(_sortByName);
+        _menu.add(_invert);
+        _menu.add(_setMaster);
+        if(!_parent.hasMenu()) {
+            _menu.add(_getConsensus);
+            _menu.add(_getGroupConsensus);
+        }
+        _menu.add(_deleteSelected);
+        if(_parent.hasMenu()) 
+            _menu.add(_sortMenu);
+        _menu.add(_createGroup);
+        _menu.add(_addToGroup);
+        if(!_parent.hasMenu())
+            _menu.add(_groupIdentical);
+//        _menu.add(_collapseGroup);
+        updateGroupMenuItems();
+        _menusInitialized = true;
+    }
+
+    public void setParent(EditorInterface parent) {
+        _parent = parent;
+        if(_parent != null) {
+            addMouseListener(_parent);
+            addMouseMotionListener(_parent);
+            setupMenus();
+            addMouseListener(this);
+            addKeyListener(parent);
+        }
+    }
+
+    public void setOffset(int[] offset) {
+        _offset = offset;
+    }
+
+    public void updateGroupMenuItems() {
+        _addToGroup.removeAll();
+        _groupMenuItems = new ArrayList<GroupMenuItem>();
+        if(_parent == null) {
+            return;
+        }
+        for(GroupKey group : _parent.getAlignment().getGroups()) {
+            _groupMenuItems.add(new GroupMenuItem(group.getName(), group));
+        }
+        for(GroupMenuItem item : _groupMenuItems) {
+            _addToGroup.add(item);
+            item.addActionListener(this);
+        }
+    }
+    
+    private void drawCollapser(Graphics g, int pos, int lh, boolean collapsed, int cheight) {
+        g.setColor(Color.BLACK);
+        int yoff = (lh/cheight)/2;
+        g.drawLine(1, pos-yoff, 9, pos-yoff);
+        g.drawLine(1, pos-yoff, 1, pos-cheight+yoff);
+        g.drawLine(1, pos-cheight-yoff, 9, pos-cheight-yoff);
+        g.drawLine(9, pos-yoff, 9, pos-cheight+yoff);
+        g.drawLine(3, pos-cheight/2-yoff, 7, pos-cheight/2+yoff);
+        if(collapsed) {
+            g.drawLine(5, pos-2-yoff, 5, pos-cheight+2+yoff);
+        }
+        g.setColor(Color.GRAY);
+        g.drawLine(7, pos-yoff, 7, pos);
+        g.setColor(Color.BLACK);
+    }
+    
+    private void drawCollapser(Graphics g, int pos, int lh, boolean collapsed) {
+        if(lh < 8) {
+            drawCollapser(g, pos, lh, collapsed, lh);
+        }
+        else {
+            drawCollapser(g, pos, lh, collapsed, 8);
+        }    
+    }
+    
+    private void drawGroupLine(Graphics g, int pos, int lh, int linelength, boolean last) {
+        g.setColor(Color.GRAY);
+        if(last) {
+            g.drawLine(5, pos-lh+linelength, 5, pos-lh);
+        }
+        else {
+            g.drawLine(5, pos-lh/2, 5, pos-lh);
+        }
+        g.drawLine(5, pos-lh/2, 9, pos-lh/2);
+        g.setColor(Color.BLACK);
+    }
+    
+    @Override
+    public void paint(Graphics g) {
+        g.setColor(Color.WHITE);
+        g.fillRect(0, 0, getWidth(), getHeight());
+        g.setColor(Color.BLACK);
+        if(_parent == null) {
+            return;
+        }
+        int lh = _parent.getLetterHeight();
+        g.setFont(new Font("Arial", Font.PLAIN, lh));
+        Alignment align = _parent.getAlignment();
+        GroupKey lastGroup = new GroupKey("__NONAME__");
+        if(align.getSequence(_offset[1]-1) != null) {
+            lastGroup = align.getSequence(_offset[1]-1).group;
+        }
+        for (int i = _offset[1]; i < align.countAll(); i++) {
+            Sequence ls = align.getSequence(i-1);
+            Sequence s = align.getSequence(i);
+            Sequence ns = align.getSequence(i+1);
+            //                ypos += s.above.levels.size() * _parent.annotationHeight;
+            if(ls != null && ls.group == s.group && s.collapsed) {
+                continue;
+            }
+            int pos0 = _parent.getScreenY(i);//(i-_offset[1])*lw+_parent.rulerHeight;
+            int pos1 = _parent.getScreenY(i+1);//(i-_offset[1]+1)*lw+_parent.rulerHeight;
+            if(pos0 > getHeight()) {
+                break;
+            }
+            if(ls != null && s.group == ls.group && s.collapsed) {
+                continue;
+            }
+            if(ls == null || ls.group != s.group) {
+                if(_parent.getMasterSequences().get(s.group) != null) {
+                    int num = _parent.getAlignment().count(s.group);
+                    g.drawString(s.group.getName() + " consensus " + "(" + num + " sequences)", 2, pos0-_parent.getConsOffset());
+                }
+            }
+            if(s.selected) {
+                g.setColor(new Color(0xef, 0xef, 0xff));
+                g.fillRect(-1, pos0-lh, getWidth()+2, lh);
+                g.setColor(new Color(0xdf, 0xdf, 0xff));
+                if(ns == null || !ns.selected) {
+                    g.drawLine(-1, pos0, getWidth()+2, pos0);                    
+                }
+                if(ls == null || !ls.selected) {
+                    g.drawLine(-1, pos0-lh, getWidth()+2, pos0-lh);
+                }
+                g.setColor(Color.BLACK);
+            }
+            g.drawString("(" + s.group.getName() + ")" + s.name, 12, pos0);
+            if(s.group != lastGroup) {
+                drawCollapser(g, pos0, lh, s.collapsed);
+            }
+            else {
+                if(ns == null || ns.group != s.group) {
+                    drawGroupLine(g, pos0, lh, lh, false);
+                }
+                else {
+                    drawGroupLine(g, pos0, lh, pos1-pos0, true);
+                }
+            }
+            lastGroup = s.group;
+        }
+        if(_parent.getMasterSequenceAll() != null) {
+            g.drawString(_parent.getMasterSequenceAll().name, 0, _parent.getRulerHeight() + _parent.getLetterHeight());
+        }
+    }
+
+    public void groupIdenticalSequences() {
+        LinkedList<Integer> seqs = new LinkedList<Integer>();
+        for(int i=0; i<_parent.getAlignment().countAll(); i++) {
+            seqs.add(i);
+        }
+        HashMap<Integer, LinkedList<Integer>> groups = new HashMap<Integer, LinkedList<Integer>>();
+        int lastLen = _parent.getAlignment().countAll() + 10;
+        int groupNum = 1;
+        while(lastLen != seqs.size() && seqs.size() > 1) {
+            lastLen = seqs.size();
+            LinkedList<Integer> currentGroup = new LinkedList<Integer>();
+            String currentSeq = _parent.getAlignment().getSequence(seqs.get(0)).seq;
+            Iterator<Integer> seqi = seqs.iterator();
+            seqi.next();
+            while(seqi.hasNext()) {
+                int seqnum = seqi.next();
+                String seq = _parent.getAlignment().getSequence(seqnum).seq;
+                if(seq.equals(currentSeq)) {
+                    seqi.remove();
+                    currentGroup.add(seqnum);
+                }
+            }
+            if(currentGroup.size() != 0) {
+                currentGroup.add(seqs.get(0));
+                seqs.remove(0);
+                groups.put(groupNum, currentGroup);
+                groupNum++;
+            }
+        }
+        for(Integer group : groups.keySet()) {
+            GroupKey groupKey = new GroupKey("Group " + group.toString());
+            for(Integer seq : groups.get(group)) {
+                _parent.getAlignment().getSequence(seq.intValue()).group = groupKey;
+            }
+        }
+        _parent.getAlignment().sortGroups();
+        _parent.consensusChange();
+        _parent.repaintAll();
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        if(e.getSource() == _invert) {
+            for(Sequence seq : _parent.getAlignment().getSequencesAll()) {
+                if(seq.selected) {
+                    seq.invert();
+                }
+            }
+            _parent.consensusChange();
+            _parent.repaintAll();
+        }
+        else if(e.getSource() == _groupIdentical) {
+            groupIdenticalSequences();
+        }
+        else if(e.getSource() == _createGroup) {
+            Collection<GroupKey> groups = _parent.getAlignment().getGroups();
+            String name = JOptionPane.showInputDialog(this, "Please enter group name:", "Group name",
+                    JOptionPane.PLAIN_MESSAGE);
+            if(name == null) {
+                return;
+            }
+            GroupKey group = new GroupKey(name);
+            for(Sequence seq : _parent.getAlignment().getSequencesAll()) {
+                if(seq.selected) {
+                    seq.group = group;
+                }
+            }
+            updateGroupMenuItems();
+            _parent.getAlignment().sortGroups();
+            _parent.consensusChange();
+            _parent.updateFlowgrams(false);
+            _parent.repaintAll();
+        }
+        else if(e.getSource() == _setMaster) {
+            _parent.setMasterSequenceAll(new MasterSequence(_parent.getAlignment().getSequence(_parent.getRealPos(_menuPos).y)));
+        }
+        else if(e.getSource() == _getConsensus) {
+            _parent.getMasterConsensus();
+        }
+        else if(e.getSource() == _getGroupConsensus) {
+            _parent.getGroupMasterSequences();
+            _parent.repaintAll();
+        }
+        else if(e.getSource() == _deleteSelected) {
+            LinkedList<Sequence> toDel = new LinkedList<Sequence>();
+            for(Sequence seq : _parent.getAlignment().getSequencesAll()) {
+                if(seq.selected) {
+                    toDel.add(seq);
+                }
+            }            
+            for(Sequence seq : toDel) {
+                _parent.getAlignment().getSequencesAll().remove(seq);
+            }
+            _parent.consensusChange();
+            _parent.repaintAll();
+        }
+        else if(e.getSource() == _sortByName) {
+            _parent.getAlignment().sortByName();
+            _parent.repaintAll();
+        }
+        else if(e.getSource() == _sortByHomology) {
+            _parent.getAlignment().sortByHomology();
+            _parent.repaintAll();
+        }
+        else if(e.getSource() == _sortBySelectionHomology) {
+            _parent.getAlignment().sortByHomology(_parent.getSelFrom()[0], _parent.getSelTo()[0]);
+            _parent.repaintAll();
+        }
+        else {
+            for(GroupMenuItem item : _groupMenuItems) {
+                if(e.getSource() == item) {
+                    Sequence firstSeq = _parent.getAlignment().getSequences(item.group).iterator().next();
+                    for(Sequence seq : _parent.getAlignment().getSequencesAll()) {
+                        if(seq.selected) {
+                            seq.group = item.group;
+                            seq.collapsed = firstSeq.collapsed;
+                        }
+                    }
+                    _parent.getAlignment().sortGroups();
+                    _parent.updateFlowgrams(false);
+                    _parent.repaintAll();                    
+                }
+            }
+        }
+    }
+    
+    public void showPopup(MouseEvent e) {
+        if (e.getButton() == 3) {
+            if(_parent.getAlignment().countAll() == 0)
+                return;
+            _menuPos[0] = e.getX();
+            _menuPos[1] = e.getY();
+            _menu.show(this, e.getX(), e.getY());
+        }
+    }
+    
+    public void mouseClicked(MouseEvent e) {
+    }
+
+    public void mousePressed(MouseEvent e) {
+        showPopup(e);
+    }
+
+    public void mouseReleased(MouseEvent e) {
+        showPopup(e);
+    }
+
+    public void mouseEntered(MouseEvent arg0) {
+    }
+
+    public void mouseExited(MouseEvent arg0) {
+    }
+}
diff --git a/src/org/rki/sequenceeditor/view/OptionsFrame.form b/src/org/rki/sequenceeditor/view/OptionsFrame.form
new file mode 100644
index 0000000..abfb546
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/OptionsFrame.form
@@ -0,0 +1,334 @@
+<?xml version="1.1" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <NonVisualComponents>
+    <Component class="org.rki.sequenceeditor.view.IntDocument" name="saltConcentrationDocument">
+    </Component>
+    <Component class="org.rki.sequenceeditor.view.IntDocument" name="mgConcentrationDocument">
+    </Component>
+    <Component class="org.rki.sequenceeditor.view.IntDocument" name="primerConcentrationDocument">
+    </Component>
+    <Component class="org.rki.sequenceeditor.view.IntDocument" name="deltaTmWarningTemperatureDocument">
+    </Component>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" value="Settings"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+  </AuxValues>
+
+  <Layout>
+    <DimensionLayout dim="0">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <Component id="B_cancel" min="-2" max="-2" attributes="0"/>
+              <EmptySpace pref="294" max="32767" attributes="0"/>
+              <Component id="B_accept" min="-2" max="-2" attributes="0"/>
+          </Group>
+          <Component id="jTabbedPane1" alignment="0" pref="401" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="1" attributes="0">
+              <Component id="jTabbedPane1" pref="271" max="32767" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Group type="103" groupAlignment="3" attributes="0">
+                  <Component id="B_accept" alignment="3" min="-2" max="-2" attributes="0"/>
+                  <Component id="B_cancel" alignment="3" min="-2" max="-2" attributes="0"/>
+              </Group>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JTabbedPane" name="jTabbedPane1">
+      <Properties>
+        <Property name="inheritsPopupMenu" type="boolean" value="true"/>
+      </Properties>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JPanel" name="jPanel1">
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout" value="org.netbeans.modules.form.compat2.layouts.support.JTabbedPaneSupportLayout$JTabbedPaneConstraintsDescription">
+              <JTabbedPaneConstraints tabName="Primers">
+                <Property name="tabTitle" type="java.lang.String" value="Primers"/>
+              </JTabbedPaneConstraints>
+            </Constraint>
+          </Constraints>
+
+          <Layout>
+            <DimensionLayout dim="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="1" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="jLabel4" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="jLabel1" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="jLabel6" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="jLabel5" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace max="-2" attributes="0"/>
+                              <Component id="jLabel3" min="-2" pref="226" max="-2" attributes="0"/>
+                          </Group>
+                          <Group type="102" alignment="0" attributes="0">
+                              <Component id="jLabel8" min="-2" max="-2" attributes="0"/>
+                              <EmptySpace min="-2" max="-2" attributes="0"/>
+                              <Group type="103" groupAlignment="0" attributes="0">
+                                  <Component id="jLabel7" alignment="0" min="-2" max="-2" attributes="0"/>
+                                  <Group type="102" alignment="0" attributes="0">
+                                      <Group type="103" groupAlignment="1" attributes="0">
+                                          <Component id="jLabel11" min="-2" pref="16" max="-2" attributes="0"/>
+                                          <Component id="i_deltaTmWarning" alignment="1" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                      <EmptySpace min="-2" max="-2" attributes="0"/>
+                                      <Group type="103" groupAlignment="0" attributes="0">
+                                          <Component id="jLabel12" min="-2" max="-2" attributes="0"/>
+                                          <Component id="l_deltaTmWarning" alignment="0" min="-2" max="-2" attributes="0"/>
+                                      </Group>
+                                  </Group>
+                              </Group>
+                          </Group>
+                      </Group>
+                      <EmptySpace pref="18" max="32767" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="TF_mgConcentration" pref="107" max="32767" attributes="0"/>
+                          <Component id="TF_saltConcentration" alignment="0" pref="107" max="32767" attributes="0"/>
+                          <Component id="TF_primerConcentration" alignment="0" pref="107" max="32767" attributes="0"/>
+                          <Component id="CB_showDTMWarning" alignment="0" min="-2" max="-2" attributes="0"/>
+                          <Component id="TF_DTMWarningTemp" alignment="1" pref="107" max="32767" attributes="0"/>
+                          <Component id="B_DTMWarningColor" min="-2" pref="23" max="-2" attributes="0"/>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+            <DimensionLayout dim="1">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Group type="102" alignment="0" attributes="0">
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                          <Component id="jLabel4" max="32767" attributes="1"/>
+                          <Group type="103" alignment="0" groupAlignment="3" attributes="0">
+                              <Component id="TF_saltConcentration" alignment="0" max="32767" attributes="1"/>
+                              <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                          <Component id="jLabel6" max="32767" attributes="1"/>
+                          <Group type="103" alignment="0" groupAlignment="3" attributes="0">
+                              <Component id="TF_mgConcentration" alignment="0" max="32767" attributes="1"/>
+                              <Component id="jLabel2" alignment="3" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                          <Component id="jLabel5" max="32767" attributes="1"/>
+                          <Group type="103" alignment="0" groupAlignment="3" attributes="0">
+                              <Component id="TF_primerConcentration" alignment="0" max="32767" attributes="1"/>
+                              <Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="CB_showDTMWarning" min="-2" max="-2" attributes="0"/>
+                          <Group type="103" alignment="0" groupAlignment="1" attributes="0">
+                              <Component id="jLabel8" alignment="1" min="-2" max="-2" attributes="0"/>
+                              <Component id="jLabel7" alignment="1" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                      <EmptySpace min="-2" max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" max="-2" attributes="0">
+                          <Component id="i_deltaTmWarning" max="32767" attributes="1"/>
+                          <Group type="103" alignment="0" groupAlignment="3" attributes="0">
+                              <Component id="TF_DTMWarningTemp" alignment="0" max="32767" attributes="1"/>
+                              <Component id="l_deltaTmWarning" alignment="3" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                      <EmptySpace max="-2" attributes="0"/>
+                      <Group type="103" groupAlignment="0" attributes="0">
+                          <Component id="B_DTMWarningColor" max="32767" attributes="1"/>
+                          <Component id="jLabel11" pref="23" max="32767" attributes="1"/>
+                          <Component id="jLabel12" alignment="1" pref="23" max="32767" attributes="1"/>
+                      </Group>
+                      <EmptySpace min="-2" pref="65" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+            </DimensionLayout>
+          </Layout>
+          <SubComponents>
+            <Component class="javax.swing.JLabel" name="jLabel1">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Salt concentration (mM)"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel2">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Magnesium concentration (mM)"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel3">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Primer concentration (nM)"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JTextField" name="TF_saltConcentration">
+              <BindingProperties>
+                <BindingProperty name="document" source="saltConcentrationDocument" target="TF_saltConcentration" targetPath="document" updateStrategy="0" immediately="false"/>
+              </BindingProperties>
+            </Component>
+            <Component class="javax.swing.JTextField" name="TF_mgConcentration">
+              <BindingProperties>
+                <BindingProperty name="document" source="mgConcentrationDocument" target="TF_mgConcentration" targetPath="document" updateStrategy="0" immediately="false"/>
+              </BindingProperties>
+            </Component>
+            <Component class="javax.swing.JTextField" name="TF_primerConcentration">
+              <BindingProperties>
+                <BindingProperty name="document" source="primerConcentrationDocument" target="TF_primerConcentration" targetPath="document" updateStrategy="0" immediately="false"/>
+              </BindingProperties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel4">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/icons/help.png"/>
+                </Property>
+                <Property name="toolTipText" type="java.lang.String" value="<html>&#xa;Salt concentration in the PCR reaction to be assumed for the<br>&#xa;calculation of primer tm&#xa;</html>"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel5">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/icons/help.png"/>
+                </Property>
+                <Property name="toolTipText" type="java.lang.String" value="<html>&#xa;Primer concentration in the PCR reaction to be assumed for the<br>&#xa;calculation of primer tm&#xa;</html>"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel6">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/icons/help.png"/>
+                </Property>
+                <Property name="toolTipText" type="java.lang.String" value="<html>&#xa;Magnesium concentration in the PCR reaction to be assumed for the<br>&#xa;calculation of primer tm&#xa;</html>"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel7">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Show delta tm warning"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel8">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/icons/help.png"/>
+                </Property>
+                <Property name="toolTipText" type="java.lang.String" value="<html>&#xa;Change the color of two primer's product if the tm difference of<br>&#xa;these primers is too high&#xa;</html>"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JCheckBox" name="CB_showDTMWarning">
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="CB_showDTMWarningActionPerformed"/>
+              </Events>
+            </Component>
+            <Component class="javax.swing.JLabel" name="l_deltaTmWarning">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Delta tm for warning"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="i_deltaTmWarning">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/icons/help.png"/>
+                </Property>
+                <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor">
+                  <ComponentRef name="l_deltaTmWarning"/>
+                </Property>
+                <Property name="toolTipText" type="java.lang.String" value="<html>&#xa;Difference in the tm of two primers at which the display of their product's<br>&#xa;color is to be changed&#xa;</html>"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JTextField" name="TF_DTMWarningTemp">
+              <BindingProperties>
+                <BindingProperty name="document" source="deltaTmWarningTemperatureDocument" target="TF_DTMWarningTemp" targetPath="document" updateStrategy="0" immediately="false"/>
+              </BindingProperties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel11">
+              <Properties>
+                <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
+                  <Image iconType="3" name="/icons/help.png"/>
+                </Property>
+                <Property name="toolTipText" type="java.lang.String" value="<html>&#xa;Color to which the display of two primer's product will be changed when<br>&#xa;the difference between the melting temperatures is too high&#xa;</html>"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JLabel" name="jLabel12">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Color for warning"/>
+              </Properties>
+            </Component>
+            <Component class="javax.swing.JButton" name="B_DTMWarningColor">
+              <Properties>
+                <Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
+                  <Color blue="66" green="f2" red="66" type="rgb"/>
+                </Property>
+                <Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
+                  <Color blue="b" green="b" red="d3" type="rgb"/>
+                </Property>
+                <Property name="borderPainted" type="boolean" value="false"/>
+                <Property name="focusPainted" type="boolean" value="false"/>
+                <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[23, 23]"/>
+                </Property>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[23, 23]"/>
+                </Property>
+                <Property name="opaque" type="boolean" value="true"/>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[23, 23]"/>
+                </Property>
+              </Properties>
+              <Events>
+                <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="B_DTMWarningColorActionPerformed"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+    <Component class="javax.swing.JButton" name="B_accept">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Accept"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="B_acceptActionPerformed"/>
+      </Events>
+    </Component>
+    <Component class="javax.swing.JButton" name="B_cancel">
+      <Properties>
+        <Property name="text" type="java.lang.String" value="Cancel"/>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="B_cancelActionPerformed"/>
+      </Events>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/src/org/rki/sequenceeditor/view/OptionsFrame.java b/src/org/rki/sequenceeditor/view/OptionsFrame.java
new file mode 100644
index 0000000..1a521f3
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/OptionsFrame.java
@@ -0,0 +1,349 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+/*
+ * OptionsFrame.java
+ *
+ * Created on May 25, 2010, 4:47:44 PM
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.Color;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.JColorChooser;
+import javax.swing.JDialog;
+import org.rki.sequenceeditor.model.Settings;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class OptionsFrame extends javax.swing.JFrame {
+
+    private Settings _settings = null;
+    private EditorApp _app = null;
+    private JColorChooser _chooser = new JColorChooser();
+    
+    /** Creates new form OptionsFrame */
+    public OptionsFrame(EditorApp app) {
+        _app = app;
+        _settings = _app.settings;
+        initComponents();
+        initValues();
+    }
+
+    private void initValues() {
+        TF_mgConcentration.setText(_settings.get(Settings.MG_CONCENTRATION));
+        TF_saltConcentration.setText(_settings.get(Settings.SALT_CONCENTRATION));
+        TF_primerConcentration.setText(_settings.get(Settings.PRIMER_CONCENTRATION));
+        CB_showDTMWarning.setSelected(_settings.getBoolean(Settings.SHOW_DTM_WARNING));
+        TF_DTMWarningTemp.setText(_settings.get(Settings.DTM_WARNING_TEMP));
+        B_DTMWarningColor.setBackground(Color.decode(_settings.get(Settings.DTM_WARNING_COLOR)));
+        setDTMEnabled();
+    }
+
+    private void setDTMEnabled() {
+        TF_DTMWarningTemp.setEnabled(CB_showDTMWarning.isSelected());
+        B_DTMWarningColor.setEnabled(CB_showDTMWarning.isSelected());
+    }
+
+    private void setValues() {
+        _settings.set(Settings.MG_CONCENTRATION, Integer.parseInt(TF_mgConcentration.getText()));
+        _settings.set(Settings.SALT_CONCENTRATION, Integer.parseInt(TF_saltConcentration.getText()));
+        _settings.set(Settings.PRIMER_CONCENTRATION, Integer.parseInt(TF_primerConcentration.getText()));
+        _settings.set(Settings.SHOW_DTM_WARNING, CB_showDTMWarning.isSelected());
+        _settings.set(Settings.DTM_WARNING_TEMP, Integer.parseInt(TF_DTMWarningTemp.getText()));
+        _settings.set(Settings.DTM_WARNING_COLOR, "0x" + Integer.toHexString(B_DTMWarningColor.getBackground().getRGB()).substring(2));
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();
+
+        saltConcentrationDocument = new org.rki.sequenceeditor.view.IntDocument();
+        mgConcentrationDocument = new org.rki.sequenceeditor.view.IntDocument();
+        primerConcentrationDocument = new org.rki.sequenceeditor.view.IntDocument();
+        deltaTmWarningTemperatureDocument = new org.rki.sequenceeditor.view.IntDocument();
+        jTabbedPane1 = new javax.swing.JTabbedPane();
+        jPanel1 = new javax.swing.JPanel();
+        jLabel1 = new javax.swing.JLabel();
+        jLabel2 = new javax.swing.JLabel();
+        jLabel3 = new javax.swing.JLabel();
+        TF_saltConcentration = new javax.swing.JTextField();
+        TF_mgConcentration = new javax.swing.JTextField();
+        TF_primerConcentration = new javax.swing.JTextField();
+        jLabel4 = new javax.swing.JLabel();
+        jLabel5 = new javax.swing.JLabel();
+        jLabel6 = new javax.swing.JLabel();
+        jLabel7 = new javax.swing.JLabel();
+        jLabel8 = new javax.swing.JLabel();
+        CB_showDTMWarning = new javax.swing.JCheckBox();
+        l_deltaTmWarning = new javax.swing.JLabel();
+        i_deltaTmWarning = new javax.swing.JLabel();
+        TF_DTMWarningTemp = new javax.swing.JTextField();
+        jLabel11 = new javax.swing.JLabel();
+        jLabel12 = new javax.swing.JLabel();
+        B_DTMWarningColor = new javax.swing.JButton();
+        B_accept = new javax.swing.JButton();
+        B_cancel = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Settings");
+
+        jTabbedPane1.setInheritsPopupMenu(true);
+
+        jLabel1.setText("Salt concentration (mM)");
+
+        jLabel2.setText("Magnesium concentration (mM)");
+
+        jLabel3.setText("Primer concentration (nM)");
+
+        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, saltConcentrationDocument, org.jdesktop.beansbinding.ObjectProperty.create(), TF_saltConcentration, org.jdesktop.beansbinding.BeanProperty.create("document"));
+        bindingGroup.addBinding(binding);
+
+        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, mgConcentrationDocument, org.jdesktop.beansbinding.ObjectProperty.create(), TF_mgConcentration, org.jdesktop.beansbinding.BeanProperty.create("document"));
+        bindingGroup.addBinding(binding);
+
+        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, primerConcentrationDocument, org.jdesktop.beansbinding.ObjectProperty.create(), TF_primerConcentration, org.jdesktop.beansbinding.BeanProperty.create("document"));
+        bindingGroup.addBinding(binding);
+
+        jLabel4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/help.png"))); // NOI18N
+        jLabel4.setToolTipText("<html>\nSalt concentration in the PCR reaction to be assumed for the<br>\ncalculation of primer tm\n</html>");
+
+        jLabel5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/help.png"))); // NOI18N
+        jLabel5.setToolTipText("<html>\nPrimer concentration in the PCR reaction to be assumed for the<br>\ncalculation of primer tm\n</html>");
+
+        jLabel6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/help.png"))); // NOI18N
+        jLabel6.setToolTipText("<html>\nMagnesium concentration in the PCR reaction to be assumed for the<br>\ncalculation of primer tm\n</html>");
+
+        jLabel7.setText("Show delta tm warning");
+
+        jLabel8.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/help.png"))); // NOI18N
+        jLabel8.setToolTipText("<html>\nChange the color of two primer's product if the tm difference of<br>\nthese primers is too high\n</html>");
+
+        CB_showDTMWarning.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                CB_showDTMWarningActionPerformed(evt);
+            }
+        });
+
+        l_deltaTmWarning.setText("Delta tm for warning");
+
+        i_deltaTmWarning.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/help.png"))); // NOI18N
+        i_deltaTmWarning.setLabelFor(l_deltaTmWarning);
+        i_deltaTmWarning.setToolTipText("<html>\nDifference in the tm of two primers at which the display of their product's<br>\ncolor is to be changed\n</html>");
+
+        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, deltaTmWarningTemperatureDocument, org.jdesktop.beansbinding.ObjectProperty.create(), TF_DTMWarningTemp, org.jdesktop.beansbinding.BeanProperty.create("document"));
+        bindingGroup.addBinding(binding);
+
+        jLabel11.setIcon(new javax.swing.ImageIcon(getClass().getResource("/icons/help.png"))); // NOI18N
+        jLabel11.setToolTipText("<html>\nColor to which the display of two primer's product will be changed when<br>\nthe difference between the melting temperatures is too high\n</html>");
+
+        jLabel12.setText("Color for warning");
+
+        B_DTMWarningColor.setBackground(new java.awt.Color(102, 242, 102));
+        B_DTMWarningColor.setForeground(new java.awt.Color(211, 11, 11));
+        B_DTMWarningColor.setBorderPainted(false);
+        B_DTMWarningColor.setFocusPainted(false);
+        B_DTMWarningColor.setMaximumSize(new java.awt.Dimension(23, 23));
+        B_DTMWarningColor.setMinimumSize(new java.awt.Dimension(23, 23));
+        B_DTMWarningColor.setOpaque(true);
+        B_DTMWarningColor.setPreferredSize(new java.awt.Dimension(23, 23));
+        B_DTMWarningColor.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                B_DTMWarningColorActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+        jPanel1.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(jLabel4)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jLabel1))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(jLabel6)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jLabel2))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(jLabel5)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 226, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addGroup(jPanel1Layout.createSequentialGroup()
+                        .addComponent(jLabel8)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(jLabel7)
+                            .addGroup(jPanel1Layout.createSequentialGroup()
+                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                                    .addComponent(jLabel11, javax.swing.GroupLayout.PREFERRED_SIZE, 16, javax.swing.GroupLayout.PREFERRED_SIZE)
+                                    .addComponent(i_deltaTmWarning))
+                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                                    .addComponent(jLabel12)
+                                    .addComponent(l_deltaTmWarning))))))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 18, Short.MAX_VALUE)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(TF_mgConcentration, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
+                    .addComponent(TF_saltConcentration, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
+                    .addComponent(TF_primerConcentration, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
+                    .addComponent(CB_showDTMWarning)
+                    .addComponent(TF_DTMWarningTemp, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 107, Short.MAX_VALUE)
+                    .addComponent(B_DTMWarningColor, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addContainerGap())
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                    .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(TF_saltConcentration)
+                        .addComponent(jLabel1)))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                    .addComponent(jLabel6, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(TF_mgConcentration)
+                        .addComponent(jLabel2)))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                    .addComponent(jLabel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(TF_primerConcentration)
+                        .addComponent(jLabel3)))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(CB_showDTMWarning)
+                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                        .addComponent(jLabel8)
+                        .addComponent(jLabel7)))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                    .addComponent(i_deltaTmWarning, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(TF_DTMWarningTemp)
+                        .addComponent(l_deltaTmWarning)))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(B_DTMWarningColor, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(jLabel11, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE)
+                    .addComponent(jLabel12, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE))
+                .addGap(65, 65, 65))
+        );
+
+        jTabbedPane1.addTab("Primers", jPanel1);
+
+        B_accept.setText("Accept");
+        B_accept.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                B_acceptActionPerformed(evt);
+            }
+        });
+
+        B_cancel.setText("Cancel");
+        B_cancel.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                B_cancelActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addComponent(B_cancel)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 294, Short.MAX_VALUE)
+                .addComponent(B_accept))
+            .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 401, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(B_accept)
+                    .addComponent(B_cancel)))
+        );
+
+        bindingGroup.bind();
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void B_acceptActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_B_acceptActionPerformed
+        setValues();
+        _settings.save();
+        _app.updatePrimerTMs();
+        dispose();
+    }//GEN-LAST:event_B_acceptActionPerformed
+
+    private void B_cancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_B_cancelActionPerformed
+        dispose();
+    }//GEN-LAST:event_B_cancelActionPerformed
+
+    private void CB_showDTMWarningActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_CB_showDTMWarningActionPerformed
+        setDTMEnabled();
+    }//GEN-LAST:event_CB_showDTMWarningActionPerformed
+
+    private void B_DTMWarningColorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_B_DTMWarningColorActionPerformed
+            JDialog jc = JColorChooser.createDialog(this, "Please select color", true, _chooser,
+                new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        B_DTMWarningColor.setBackground(_chooser.getColor());
+                    }
+                }
+            , null);
+            jc.setVisible(true);
+    }//GEN-LAST:event_B_DTMWarningColorActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton B_DTMWarningColor;
+    private javax.swing.JButton B_accept;
+    private javax.swing.JButton B_cancel;
+    private javax.swing.JCheckBox CB_showDTMWarning;
+    private javax.swing.JTextField TF_DTMWarningTemp;
+    private javax.swing.JTextField TF_mgConcentration;
+    private javax.swing.JTextField TF_primerConcentration;
+    private javax.swing.JTextField TF_saltConcentration;
+    private org.rki.sequenceeditor.view.IntDocument deltaTmWarningTemperatureDocument;
+    private javax.swing.JLabel i_deltaTmWarning;
+    private javax.swing.JLabel jLabel1;
+    private javax.swing.JLabel jLabel11;
+    private javax.swing.JLabel jLabel12;
+    private javax.swing.JLabel jLabel2;
+    private javax.swing.JLabel jLabel3;
+    private javax.swing.JLabel jLabel4;
+    private javax.swing.JLabel jLabel5;
+    private javax.swing.JLabel jLabel6;
+    private javax.swing.JLabel jLabel7;
+    private javax.swing.JLabel jLabel8;
+    private javax.swing.JPanel jPanel1;
+    private javax.swing.JTabbedPane jTabbedPane1;
+    private javax.swing.JLabel l_deltaTmWarning;
+    private org.rki.sequenceeditor.view.IntDocument mgConcentrationDocument;
+    private org.rki.sequenceeditor.view.IntDocument primerConcentrationDocument;
+    private org.rki.sequenceeditor.view.IntDocument saltConcentrationDocument;
+    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/src/org/rki/sequenceeditor/view/RKIFilesDialog.java b/src/org/rki/sequenceeditor/view/RKIFilesDialog.java
new file mode 100644
index 0000000..b280a67
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/RKIFilesDialog.java
@@ -0,0 +1,135 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.Dialog;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Iterator;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JList;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.rki.sequenceeditor.model.RKIFile;
+import org.rki.sequenceeditor.model.RKIFolder;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class RKIFilesDialog extends Dialog implements ActionListener, TreeSelectionListener, ListSelectionListener {
+
+    private JTree _tree;
+    private JList _list = new JList();
+    private JButton _accept = new JButton("Accept");
+    private JButton _cancel = new JButton("Cancel");
+    private Editor _editor;
+    private DefaultListModel _lm = new DefaultListModel();
+    private JScrollPane _scroll;
+
+    public boolean accepted = false;
+
+    public RKIFilesDialog(Frame parent, String name, DefaultMutableTreeNode root, Editor editor) {
+        super(parent, name, true);
+        _tree = new JTree(root);
+        _editor = editor;
+        _tree.setPreferredSize(new Dimension(300, 500));
+        _tree.addTreeSelectionListener(this);
+        _list.setModel(_lm);
+        _scroll = new JScrollPane(_list);
+        _scroll.setPreferredSize(new Dimension(300, 500));
+        GridBagLayout gbl = new GridBagLayout();
+        setLayout(gbl);
+        GridBagConstraints gbc = new GridBagConstraints();
+        gbc.fill = GridBagConstraints.BOTH;
+        gbc.insets = new Insets(2,2,2,2);
+        gbc.gridx = 0;
+        gbc.gridy = 0;
+        gbl.setConstraints(_tree, gbc);
+        add(_tree);
+        gbc.gridx = 1;
+        gbl.setConstraints(_scroll, gbc);
+        add(_scroll);
+        gbc.fill = GridBagConstraints.VERTICAL;
+        gbc.insets = new Insets(0,0,0,0);
+        gbc.gridx = 0;
+        gbc.gridy = 1;
+        gbc.anchor = GridBagConstraints.EAST;
+        gbl.setConstraints(_cancel, gbc);
+        add(_cancel);
+        gbc.gridx = 1;
+        gbc.anchor = GridBagConstraints.WEST;
+        gbl.setConstraints(_accept, gbc);
+        add(_accept);
+        pack();
+
+        _accept.addActionListener(this);
+        _cancel.addActionListener(this);
+        _list.addListSelectionListener(this);
+        _accept.setEnabled(false);
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        if(e.getSource() == _cancel) {
+            accepted = false;
+            setVisible(false);
+        }
+        else if(e.getSource() == _accept) {
+            setVisible(false);
+            accepted = true;
+        }
+    }
+
+    public void valueChanged(TreeSelectionEvent e) {
+        DefaultMutableTreeNode node = (DefaultMutableTreeNode)_tree.getSelectionPath().getLastPathComponent();
+        RKIFolder folder = (RKIFolder)node.getUserObject();
+        try {
+            String data = _editor.readFromURL(_editor.baseUrl + "nodefiles/" + folder.id + "/");
+            JSONObject ob = new JSONObject(data);
+            ArrayList<RKIFile> files = new ArrayList<RKIFile>();
+            Iterator<String> keys = ob.keys();
+            while(keys.hasNext()) {
+                String key = keys.next();
+                if(!key.startsWith("fasta")) {
+                    continue;
+                }
+                JSONObject fileso = ob.getJSONObject(key);
+                JSONArray far = fileso.getJSONArray("files");
+                for(int i=0; i<far.length(); i++) {
+                    files.add(new RKIFile(far.getJSONObject(i).getString("name"), far.getJSONObject(i).getInt("id")));
+                }
+            }
+            _accept.setEnabled(false);
+            _lm.clear();
+            for(RKIFile file : files) {
+                _lm.addElement(file);
+            }
+            System.out.println("Bla");
+        } catch(Exception ex) {}
+    }
+
+    public void valueChanged(ListSelectionEvent e) {
+        _accept.setEnabled(true);
+    }
+
+    public RKIFile getSelectedFile() {
+        return((RKIFile)_list.getSelectedValue());
+    }
+}
diff --git a/src/org/rki/sequenceeditor/view/RecentMenuItem.java b/src/org/rki/sequenceeditor/view/RecentMenuItem.java
new file mode 100644
index 0000000..76c24ec
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/RecentMenuItem.java
@@ -0,0 +1,26 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.io.File;
+import javax.swing.JMenuItem;
+import org.rki.sequenceeditor.model.filters.LoadFilter;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class RecentMenuItem extends JMenuItem {
+
+    public String filename;
+    public LoadFilter loadFilter;
+
+    public RecentMenuItem(String fname, LoadFilter filter) {
+        super(new File(fname).getName());
+        filename = fname;
+        loadFilter = filter;
+    }
+}
diff --git a/src/org/rki/sequenceeditor/view/SequenceInfo.java b/src/org/rki/sequenceeditor/view/SequenceInfo.java
new file mode 100644
index 0000000..6a71947
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/SequenceInfo.java
@@ -0,0 +1,28 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import javax.swing.JComponent;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class SequenceInfo extends JComponent {
+    public String text = "test";
+
+    public SequenceInfo() {
+    }
+
+    @Override
+    public void paint(Graphics gr) {
+        Graphics2D g = (Graphics2D)gr;
+        gr.drawRect(0, 0, 50, 50);
+    }
+
+}
diff --git a/src/org/rki/sequenceeditor/view/SequencePane.java b/src/org/rki/sequenceeditor/view/SequencePane.java
new file mode 100644
index 0000000..41511ba
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/SequencePane.java
@@ -0,0 +1,1448 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import org.rki.sequenceeditor.model.Sequence;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Polygon;
+import java.awt.Stroke;
+import java.awt.Toolkit;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.StringSelection;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseWheelListener;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.MemoryImageSource;
+import java.io.InputStream;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.TimerTask;
+import javax.imageio.ImageIO;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JColorChooser;
+import javax.swing.JDialog;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import org.netbeans.lib.awtextra.AbsoluteConstraints;
+import org.netbeans.lib.awtextra.AbsoluteLayout;
+import org.rki.sequenceeditor.model.Alignment;
+import org.rki.sequenceeditor.model.Annotation;
+import org.rki.sequenceeditor.model.BaseColorModel;
+import org.rki.sequenceeditor.model.ColorModels;
+import org.rki.sequenceeditor.model.GroupKey;
+import org.rki.sequenceeditor.model.Letters;
+import org.rki.sequenceeditor.model.MasterSequence;
+import org.rki.sequenceeditor.model.Position;
+import org.rki.sequenceeditor.model.Primer;
+import org.rki.sequenceeditor.model.SNP;
+import org.rki.sequenceeditor.model.Settings;
+import org.rki.sequenceeditor.model.SizeMenuItem;
+import org.rki.sequenceeditor.model.TripletMenuItem;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class SequencePane extends JPanel implements MouseListener, MouseWheelListener, ActionListener, ClipboardOwner {
+
+    private BufferedImage _logoText;
+    private BufferedImage _logoRKI;
+
+    private int _width;
+    private int _height;
+    private int[] _pixels;
+    private int[] _overlayPixels;
+    private Image _disp;// = new BufferedImage(_width, _height, BufferedImage.TYPE_INT_RGB);
+    private MemoryImageSource _source;
+    private MemoryImageSource _overlay;
+    private int[] _offset;
+    private EditorInterface _parent;
+    private int _cursorX=0, _cursorY=0;
+    private JPopupMenu _menu = new JPopupMenu();
+    private JMenuItem _deleteSelected = new JMenuItem("Delete selected");
+    private JMenu _annotation = new JMenu("Add annotation");
+    private JMenuItem _annotationAbove = new JMenuItem("Above sequence");
+    private JMenuItem _annotationBelow = new JMenuItem("Below sequence");
+    private JMenu _primer = new JMenu("Add primer");
+    private JMenuItem _primerAbove = new JMenuItem("Forward");
+    private JMenuItem _primerBelow = new JMenuItem("Reverse");
+    private JMenuItem _loadFile = new JMenuItem("Load file");
+    private JMenuItem _addSequences = new JMenuItem("Append sequences from file");    
+    private JMenuItem _loadFileRKI = new JMenuItem("Load file from RKI-Tools");
+    private JMenuItem _addSequencesRKI = new JMenuItem("Append sequences from RKI-Tools");
+    private JMenuItem _saveFileRKI = new JMenuItem("Save file to RKI Tools");
+    private JMenuItem _saveFileRKIas = new JMenuItem("Save file to RKI Tools as...");
+    private JPopupMenu _annotationMenu = new JPopupMenu();
+    private JPopupMenu _primerMenu = new JPopupMenu();
+    private JMenuItem _removeAnnotation = new JMenuItem("Remove");
+    private JMenuItem _recolorAnnotation = new JMenuItem("Change color");
+    private JMenuItem _degeneratePrimer = new JMenuItem("Degenerate primer");
+    private JMenuItem _degeneratePrimerGroup = new JMenuItem("Degenerate primer for group");
+    private JMenuItem _copyPrimerSequence = new JMenuItem("Copy primer sequence");
+    private JMenuItem _copyPrimer = new JMenuItem("Copy primer");
+    private JMenuItem _copyPrimers = new JMenuItem("Copy all primers");
+    private JMenu _copyProduct = new JMenu("Copy product with...");
+    private JMenuItem _copyProductWithPrimersGaps = new JMenuItem("primers and gaps");
+    private JMenuItem _copyProductWithoutPrimersGaps = new JMenuItem("no primers and gaps");
+    private JMenuItem _copyProductWithPrimersWithoutGaps = new JMenuItem("primers and no gaps");
+    private JMenuItem _copyProductWithoutPrimersWithoutGaps = new JMenuItem("no primers and no gaps");
+    private JCheckBoxMenuItem _sequencingPrimer = new JCheckBoxMenuItem("Is pyrosequencing primer", false);
+    private JMenu _copy = new JMenu("Copy");
+    private JMenuItem _copySequences = new JMenuItem("Sequences");
+    private JMenuItem _copySequencesWithNames = new JMenuItem("Sequences with names");
+    private JMenuItem _copyMaster = new JMenuItem("Master consensus sequence");
+    private JMenuItem _copyGroup = new JMenuItem("Group consensus sequence");
+    private JMenuItem _snpToggle = new JMenuItem("Toggle SNP");
+    private boolean _redrawAll = true;
+    private boolean _redrawAllBlocked = false;
+    private AnnotationTextField _annoEdit = new AnnotationTextField();
+    private int[] _editPos = {0, 0};
+    private Position _rightClickPos;
+    private Annotation _currentAnnotation = null;
+    private JColorChooser _chooser = new JColorChooser();
+
+    private FlowFrame _flowViewer;
+
+    public String toolTipText = "Test";
+    public int seqNum = 1;
+
+    public SequencePane() {
+        super();
+        int[] off = {0, 0};
+        init(off, null);
+    }
+
+    public SequencePane(int[] offset, EditorInterface parent) {
+        super();
+        init(offset, parent);
+    }
+
+    public void setParent(EditorInterface parent) {
+        _parent = parent;
+        _flowViewer.flowPanel.setParent(parent);
+    }
+
+    public void setOffset(int[] offset) {
+        _offset = offset;
+    }
+
+    public void sequenceLoaded() {
+        _width = getWidth();
+        _height = getHeight();
+        _pixels = new int[_width * _height];
+        _overlayPixels = new int[_width * _height];
+        _source = new MemoryImageSource(_width, _height, _pixels, 0, _width);
+        _source.setAnimated(true);
+        _overlay = new MemoryImageSource(_width, _height, _overlayPixels, 0, _width);
+        _overlay.setAnimated(true);
+        _disp = Toolkit.getDefaultToolkit().createImage(_source);
+    }
+
+    public void resized() {
+        sequenceLoaded();
+        redrawAll();
+        repaint();
+    }
+
+    public void updateFlowgrams(boolean fromWindow) {
+        if(_parent == null)
+            return;
+        if(fromWindow && _flowViewer.isVisible()) {
+            _flowViewer.setVisible(false);
+            return;
+        }
+        if(!fromWindow && !_flowViewer.isVisible())
+            return;
+        _parent.findSNPs();
+        int maxlength = 1000;
+        for(Primer p : _parent.getAlignment().getPyroPrimers()) {
+            maxlength = Math.min(maxlength, p.getMaxFlowgramLength())+20;
+        }
+        _flowViewer.setMaxLength(maxlength);
+        _flowViewer.flowPanel.recalc();
+        _flowViewer.setVisible(true);
+        _flowViewer.repaint();
+        _flowViewer.flowPanel.repaint();
+    }
+
+    private void init(int[] offset, EditorInterface parent) {
+        InputStream stream = this.getClass().getResourceAsStream("/EditorName.png");
+        addMouseWheelListener(this);
+        try {
+            _logoText = ImageIO.read(stream);
+        } catch(Exception e) {
+            e.printStackTrace();
+        }
+
+        stream = this.getClass().getResourceAsStream("/RKILogo.png");
+        try {
+            _logoRKI = ImageIO.read(stream);
+        } catch(Exception e) {
+            e.printStackTrace();
+        }
+        _flowViewer = new FlowFrame();
+        _flowViewer.setParent(this);
+        _parent = parent;
+        _offset = offset;
+        _width = getWidth();
+        _height = getHeight();
+        _pixels = new int[_width * _height];
+        _overlayPixels = new int[_width * _height];
+        setLayout(new AbsoluteLayout());
+        _source = new MemoryImageSource(_width, _height, _pixels, 0, _width);
+        _source.setAnimated(true);
+        _overlay = new MemoryImageSource(_width, _height, _overlayPixels, 0, _width);
+        _overlay.setAnimated(true);
+        _disp = Toolkit.getDefaultToolkit().createImage(_source);
+        _offset = offset;
+        _parent = parent;
+//        _flowViewer = new FlowViewer(_parent);
+        setFocusable(true);
+        requestFocus();
+//        addMouseMotionListener(_parent);
+//        addMouseListener(_parent);
+//        addKeyListener(_parent);
+        JMenuItem cmmenu = new JMenu("Color model");
+        for (String name : ColorModels.models.keySet()) {
+            JMenuItem jm = new ColorModelMenuItem(name);
+            jm.addActionListener(this);
+            cmmenu.add(jm);
+        }
+        JMenuItem ptmenu = new JMenu("Text size");
+        for (int size : Letters.sizes) {
+            JMenuItem jm = new SizeMenuItem(new Integer(size).toString());
+            jm.addActionListener(this);
+            ptmenu.add(jm);
+        }
+
+
+        JMenuItem tripmenu = new JMenu("Triplet grouping");
+        JMenuItem it = new TripletMenuItem("None");
+        it.addActionListener(this);
+        tripmenu.add(it);
+
+        it = new TripletMenuItem("+0");
+        it.addActionListener(this);
+        tripmenu.add(it);
+
+        it = new TripletMenuItem("+1");
+        it.addActionListener(this);
+        tripmenu.add(it);
+
+        it = new TripletMenuItem("+2");
+        it.addActionListener(this);
+        tripmenu.add(it);
+
+
+
+        _deleteSelected.addActionListener(this);
+        _annotationAbove.addActionListener(this);
+        _annotationBelow.addActionListener(this);
+        _annotation.add(_annotationAbove);
+        _annotation.add(_annotationBelow);
+//        if(_parent != null) {// && !_parent.isApplication()) {
+            _primer.add(_primerAbove);
+            _primer.add(_primerBelow);
+            _primerAbove.addActionListener(this);
+            _primerBelow.addActionListener(this);
+//        }
+        _loadFile.addActionListener(this);
+        _addSequences.addActionListener(this);
+        _loadFileRKI.addActionListener(this);
+        _addSequencesRKI.addActionListener(this);
+        _saveFileRKI.addActionListener(this);
+        _saveFileRKIas.addActionListener(this);
+
+        _copy.add(_copySequences);
+        _copy.add(_copySequencesWithNames);
+        _copy.add(_copyMaster);
+        _copy.add(_copyGroup);
+        _copySequences.addActionListener(this);
+        _copyMaster.addActionListener(this);
+        _copyGroup.addActionListener(this);
+        _copySequencesWithNames.addActionListener(this);
+
+        _snpToggle.addActionListener(this);
+
+        if(_parent != null && !_parent.isApplication()) {
+            _menu.add(_loadFile);
+            _menu.add(_addSequences);
+            _menu.add(_loadFileRKI);
+            _menu.add(_addSequencesRKI);
+            _menu.add(_saveFileRKI);
+            _menu.add(_saveFileRKIas);
+        }
+        _menu.add(_deleteSelected);
+        _menu.add(_copy);
+        if(_parent != null && !_parent.isApplication())
+            _menu.add(cmmenu);
+        _menu.add(ptmenu);
+        if(_parent != null && !_parent.isApplication()) {
+            _menu.add(tripmenu);
+        }
+        _menu.add(_annotation);
+//        if(_parent != null) {// && !_parent.isApplication()) {
+            _menu.add(_primer);
+//        }
+        _menu.add(_snpToggle);
+        addMouseListener(this);
+        _annoEdit.addActionListener(this);
+
+        _removeAnnotation.addActionListener(this);
+        _recolorAnnotation.addActionListener(this);
+        _degeneratePrimer.addActionListener(this);
+        _degeneratePrimerGroup.addActionListener(this);
+        _copyPrimerSequence.addActionListener(this);
+        _copyPrimer.addActionListener(this);
+        _copyPrimers.addActionListener(this);
+        _sequencingPrimer.addActionListener(this);
+        _copyProductWithPrimersGaps.addActionListener(this);
+        _copyProductWithoutPrimersGaps.addActionListener(this);
+        _copyProductWithoutPrimersWithoutGaps.addActionListener(this);
+        _copyProductWithPrimersWithoutGaps.addActionListener(this);
+        _annotationMenu.add(_removeAnnotation);
+        _annotationMenu.add(_recolorAnnotation);
+        _copyProduct.add(_copyProductWithPrimersGaps);
+        _copyProduct.add(_copyProductWithPrimersWithoutGaps);
+        _copyProduct.add(_copyProductWithoutPrimersGaps);
+        _copyProduct.add(_copyProductWithoutPrimersWithoutGaps);
+        _primerMenu.add(_degeneratePrimer);
+        _primerMenu.add(_degeneratePrimerGroup);
+        _primerMenu.add(_copyPrimerSequence);
+        _primerMenu.add(_copyPrimer);
+        _primerMenu.add(_copyPrimers);
+        _primerMenu.add(_sequencingPrimer);
+        _primerMenu.add(_removeAnnotation);
+        _primerMenu.add(_recolorAnnotation);
+        _primerMenu.add(_copyProduct);
+        updateCopyMenues();
+
+//        _timer = new Timer();
+//        _timer.schedule(new RedrawTask(this), 10, 1000/25);
+    }
+
+    public void updateCopyMenues() {
+        if(_parent == null)
+            return;
+        if(_parent.getMasterSequenceAll() == null) {
+            _copyMaster.setEnabled(false);
+        }
+        else {
+            _copyMaster.setEnabled(true);
+        }
+        if(!_parent.getMasterSequences().isEmpty()) {
+            _copyGroup.setEnabled(true);
+        }
+        else {
+            _copyGroup.setEnabled(false);
+        }
+        if(_parent.isSequenceSelected()) {
+            _copySequences.setEnabled(true);
+            _copySequencesWithNames.setEnabled(true);
+        }
+        else {
+            _copySequences.setEnabled(false);
+            _copySequencesWithNames.setEnabled(false);
+        }
+    }
+    
+    private void clear(int[] data) {
+        for (int i = 0; i < data.length; i++) {
+            data[i] = 0xffffffff;
+        }
+    }
+
+    private void writeLetter(int[] data, int x, int y, int[] letter, int color, int bgcolor) {
+        double tmp_lw = (int)_parent.getLetterWidth();
+        int lw = tmp_lw==0?1:(int)tmp_lw;
+        int lh = _parent.getLetterHeight();
+        if (x + lw + (_width * (y + lw)) >= data.length || x + lw >= _width) {
+            return;
+        }
+        for (int i = 0; i < lw; i++) {
+            if (x + i >= _width) {
+                return;
+            }
+            for (int j = 0; j < lh && x + i + (_width * (y + j)) < data.length; j++) {
+                data[x + i + (_width * (y + j))] = (color * letter[i + lw * j] + bgcolor * (1 - letter[i + lw * j])) | 0xff000000;
+            }
+        }
+    }
+
+    private void updateCursor(Graphics g) {
+        double tmp_lw = (int)_parent.getLetterWidth();
+        int lw = tmp_lw==0?1:(int)tmp_lw;
+        int lh = _parent.getLetterHeight();
+        int ypos = _parent.getScreenY(_cursorY);
+        int xpos = _parent.getScreenX(_cursorX);
+        int xto = _parent.getScreenX(_cursorX + 1);
+//        int ypos = (_cursorY-_offset[1]+1)*lw+_parent.rulerHeight;
+//        int xpos = (_cursorX-_offset[0])*lw;
+//        if(_parent.getAlignment().tripletGrouping != -1) {
+//            xpos += (((_parent.getAlignment().tripletGrouping+_offset[0])%3+_cursorX)/3)*_parent.tripletDist;
+//        }
+        g.setColor(new Color(190, 190, 190));
+        g.drawLine(0, ypos, _width, ypos);
+        g.drawLine(xpos, _parent.getRulerHeight()-2, xpos, _height);
+        g.setFont(new Font("Arial", Font.PLAIN, 12));
+        String valS = new Integer(_cursorX).toString();
+        FontMetrics metrics = g.getFontMetrics(g.getFont());
+        int w = metrics.stringWidth(valS);
+        int h = metrics.getHeight();
+        g.drawString(valS, xpos-w/2, h-3);
+        if(_parent.getMode() == Editor.MODE_EDITING) {
+            g.setColor(new Color(200, 200, 255, 70));
+            g.fillRect(xpos, ypos-lh, xto-xpos, lh);
+            g.setColor(Color.BLUE);
+            g.drawRect(xpos, ypos-lh, xto-xpos, lh);
+        }
+    }
+
+    private void drawMarkerBox(Graphics g, int[] from, int[] to, Color border, Color fill, boolean canResize, boolean active) {
+        int xpos0 = _parent.getScreenX(from[0]);
+        int ypos0 = _parent.getScreenY(from[1]);
+        int xpos1 = _parent.getScreenX(to[0]);
+        int ypos1 = _parent.getScreenY(to[1]-1);
+        if(xpos0 > xpos1) {
+            int tmp = xpos0;
+            xpos0 = xpos1;
+            xpos1 = tmp;
+        }
+        if(ypos0 > ypos1) {
+            int tmp = ypos0;
+            ypos0 = ypos1;
+            ypos1 = tmp;
+        }
+        // Draw selection box around the selected sequences
+        ypos0 = Math.max(_parent.getOffsetY(), ypos0);
+        if(active) {
+            g.setColor(new Color(fill.getRed(), fill.getGreen(), fill.getBlue(), fill.getAlpha() + 50));
+        }
+        else {
+            g.setColor(fill);
+        }
+        g.fillRect(xpos0, ypos0-_parent.getLetterHeight(), xpos1-xpos0, ypos1-ypos0+_parent.getLetterHeight());
+        if(canResize && active) {
+            g.setColor(border.brighter());
+            g.drawRect(xpos0+2, ypos0-_parent.getLetterHeight()+2, xpos1-xpos0-4, ypos1-ypos0+_parent.getLetterHeight()-4);
+        }
+        g.setColor(border);
+        g.drawRect(xpos0, ypos0-_parent.getLetterHeight(), xpos1-xpos0, ypos1-ypos0+_parent.getLetterHeight());
+        // Draw selection box around master consensus sequence, if any
+        if(_parent.getMasterSequenceAll() != null) {
+            g.setColor(fill);
+            g.fillRect(xpos0, _parent.getRulerHeight()+5, xpos1-xpos0, _parent.getLetterHeight());
+            g.setColor(border);
+            g.drawRect(xpos0, _parent.getRulerHeight()+5, xpos1-xpos0, _parent.getLetterHeight());
+        }
+    }
+
+    private void updateSelection(Graphics g) {
+        if(_parent.getSelFrom()[0] == _parent.getSelTo()[0] &&
+                _parent.getSelFrom()[1] == _parent.getSelTo()[1]) {
+            return;
+        }
+        else {
+            drawMarkerBox(g, _parent.getSelFrom(), _parent.getSelTo(), Color.BLUE, new Color(200, 200, 255, 70), true, _parent.isSelectionActive());
+        }
+    }
+    
+    private void drawRuler(Graphics g) {
+        int steps = 4;
+        int bases = (int)(_width/_parent.getLetterWidth());
+        int step = (int)(bases/steps);
+        int first = 0;
+        int goffset = 0;
+        g.setColor(Color.BLACK);
+        if(_offset[0]%step == 0) {
+            first = _offset[0];
+        }
+        else {
+            first = (int)(_offset[0]/step)*step;
+            goffset = (int)((_offset[0]%step)*_parent.getLetterWidth());
+        }
+        g.drawLine(0, _parent.getRulerHeight()-1, _width, _parent.getRulerHeight()-1);
+        g.setFont(new Font("Arial", Font.PLAIN, 12));
+        for(int i=0; i<=steps; i++) {
+            int val = first + i*step;
+            String valS = new Integer(val).toString();
+            FontMetrics metrics = g.getFontMetrics(g.getFont());
+            int w = metrics.stringWidth(valS);
+            int h = metrics.getHeight();
+            int pos = (int)(_parent.getLetterWidth()*step*i - goffset + _parent.getLetterWidth()/2);
+            if(_parent.getAlignment().tripletGrouping != -1) {
+                pos += (((_parent.getAlignment().tripletGrouping+_offset[0])%3+step*i-goffset/_parent.getLetterWidth())/3)*_parent.getTripletDist();
+                if(_offset[0]%3 == _parent.getAlignment().tripletGrouping)
+                    pos += _parent.getTripletDist();
+            }
+            g.drawString(valS, pos-w/2, h-3);
+            g.drawLine(pos, _parent.getRulerHeight()-1, pos, _parent.getRulerHeight()-3);
+        }
+    }
+    
+    private void drawConservation(int tripletGrouping, int ypos) {
+        double[] conservation = _parent.getMasterSequenceAll().conservation;
+        drawConservation(tripletGrouping, ypos, conservation);
+    }
+    
+    private void drawConservation(int tripletGrouping, int ypos, double[] conservation) {
+        double lw = _parent.getLetterWidth();
+        int lh = _parent.getConsHeight();
+        int ml =(int)Math.min(conservation.length, _offset[0] + _width / lw);
+        int tripletSum = 0;
+        for (int j = _offset[0]; j < ml; j++) {
+            int ch = (int)(conservation[j]*lh);
+            if(ch == 0) 
+                ch = 1;
+            if(tripletGrouping != -1) {
+                if(j%3 == tripletGrouping) {
+                    tripletSum += _parent.getTripletDist();
+                }
+            }
+            int color = 0xff00ff00;
+            if(conservation[j] == 1)
+                color = 0xff00ff00;                
+            else if(conservation[j] > 0.3)
+                color = 0xffffac4b;
+            else
+                color = 0xffff0000;
+            int xpos = (int)(((j - _offset[0]) * lw) + tripletSum);
+            try {
+                for (int x = 0; x < lw; x++) {
+                    for (int y = 0; y < ch; y++) {
+                        _pixels[xpos + x + (_width * (ypos + lh - y))] = color;
+                    }
+                }
+            }
+            catch(ArrayIndexOutOfBoundsException e) {
+                
+            }
+        }
+    }
+
+    private int getMaximumLength(int seqlen) {
+        return (int)Math.min(seqlen, _offset[0] + _width / _parent.getLetterWidth());
+    }
+
+    private void drawSequence(int tripletGrouping, BaseColorModel cm, Sequence s, int ypos, boolean highlight) {
+        int[] colors = null;
+        double lw = _parent.getLetterWidth();
+        char[] seq = s.seq.toCharArray();
+        int ml = getMaximumLength(s.seq.length());
+        int tripletSum = 0;
+        char[] masterSeq = null;
+        if(_parent.getMasterSequenceAll() != null) {
+            if(_parent.useIUB()) {
+                masterSeq = _parent.getMasterSequenceAll().IUB.seq.toCharArray();
+            }
+            else {
+                masterSeq = _parent.getMasterSequenceAll().seq.toCharArray();
+            }
+        }
+        int lastDrawn = -1;
+        for (int j = _offset[0]; j < ml; j++) {
+            // Slower method of finding out which bases need to be drawn, but pixel perfect.
+            if(lw < 1) {
+                int npos = _parent.getScreenX(j);
+                if(npos <= lastDrawn)
+                    continue;
+                lastDrawn = npos;
+            }
+            if(tripletGrouping != -1) {
+                if(j%3 == tripletGrouping) {
+                    tripletSum += _parent.getTripletDist();
+                }
+            }
+            colors = cm.baseColor.get(seq[j]);
+            if(colors == null) {
+                colors = cm.baseColor.get('-');
+            }
+            int fgcolor = colors[0];
+            int bgcolor = colors[1];
+            // colors[2] == 0: Background color dominant in zoomed-out view
+            if(lw < 8 && colors[2] == 0) {
+                fgcolor = colors[1];
+                bgcolor = colors[0];                
+            }
+            // Get the letter of appropriate size, or for size 1 if the size is too small.
+            int[] letter = null;
+            if(lw >= 1) {
+                if(Letters.letters.containsKey(seq[j] + 100 * (int)lw)) {
+                    letter = Letters.letters.get(seq[j] + 100 * (int)lw);
+                }
+                else {
+                    letter = Letters.letters.get('?' + 100 * (int)lw);                    
+                }
+                if(highlight && _parent.getMasterSequenceAll() != null
+                        && j<_parent.getMasterSequenceAll().conservation.length) {
+                    if(colors[2] == 0) {
+                        bgcolor = masterSeq[j] == seq[j]?0xffc0c0c0:bgcolor;
+                        if(lw <= 4) {
+                            fgcolor = masterSeq[j] == seq[j]?0xffc0c0c0:fgcolor;
+                            bgcolor = 0xffffffff;
+                        }
+                    }
+                    else {
+                        fgcolor = masterSeq[j] == seq[j]?0xffc0c0c0:fgcolor;
+                    }
+                }
+//                letter = Letters.letters.get('R' + 100 * (int)lw);
+            }
+            else {
+                if(Letters.letters.containsKey(seq[j] + 100)) {
+                    letter = Letters.letters.get(seq[j] + 100);
+                }
+                else {
+                    letter = Letters.letters.get('?' + 100);                    
+                }
+                letter = Letters.letters.get(seq[j] + 100);
+                bgcolor = 0xffffffff;
+                if(_parent.getMasterSequenceAll() != null
+                        && j<_parent.getMasterSequenceAll().conservation.length)
+                    fgcolor = masterSeq[j] == seq[j]?0xffa0a0a0:0xff000000;
+                else
+                    fgcolor = 0xff000000;
+            }
+            writeLetter(_pixels, (int)((j - _offset[0]) * lw) + tripletSum, ypos-(int)_parent.getLetterHeight(), letter, fgcolor, bgcolor);
+        }
+    }
+
+    private void drawSNPmarkers(Graphics g) {
+        int ml = getMaximumLength(_parent.getAlignment().getLongestAll());
+        for(SNP s : _parent.getAlignment().snps) {
+            if(s.pos >= _offset[0] && s.pos < ml) {
+                int[] from = {s.pos, 0};
+                int[] to = {s.pos+1, _height};
+                drawMarkerBox(g, from, to, Color.RED, new Color(255, 200, 200, 70), false, true);
+            }
+        }
+    }
+
+    @Override
+    public synchronized void paint(Graphics g) {
+//		int[] data = _disp.getRGB(0, 0, _width, _height, null, 0, _width);
+        if(_parent == null) {
+            g.setColor(Color.white);
+            g.fillRect(0, 0, getWidth(), getHeight());
+            g.drawString("Please load a file", 10, 10);
+            g.drawImage(_logoText, 20, 50, Color.RED, null);
+//            BlingFilter bf = new BlingFilter(_lastFrame);
+//            g.drawImage(bf.filter(_logoRKI, null), 450, 50+_logoRKI.getHeight()+10, Color.RED, null);
+            g.drawImage(_logoRKI, 450, 50+_logoRKI.getHeight()+10, Color.RED, null);
+//            _lastFrame += 10;
+//            if(_lastFrame > _logoRKI.getWidth() + _logoRKI.getHeight() + 500) {
+//                _lastFrame = 0;
+//            }
+            return;
+        }
+        if(_redrawAll) {
+            double lw = _parent.getLetterWidth();
+            int lh = _parent.getLetterHeight();
+            Alignment align = _parent.getAlignment();
+            clear(_pixels);
+            BaseColorModel cm = ColorModels.models.get(ColorModels.currentModel);
+            int ypos = _parent.getTopOffset();
+            /**
+             * Draw the sequences
+             */
+            for (int i = _offset[1]; i < align.countAll(); i++) {
+                Sequence s = align.getSequence(i);
+                Sequence ls = align.getSequence(i-1);
+//                ypos += s.above.levels.size() * _parent.annotationHeight;
+                if(ls != null && ls.group == s.group && s.collapsed) {
+                    continue;
+                }
+                ypos = _parent.getScreenY(i);
+                if(ypos > _height) {
+                    break;
+                }
+                drawSequence(align.tripletGrouping, cm, s, ypos, true);
+                if(ls == null || ls.group != s.group) {
+                    if(_parent.getMasterSequences().get(s.group) != null) {
+                        ypos = _parent.getScreenYConsensus(i);
+                        drawSequence(align.tripletGrouping, cm, _parent.getMasterSequences().get(s.group), ypos-_parent.getConsOffset(), _redrawAll);
+                        drawConservation(ypos, ypos-_parent.getConsOffset(), _parent.getMasterSequences().get(s.group).conservation);
+                    }
+                }
+//                ypos += lh;
+//                ypos += s.below.levels.size()*_parent.annotationHeight;
+            }
+            if(_parent.getMasterSequenceAll() != null) {
+                if(_parent.useIUB()) {
+                    drawSequence(align.tripletGrouping, cm, _parent.getMasterSequenceAll().IUB, _parent.getRulerHeight()+_parent.getLetterHeight()+5, false);
+                }
+                else {
+                    drawSequence(align.tripletGrouping, cm, _parent.getMasterSequenceAll(), _parent.getRulerHeight()+_parent.getLetterHeight()+5, false);
+                }
+                drawConservation(align.tripletGrouping, _parent.getConsOffset()+5);
+            }
+            _source.newPixels();
+            _redrawAllBlocked = false;
+            _redrawAll = false;
+        }
+        g.drawImage(_disp, 0, 0, null);
+        drawAnnotations(g);
+        drawRuler(g);
+        updateCursor(g);
+        drawSNPmarkers(g);
+        updateSelection(g);
+        updateToolTip(g);
+        if(_annoEdit.isAdded) {
+            _annoEdit.paint(g.create(_editPos[0], _editPos[1], _annoEdit.getWidth(), _annoEdit.getHeight()));
+        }
+    }
+
+    private void updateToolTip(Graphics g) {
+        if(!_parent.showSequenceName())
+            return;
+        int ypos = _parent.getScreenY(seqNum);
+        FontMetrics metrics = g.getFontMetrics();
+        int hgt = metrics.getHeight();
+        int adv = metrics.stringWidth(toolTipText);
+        g.setColor(new Color(200,200,255,220));
+        g.fillRect(0, ypos, adv+6, hgt+2);
+        g.setColor(Color.GRAY);
+        g.drawRect(0, ypos, adv+6, hgt+2);
+        g.setColor(Color.BLACK);
+        g.drawString(toolTipText, 3, ypos+hgt-1);
+    }
+
+    public int[] getAnnotationXpos(Annotation anno) {
+        int[] res = {0, 0};
+        res[0] = (int)((anno.from - _offset[0])*_parent.getLetterWidth());
+        res[1] = (int)((anno.to - _offset[0])*_parent.getLetterWidth());
+        return(res);
+    }
+
+    private Polygon getAnnoBorder(int[] annoXpos, int ypos, int lwi, boolean above, boolean primer) {
+        Polygon annoBorder = new Polygon();
+        if(above) {
+            annoBorder.addPoint(annoXpos[0], ypos+_parent.getAnnotationHeight());
+            if(primer) {
+                annoBorder.addPoint(annoXpos[0], ypos);
+                annoBorder.addPoint(annoXpos[1]-lwi, ypos);
+            }
+            else {
+                annoBorder.addPoint(annoXpos[0]+lwi/2, ypos);
+                annoBorder.addPoint(annoXpos[1]-lwi/2, ypos);
+            }
+            annoBorder.addPoint(annoXpos[1], ypos+_parent.getAnnotationHeight());
+        }
+        else {
+            annoBorder.addPoint(annoXpos[1], ypos);
+            if(primer) {
+                annoBorder.addPoint(annoXpos[1], ypos+_parent.getAnnotationHeight());
+                annoBorder.addPoint(annoXpos[0]+lwi, ypos+_parent.getAnnotationHeight());
+            }
+            else {
+                annoBorder.addPoint(annoXpos[1]-lwi/2, ypos+_parent.getAnnotationHeight());
+                annoBorder.addPoint(annoXpos[0]+lwi/2, ypos+_parent.getAnnotationHeight());
+            }
+            annoBorder.addPoint(annoXpos[0], ypos);
+        }
+        return annoBorder;
+    }
+
+    private Polygon getLeftHandle(int[] annoXpos, int ypos, int lwi, boolean above, boolean primer) {
+        Polygon leftHandle = new Polygon();
+        if(above) {
+            leftHandle.addPoint(annoXpos[0], ypos+_parent.getAnnotationHeight());
+            if(primer) 
+                leftHandle.addPoint(annoXpos[0], ypos);
+            else 
+                leftHandle.addPoint(annoXpos[0]+lwi/2, ypos);
+            leftHandle.addPoint(annoXpos[0]+lwi, ypos);
+            leftHandle.addPoint(annoXpos[0]+lwi, ypos+_parent.getAnnotationHeight());
+        }
+        else {
+            leftHandle.addPoint(annoXpos[1], ypos);
+            if(primer)
+                leftHandle.addPoint(annoXpos[1], ypos+_parent.getAnnotationHeight());
+            else
+                leftHandle.addPoint(annoXpos[1]-lwi/2, ypos+_parent.getAnnotationHeight());
+            leftHandle.addPoint(annoXpos[1]-lwi, ypos+_parent.getAnnotationHeight());
+            leftHandle.addPoint(annoXpos[1]-lwi, ypos);
+        }
+        return leftHandle;
+    }
+
+    private Polygon getRightHandle(int[] annoXpos, int ypos, int lwi, boolean above, boolean primer) {
+        Polygon rightHandle = new Polygon();
+        if(above) {
+            if(primer)
+                rightHandle.addPoint(annoXpos[1]-lwi, ypos);
+            else
+                rightHandle.addPoint(annoXpos[1]-lwi/2, ypos);
+            rightHandle.addPoint(annoXpos[1], ypos+_parent.getAnnotationHeight());
+            rightHandle.addPoint(annoXpos[1]-lwi, ypos+_parent.getAnnotationHeight());
+            rightHandle.addPoint(annoXpos[1]-lwi, ypos);
+        }
+        else {
+            if(primer)
+                rightHandle.addPoint(annoXpos[0]+lwi, ypos+_parent.getAnnotationHeight());
+            else
+                rightHandle.addPoint(annoXpos[0]+lwi/2, ypos+_parent.getAnnotationHeight());
+            rightHandle.addPoint(annoXpos[0], ypos);
+            rightHandle.addPoint(annoXpos[0]+lwi, ypos);
+            rightHandle.addPoint(annoXpos[0]+lwi, ypos+_parent.getAnnotationHeight());
+        }
+        return rightHandle;
+    }
+
+    private void drawAnnotation(Graphics g, Annotation anno, int ypos, int lh, boolean above) {
+        double lw = _parent.getLetterWidth();
+        int lwi = (int)lw;
+        int[] annoXpos = getAnnotationXpos(anno);
+
+        drawBaseShape(g, anno, annoXpos, ypos, lw, lwi, above);
+        int primerTmSize = 0;
+        int primerLengthSize = 0;
+
+        if(anno == _parent.getEditedAnnotation() && !((anno instanceof Primer) && _parent.isPrimerSequenceActive())) {
+            int from = Math.max(annoXpos[0], 0);
+            int to = Math.min(annoXpos[1], _width);
+            int w = to-from;
+            if(!_annoEdit.isAdded) {
+                add(_annoEdit, new AbsoluteConstraints(from, ypos));
+                _annoEdit.setBounds(from, ypos, _parent.getAnnotationHeight(), w);
+                _annoEdit.isAdded = true;
+            }
+            _editPos[0] = annoXpos[0];
+            _editPos[1] = ypos;
+            _annoEdit.setPreferredSize(new Dimension(w, _parent.getAnnotationHeight()));
+            _annoEdit.setSize(new Dimension(w, _parent.getAnnotationHeight()));
+            doLayout();
+            if(!_annoEdit.correctText) {
+                _annoEdit.setFont(new Font("Arial", Font.PLAIN, lh-3));
+                _annoEdit.setText(anno.text);
+                _annoEdit.correctText = true;
+                _annoEdit.requestFocus();
+                _annoEdit.selectAll();
+            }
+        }
+        else {
+            if(lw > 2) {
+                g.setColor(Color.BLACK);
+                g.setFont(new Font("Arial", Font.PLAIN, _parent.getLetterHeight()));
+                FontMetrics metrics = g.getFontMetrics(g.getFont());
+                int w = metrics.stringWidth(anno.text);
+                int h = metrics.getHeight();
+                int dh = (_parent.getAnnotationHeight() - h)/2;
+                if(!(anno instanceof Primer) || !_parent.isPrimerSequenceActive()) {
+                    drawAnnotationName(g, anno, above, annoXpos, lw, w, ypos, lh, dh);
+                }
+                else {
+                    Primer primer = (Primer)anno;
+                    int move=above?0:2;
+                    for(int i=0; i<primer.getSequence().length(); i++) {
+                        g.drawString(primer.getSequence().substring(i, i+1), (primer.from-_offset[0]+i)*lwi, ypos+lh+dh+move);
+                    }
+                }
+                if(anno instanceof Primer) {
+                    Primer primer = (Primer)anno;
+                    drawPrimerScores(g, primer, above, annoXpos, lwi, ypos);
+                    if(anno == _parent.getEditedAnnotation()) {
+                        g.setColor(Color.BLUE);
+                        int dy = above?1:3;
+                        g.drawRect(annoXpos[0]+_parent.getPrimerEditPos()*lwi-2, ypos+dy, lwi, lh);
+                    }
+                    if(lw >= 4 && _parent.isPrimerTmEnabled() && primer.getTm() > 0) {
+                        primerTmSize = drawPrimerTm(g, primer, above, annoXpos, lwi, ypos);
+                    }
+                    if(lw >= 4 && _parent.isPrimerLengthEnabled()) {
+                        primerLengthSize = drawPrimerLength(g, primer, above, annoXpos, lwi, ypos);
+                    }
+                }
+            }
+            if(anno instanceof Primer)
+                drawPrimerProduct(g, (Primer)anno, above, annoXpos, ypos, lw, primerTmSize, primerLengthSize);
+        }
+    }
+
+    private void drawBaseShape(Graphics g, Annotation anno, int[] annoXpos, int ypos, double lw, int lwi, boolean above) {
+        boolean isPrimer = anno instanceof Primer;
+        Color c = anno.background;
+        Polygon annoBorder = getAnnoBorder(annoXpos, ypos, lwi, above, isPrimer);
+        Polygon leftHandle = getLeftHandle(annoXpos, ypos, lwi, above, isPrimer);
+        Polygon rightHandle = getRightHandle(annoXpos, ypos, lwi, above, isPrimer);
+
+        g.setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), 100));
+        g.fillPolygon(annoBorder);
+        g.setColor(c);
+        g.drawPolyline(annoBorder.xpoints, annoBorder.ypoints, annoBorder.npoints);
+        g.setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), 40));
+        if(lw > 1) {
+            g.fillPolygon(leftHandle);
+            g.fillPolygon(rightHandle);
+        }
+    }
+
+    private void drawAnnotationName(Graphics g, Annotation anno, boolean above, int[] annoXpos, double lw, int w, int ypos, int lh, int dh) {
+        int dpos = (int)(((anno.to-anno.from)*lw-w)/2);
+        int textx = (int)((anno.from-_offset[0])*lw+dpos);
+        if(textx+w > _width) {
+            textx = Math.max(annoXpos[0]+1, _width-w);
+        }
+        else if(textx < 0) {
+            textx = Math.min(annoXpos[1]-1-w, 0);
+        }
+        int move=above?0:2;
+        g.drawString(anno.text, textx, ypos+lh+dh+move);
+    }
+
+    private void drawPrimerProduct(Graphics g, Primer primer, boolean above, int[] annoXpos, int ypos, double lw, int primerTmSize, int primerLengthSize) {
+        if(primer.opposite == null) {
+            return;
+        }
+        int[] oppositeXpos = getAnnotationXpos(primer.opposite);
+        int startx = annoXpos[0]+(int)(primer.getSequence().length()*lw)+primerLengthSize+2;
+        int starty = ypos+_parent.getAnnotationHeight()/2-2;
+        int endx = oppositeXpos[0];
+
+        if(Math.abs(startx - endx) < 4)
+            return;
+        Color dashc = Color.BLACK;
+        Graphics2D g2d = (Graphics2D)g;
+        Stroke oldStroke = g2d.getStroke();
+        float dash_w = (float)lw/2<=2?2:(float)lw/2;
+        float[] dash = {dash_w,dash_w};
+        g2d.setColor(Color.BLACK);
+        g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10, dash, 0));
+        if(_parent.getSettings().getBoolean(Settings.SHOW_DTM_WARNING)) {
+            if(Math.abs(primer.getTm() - primer.opposite.getTm()) > _parent.getSettings().getFloat(Settings.DTM_WARNING_TEMP)) {
+                dashc = Color.decode(_parent.getSettings().get(Settings.DTM_WARNING_COLOR));
+                g.setColor(dashc);
+                g2d.setStroke(new BasicStroke(3, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10, dash, 0));
+            }
+        }
+        if(above) {
+            g.drawLine(startx, starty, endx, starty);
+            g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND));
+            g.drawLine(startx, starty-2, startx, starty+2);
+            g.drawLine(endx, starty-2, endx, starty+2);
+            g2d.setStroke(oldStroke);
+
+            NumberFormat formatter = new DecimalFormat("#");
+            g.setFont(new Font("Arial", Font.PLAIN, (int)(0.9*_parent.getLetterHeight())));
+            FontMetrics metrics = g.getFontMetrics(g.getFont());
+            String plen = formatter.format(primer.opposite.from - primer.to);
+            int w = metrics.stringWidth(plen);
+            int leftSide = annoXpos[1] + primerLengthSize;
+            int rightSide = oppositeXpos[0];
+            if(leftSide < 0 && rightSide > w) {
+                leftSide = 0;
+            }
+            if(rightSide > _width) {
+                rightSide = _width;
+            }
+            int posx = leftSide/2+rightSide/2-w/2;
+            if(posx < annoXpos[1] + primerLengthSize) {
+                posx = annoXpos[1] + primerLengthSize;
+            }
+            Rectangle2D bounds = metrics.getStringBounds(plen, g);
+            g.setColor(Color.WHITE);
+            g.fillRect(posx-1, ypos, (int)bounds.getWidth()+1, (int)bounds.getHeight());
+            g.setColor(dashc);
+            g.drawRect(posx-2, ypos, (int)bounds.getWidth()+2, (int)bounds.getHeight()+2);
+            g.setColor(Color.BLACK);
+            g.drawString(plen, posx, ypos+(int)bounds.getHeight());
+        }
+        g2d.setStroke(oldStroke);
+    }
+
+    private void drawPrimerScores(Graphics g, Primer primer, boolean above, int[] annoXpos, int lwi, int ypos) {
+        int[] scores = primer.getScores();
+        int[] groupScores = primer.getGroupScores();
+        for(int i=0; i<scores.length; i++) {
+        float red = (1.f-(scores[i]/100.f))*1.f;
+        float green = 1.f-red;
+        Color color = new Color(red, green, 0.f, 1.f);
+        g.setColor(color);
+        if(above)
+            g.fillRect(annoXpos[0]+i*lwi, ypos+_parent.getAnnotationHeight()-2, lwi, 2);
+        else
+            g.fillRect(annoXpos[0]+i*lwi, ypos, lwi, 2);
+        }
+        for(int i=0; i<groupScores.length; i++) {
+            float blue = (1.f-(groupScores[i]/100.f))*1.f;
+            float green = 1.f-blue;
+            Color color = new Color(0.f, green, blue, 1.f);
+            g.setColor(color);
+            if(above)
+                g.fillRect(annoXpos[0]+i*lwi, ypos+_parent.getAnnotationHeight()-4, lwi, 2);
+            else
+                g.fillRect(annoXpos[0]+i*lwi, ypos+2, lwi, 2);
+        }
+    }
+
+    private int drawPrimerTm(Graphics g, Primer primer, boolean above, int[] annoXpos, int lwi, int ypos) {
+        g.setColor(Color.BLACK);
+        NumberFormat formatter = new DecimalFormat("#.0");
+        g.setFont(new Font("Arial", Font.PLAIN, (int)(0.9*_parent.getLetterHeight())));
+        FontMetrics metrics = g.getFontMetrics(g.getFont());
+        String plen = formatter.format(primer.getTm());
+        int w = metrics.stringWidth(plen);
+        Rectangle2D bounds = metrics.getStringBounds(plen, g);
+        if(above) {
+            g.drawString(plen, annoXpos[0]-w, ypos+(int)bounds.getHeight());
+        }
+        else {
+            g.drawString(plen, annoXpos[0]+primer.getSequence().length()*lwi+1, ypos+(int)bounds.getHeight());
+        }
+        return w;
+    }
+
+    private int drawPrimerLength(Graphics g, Primer primer, boolean above, int[] annoXpos, int lwi, int ypos) {
+        g.setColor(Color.BLACK);
+        NumberFormat formatter = new DecimalFormat("#");
+        g.setFont(new Font("Arial", Font.PLAIN, (int)(0.9*_parent.getLetterHeight())));
+        FontMetrics metrics = g.getFontMetrics(g.getFont());
+        String tm = formatter.format(primer.getSequence().replace("-", "").length());
+        int w = metrics.stringWidth(tm);
+        Rectangle2D bounds = metrics.getStringBounds(tm, g);
+        if(above) {
+            g.drawString(tm, annoXpos[0]+primer.getSequence().length()*lwi, ypos+(int)bounds.getHeight());
+        }
+        else {
+            g.drawString(tm, annoXpos[0]-w, ypos+(int)bounds.getHeight());
+        }
+        return w;
+    }
+
+    private void drawAnnotations(Graphics g) {
+        int lh = _parent.getLetterHeight();
+        Alignment align = _parent.getAlignment();
+        int ypos = _parent.getTopOffset() + _parent.getLetterHeight();
+        for (int i = _offset[1]; i < Math.min(align.countAll(), _offset[1]+_height/lh); i++) {
+            Sequence s = align.getSequence(i);
+            Sequence ls = align.getSequence(i-1);
+            Sequence ns = align.getSequence(i+1);
+            if(ls != null && s.group == ls.group && s.collapsed) {
+                continue;
+            }
+            // -letterHeight for the sequence line, and another -annotationHeight for each
+            // level of annotation
+            ypos = _parent.getScreenY(i)-s.above.levels.size()*_parent.getAnnotationHeight() - _parent.getLetterHeight();
+            for(LinkedList<Annotation> level : s.above.levels) {
+                for(Annotation anno : level) {
+                    drawAnnotation(g, anno, ypos, lh, true);
+                }
+                ypos += _parent.getAnnotationHeight();
+            }
+            ypos += lh;
+            for(LinkedList<Annotation> level : s.below.levels) {
+                for(Annotation anno : level) {
+                    drawAnnotation(g, anno, ypos, lh, false);
+                }
+                ypos += _parent.getAnnotationHeight();
+            }
+        }
+    }
+    
+    public int getImageWidth() {
+        return(_width);
+    }
+    
+    public void redrawCursor(int cursorX, int cursorY) {
+        if(!_redrawAllBlocked) {
+            _redrawAll = false;
+        }
+        _cursorX = cursorX;
+        _cursorY = cursorY;
+    }
+    
+    public void redrawAll() {
+        _redrawAllBlocked = true;
+        _redrawAll = true;
+    }
+    
+    @Override
+    public void update(Graphics g) {
+        paint(g);
+    }
+
+    public void showPopup(MouseEvent e) {
+        if(_parent == null)
+            return;
+        if (e.getButton() == 3) {
+            if(_parent == null)
+                return;
+            updateCopyMenues();
+            int[] pos = {e.getX(), e.getY()};
+            Position realPos = _parent.getRealPos(pos);
+            _rightClickPos = realPos;
+            if(realPos.onAnnotation) {
+                _primerMenu.add(_removeAnnotation);
+                _primerMenu.add(_recolorAnnotation);
+                _currentAnnotation = realPos.annotation;
+                if(_currentAnnotation instanceof Primer) {
+                    if(((Primer)(_currentAnnotation)).isPyro)
+                        _sequencingPrimer.setSelected(true);
+                    else
+                        _sequencingPrimer.setSelected(false);
+                    if(((Primer)(_currentAnnotation)).opposite != null)
+                        _copyProduct.setEnabled(true);
+                    else
+                        _copyProduct.setEnabled(false);
+                    _primerMenu.show(this, e.getX(), e.getY());
+                }
+                else {
+                    _annotationMenu.add(_removeAnnotation);
+                    _annotationMenu.add(_recolorAnnotation);
+                    _annotationMenu.show(this, e.getX(), e.getY());
+                }
+                return;
+            }
+            if(!_parent.canAddAnnotation()) {
+                _annotation.setEnabled(false);
+                _primer.setEnabled(false);
+            }
+            else {
+                _annotation.setEnabled(true); 
+                _primer.setEnabled(true);
+            }
+            _menu.show(this, e.getX(), e.getY());
+        }
+    }
+
+    @Override
+    public void mouseClicked(MouseEvent e) {
+    }
+
+    @Override
+    public void mousePressed(MouseEvent e) {
+        showPopup(e);
+    }
+
+    @Override
+    public void mouseReleased(MouseEvent e) {
+        showPopup(e);
+    }
+
+    @Override
+    public void mouseEntered(MouseEvent e) {
+    }
+
+    @Override
+    public void mouseExited(MouseEvent e) {
+    }
+
+    public void copySequences(boolean withNames) {
+        Clipboard clip = getToolkit().getSystemClipboard();
+        StringBuilder seqStringBuilder = new StringBuilder();
+        for(int i=_parent.getSelFrom()[1]; i<_parent.getSelTo()[1]; i++) {
+            Sequence seq = _parent.getAlignment().getSequence(i);
+            if(withNames) {
+                seqStringBuilder.append(">");
+                seqStringBuilder.append(seq.name);
+                seqStringBuilder.append(" (");
+                seqStringBuilder.append(_parent.getSelFrom()[0]);
+                seqStringBuilder.append(" - ");
+                seqStringBuilder.append(_parent.getSelTo()[0]);
+                seqStringBuilder.append(")\n");
+            }
+            seqStringBuilder.append(seq.seq.substring(_parent.getSelFrom()[0], _parent.getSelTo()[0]));
+            seqStringBuilder.append("\n");
+        }
+        StringSelection contents = new StringSelection(seqStringBuilder.toString());
+        clip.setContents(contents, this);
+    }
+
+    public void copyMasterConsensusSequence() {
+        Clipboard clip = getToolkit().getSystemClipboard();
+        String res = "";
+        if(_parent.getSelFrom()[0] == 0 && _parent.getSelTo()[0] == 0) {
+            res = _parent.getMasterSequenceAll().seq;
+
+        }
+        else {
+            res = _parent.getMasterSequenceAll().seq.substring(_parent.getSelFrom()[0], _parent.getSelTo()[0]);
+        }
+        clip.setContents(new StringSelection(res), this);
+    }
+
+    public void copyGroupConsensusSequence() {
+        Clipboard clip = getToolkit().getSystemClipboard();
+        String res = _parent.getMasterSequences().get(_parent.getAlignment().getSequence(_parent.getSelFrom()[1]).group).seq;
+        if(_parent.getSelFrom()[0] != 0 || _parent.getSelTo()[0] != 0) {
+            res = res.substring(_parent.getSelFrom()[0], _parent.getSelTo()[0]);
+        }
+        clip.setContents(new StringSelection(res), this);
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        if(e.getSource() == _annoEdit) {
+            _parent.getEditedAnnotation().text = _annoEdit.getText();
+            _annoEdit.correctText = false;
+            _annoEdit.isAdded = false;
+            remove(_annoEdit);
+            _parent.setEditedAnnotation(null);
+            doLayout();
+            repaint();
+        }
+        else if(e.getSource() == _loadFile) {
+            _parent.loadFile(true);
+        }
+        else if(e.getSource() == _loadFileRKI) {
+            _parent.loadFileRKI(true);
+        }
+        else if(e.getSource() == _addSequencesRKI) {
+            _parent.loadFileRKI(false);
+        }
+        else if(e.getSource() == _addSequences) {
+            _parent.loadFile(false);
+        }
+        else if(e.getSource() == _saveFileRKI) {
+            _parent.saveToRKITools(null);
+        }
+        else if(e.getSource() == _snpToggle) {
+            _parent.getAlignment().toggleSnp(_rightClickPos.x);
+        }
+        else if(e.getSource() == _saveFileRKIas) {
+            Frame parentFrame = _parent.getParentFrame();
+            String name = JOptionPane.showInputDialog(parentFrame, "Please enter the new filename");
+            if(name != null && name.length() != 0) {
+                _parent.saveToRKITools(name);
+            }
+//            _parent.saveToRKITools();
+        }
+        else if(e.getSource() == _deleteSelected) {
+            int from = Math.min(_parent.getSelFrom()[1], _parent.getSelTo()[1]);
+            int to = Math.max(_parent.getSelFrom()[1], _parent.getSelTo()[1]);
+            int xfrom = Math.min(_parent.getSelFrom()[0], _parent.getSelTo()[0]);
+            int xto = Math.max(_parent.getSelFrom()[0], _parent.getSelTo()[0]);
+            for(int i=from; i<to; i++) {
+                _parent.getAlignment().getSequence(i).removePart(xfrom, xto);
+            }
+            _parent.setSelFrom(0, 0);
+            _parent.setSelFrom(1, 0);
+            _parent.setSelTo(0, 0);
+            _parent.setSelTo(1, 0);
+            _parent.consensusChange();
+            _parent.repaintAll();
+        }
+        else if(e.getSource() == _removeAnnotation) {
+            _currentAnnotation.list.removeAnnotation(_currentAnnotation);
+            _currentAnnotation.list.resetAnnotations();
+            redrawAll();
+            repaint();
+            updateFlowgrams(false);
+        }
+        else if(e.getSource() == _recolorAnnotation) {
+            JDialog jc = JColorChooser.createDialog(this, TOOL_TIP_TEXT_KEY, true, _chooser,
+                new ActionListener() {
+                    @Override
+                    public void actionPerformed(ActionEvent e) {
+                        _currentAnnotation.background = _chooser.getColor();
+                        _parent.repaintAll();
+                    }
+                }
+            , null);
+            jc.setVisible(true);
+        }
+        else if(e.getSource() == _degeneratePrimer) {
+            if(_parent.getMasterSequenceAll() == null) {
+                _parent.getMasterConsensus();
+            }
+            Primer primer = (Primer)_currentAnnotation;
+            primer.degenerate(_parent.getMasterSequenceAll().IUB.seq.substring(
+                    primer.from, primer.to));
+            repaint();
+        }
+        else if(e.getSource() == _degeneratePrimerGroup) {
+            if(_parent.getMasterSequences().isEmpty()) {
+                _parent.getGroupMasterSequences();
+            }
+            HashMap<GroupKey, MasterSequence> masterSequences = _parent.getMasterSequences();
+            MasterSequence master = masterSequences.get(_currentAnnotation.list.sequence.group);
+            Primer primer = (Primer)_currentAnnotation;
+            primer.degenerate(master.IUB.seq.substring(primer.from, primer.to));
+            repaint();
+        }
+        else if(e.getSource() == _copyPrimerSequence) {
+            Primer primer = (Primer)_currentAnnotation;
+            Clipboard clip = getToolkit().getSystemClipboard();
+            if(primer.list.above)
+                clip.setContents(new StringSelection(primer.getSequence()), this);
+            else
+                clip.setContents(new StringSelection(Sequence.invert(primer.getSequence())), this);
+        }
+        else if(e.getSource() == _copyPrimer) {
+            Primer primer = (Primer)_currentAnnotation;
+            Clipboard clip = getToolkit().getSystemClipboard();
+            if(primer.list.above)
+                clip.setContents(new StringSelection(">" + primer.text + "\n" + primer.getSequence()), this);
+            else
+                clip.setContents(new StringSelection(">" + primer.text + "\n" + Sequence.invert(primer.getSequence())), this);
+        }
+        else if(e.getSource() == _copyProductWithPrimersGaps
+                || e.getSource() == _copyProductWithPrimersWithoutGaps
+                || e.getSource() == _copyProductWithoutPrimersGaps
+                || e.getSource() == _copyProductWithoutPrimersWithoutGaps) {
+            Primer primer = (Primer)_currentAnnotation;
+            Clipboard clip = getToolkit().getSystemClipboard();
+            if(primer.list.above && e.getSource() == _copyProductWithPrimersGaps)
+                clip.setContents(new StringSelection(primer.list.sequence.seq.substring(primer.from, primer.opposite.to)), this);
+            else if(!primer.list.above && e.getSource() == _copyProductWithPrimersGaps)
+                clip.setContents(new StringSelection(primer.list.sequence.seq.substring(primer.opposite.from, primer.to)), this);
+            else if(primer.list.above && e.getSource() == _copyProductWithoutPrimersGaps)
+                clip.setContents(new StringSelection(primer.list.sequence.seq.substring(primer.to, primer.opposite.from)), this);
+            else if(!primer.list.above && e.getSource() == _copyProductWithoutPrimersGaps)
+                clip.setContents(new StringSelection(primer.list.sequence.seq.substring(primer.opposite.to, primer.from)), this);
+            else if(primer.list.above && e.getSource() == _copyProductWithPrimersWithoutGaps)
+                clip.setContents(new StringSelection(primer.list.sequence.seq.substring(primer.from, primer.opposite.to).replace("-", "")), this);
+            else if(!primer.list.above && e.getSource() == _copyProductWithPrimersWithoutGaps)
+                clip.setContents(new StringSelection(primer.list.sequence.seq.substring(primer.opposite.from, primer.to).replace("-", "")), this);
+            else if(primer.list.above && e.getSource() == _copyProductWithoutPrimersWithoutGaps)
+                clip.setContents(new StringSelection(primer.list.sequence.seq.substring(primer.to, primer.opposite.from).replace("-", "")), this);
+            else if(!primer.list.above && e.getSource() == _copyProductWithoutPrimersWithoutGaps)
+                clip.setContents(new StringSelection(primer.list.sequence.seq.substring(primer.opposite.to, primer.from).replace("-", "")), this);
+        }
+        else if(e.getSource() == _copyPrimers) {
+            Clipboard clip = getToolkit().getSystemClipboard();
+            StringBuilder primerSeqs = new StringBuilder();
+            for(Sequence seq : _parent.getAlignment().getSequencesAll()) {
+                for(Annotation anno : seq.above.getAnnotations()) {
+                    if(anno instanceof Primer) {
+                        Primer primer = (Primer)anno;
+                        primerSeqs.append(">");
+                        primerSeqs.append(primer.text);
+                        primerSeqs.append("\n");
+                        primerSeqs.append(primer.getSequence());
+                        primerSeqs.append("\n");
+                    }
+                }
+                for(Annotation anno : seq.below.getAnnotations()) {
+                    if(anno instanceof Primer) {
+                        Primer primer = (Primer)anno;
+                        primerSeqs.append(">");
+                        primerSeqs.append(primer.text);
+                        primerSeqs.append("\n");
+                        primerSeqs.append(Sequence.invert(primer.getSequence()));
+                        primerSeqs.append("\n");
+                    }
+                }
+            }
+            clip.setContents(new StringSelection(primerSeqs.toString()), this);
+        }
+        else if(e.getSource() == _sequencingPrimer) {
+            Primer primer = (Primer)_currentAnnotation;
+            primer.isPyro = _sequencingPrimer.isSelected();
+            _parent.updateFlowgrams(false);
+        }
+        else if (e.getSource().getClass() == ColorModelMenuItem.class) {
+            JMenuItem jm = (JMenuItem) e.getSource();
+            String name = jm.getText();
+            ColorModels.currentModel = name;
+            _parent.setColorOpts(name);
+            _parent.repaintAll();
+        }
+        else if (e.getSource().getClass() == SizeMenuItem.class) {
+            JMenuItem jm = (JMenuItem) e.getSource();
+            int size = Integer.parseInt(jm.getText());
+            _parent.setLetterWidth(size);
+        }
+        else if(e.getSource().getClass() == TripletMenuItem.class) {
+            JMenuItem jm = (JMenuItem) e.getSource();
+            if(jm.getText().equals("None")) {
+                _parent.getAlignment().tripletGrouping = -1;
+            }
+            else if(jm.getText().equals("+0")) {
+                _parent.getAlignment().tripletGrouping = 0;
+            }
+            else if(jm.getText().equals("+1")) {
+                _parent.getAlignment().tripletGrouping = 1;
+            }
+            else if(jm.getText().equals("+2")) {
+                _parent.getAlignment().tripletGrouping = 2;
+            }
+            _parent.repaintAll();
+        }
+        else if(e.getSource() == _annotationAbove) {
+            _parent.addAnnotation(true, false);
+        }
+        else if(e.getSource() == _annotationBelow) {
+            _parent.addAnnotation(false, false);
+        }
+        else if(e.getSource() == _primerAbove) {
+            _parent.addAnnotation(true, true);
+            _parent.updateFlowgrams(false);
+        }
+        else if(e.getSource() == _primerBelow) {
+            _parent.addAnnotation(false, true);
+            _parent.updateFlowgrams(false);
+        }
+        else if(e.getSource() == _copySequences || e.getSource() == _copySequencesWithNames) {
+            Clipboard clip = getToolkit().getSystemClipboard();
+            StringBuilder seqStringBuilder = new StringBuilder();
+            for(int i=_parent.getSelFrom()[1]; i<_parent.getSelTo()[1]; i++) {
+                Sequence seq = _parent.getAlignment().getSequence(i);
+                if(e.getSource() == _copySequencesWithNames) {
+                    seqStringBuilder.append(">");
+                    seqStringBuilder.append(seq.name);
+                    seqStringBuilder.append(" (");
+                    seqStringBuilder.append(_parent.getSelFrom()[0]);
+                    seqStringBuilder.append(" - ");
+                    seqStringBuilder.append(_parent.getSelTo()[0]);
+                    seqStringBuilder.append(")\n");
+                }
+                seqStringBuilder.append(seq.seq.substring(_parent.getSelFrom()[0], _parent.getSelTo()[0]));
+                seqStringBuilder.append("\n");
+            }
+            StringSelection contents = new StringSelection(seqStringBuilder.toString());
+            clip.setContents(contents, this);
+        }
+        else if(e.getSource() == _copyMaster) {
+            copyMasterConsensusSequence();
+        }
+        else if(e.getSource() == _copyGroup) {
+            copyGroupConsensusSequence();
+        }
+    }
+
+    @Override
+    public void lostOwnership(Clipboard clipboard, Transferable contents) {
+    }
+
+    @Override
+    public void mouseWheelMoved(MouseWheelEvent e) {
+        _parent.mouseWheelMoved(e);
+    }
+
+    private class RedrawTask extends TimerTask {
+        private SequencePane _pane;
+        public RedrawTask(SequencePane pane) {
+            super();
+            _pane = pane;
+        }
+
+        @Override
+        public void run() {
+            _pane.repaint();
+        }
+    }
+}
diff --git a/src/org/rki/sequenceeditor/view/SequenceTip.java b/src/org/rki/sequenceeditor/view/SequenceTip.java
new file mode 100644
index 0000000..3b329ba
--- /dev/null
+++ b/src/org/rki/sequenceeditor/view/SequenceTip.java
@@ -0,0 +1,32 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.rki.sequenceeditor.view;
+
+import java.awt.Point;
+import javax.swing.JToolTip;
+
+/**
+ *
+ * @author dabrowskiw
+ */
+public class SequenceTip extends JToolTip {
+    private String _text = "Bla";
+
+    @Override
+    public String getTipText() {
+        return(_text);
+    }
+    
+    @Override
+    public void setTipText(String text) {
+    }
+
+    @Override
+    public Point getLocationOnScreen() {
+        return(new Point(0, 0));
+    }
+    
+}
diff --git a/src/version.properties b/src/version.properties
new file mode 100644
index 0000000..ab9df16
--- /dev/null
+++ b/src/version.properties
@@ -0,0 +1,2 @@
+#Thu Sep 10 14:46:16 CEST 2009
+BUILD=1,042

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/mpsqed.git



More information about the debian-med-commit mailing list