[med-svn] [libalter-java] 01/02: Imported Upstream version 1.3.3+dfsg

Andreas Tille tille at debian.org
Sat Sep 5 06:20:28 UTC 2015


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

tille pushed a commit to branch master
in repository libalter-java.

commit d19059a03d3b554fa734e419cbe6df90513082fa
Author: Andreas Tille <tille at debian.org>
Date:   Sat Sep 5 08:18:32 2015 +0200

    Imported Upstream version 1.3.3+dfsg
---
 COPYING.LESSER                                     |  165 +++
 alter-lib/MANIFEST.MF                              |    7 +
 alter-lib/alter.sh                                 |    3 +
 alter-lib/build.xml                                |   55 +
 alter-lib/src/alter.sh                             |    3 +
 alter-lib/src/cmdLine/CmdLineLogHandler.java       |   64 ++
 alter-lib/src/cmdLine/CmdLineOptions.java          |  130 +++
 alter-lib/src/cmdLine/Convert.java                 |  140 +++
 alter-lib/src/cmdLine/package.html                 |   12 +
 alter-lib/src/converter/Converter.java             |   36 +
 alter-lib/src/converter/DefaultConverter.java      |  101 ++
 alter-lib/src/converter/DefaultFactory.java        |  458 ++++++++
 alter-lib/src/converter/Factory.java               |   90 ++
 alter-lib/src/converter/ProgramOptions.java        |  409 +++++++
 alter-lib/src/converter/package.html               |   12 +
 alter-lib/src/gui/ConvertPanel.form                |  428 ++++++++
 alter-lib/src/gui/ConvertPanel.java                |  791 ++++++++++++++
 alter-lib/src/gui/GUILogHandler.java               |   96 ++
 alter-lib/src/gui/HelpPanel.form                   |   52 +
 alter-lib/src/gui/HelpPanel.java                   |   84 ++
 alter-lib/src/gui/MainFrame.form                   |  353 +++++++
 alter-lib/src/gui/MainFrame.java                   | 1115 ++++++++++++++++++++
 alter-lib/src/gui/package.html                     |   12 +
 alter-lib/src/org/kohsuke/args4j/Argument.java     |   33 +
 .../src/org/kohsuke/args4j/CmdLineException.java   |   22 +
 .../src/org/kohsuke/args4j/CmdLineParser.java      |  599 +++++++++++
 alter-lib/src/org/kohsuke/args4j/ExampleMode.java  |   33 +
 alter-lib/src/org/kohsuke/args4j/FieldSetter.java  |   42 +
 .../org/kohsuke/args4j/IllegalAnnotationError.java |   27 +
 alter-lib/src/org/kohsuke/args4j/MapSetter.java    |   65 ++
 alter-lib/src/org/kohsuke/args4j/Messages.java     |   29 +
 .../src/org/kohsuke/args4j/Messages.properties     |   25 +
 alter-lib/src/org/kohsuke/args4j/MethodSetter.java |   61 ++
 .../org/kohsuke/args4j/MultiValueFieldSetter.java  |   69 ++
 .../src/org/kohsuke/args4j/NamedOptionDef.java     |   44 +
 alter-lib/src/org/kohsuke/args4j/Option.java       |  167 +++
 alter-lib/src/org/kohsuke/args4j/OptionDef.java    |   63 ++
 alter-lib/src/org/kohsuke/args4j/Starter.java      |  109 ++
 alter-lib/src/org/kohsuke/args4j/package.html      |   14 +
 .../kohsuke/args4j/spi/BooleanOptionHandler.java   |   43 +
 .../org/kohsuke/args4j/spi/ByteOptionHandler.java  |   24 +
 .../org/kohsuke/args4j/spi/CharOptionHandler.java  |   23 +
 .../kohsuke/args4j/spi/DoubleOptionHandler.java    |   21 +
 .../org/kohsuke/args4j/spi/EnumOptionHandler.java  |   53 +
 .../org/kohsuke/args4j/spi/FileOptionHandler.java  |   29 +
 .../org/kohsuke/args4j/spi/FloatOptionHandler.java |   26 +
 .../org/kohsuke/args4j/spi/IntOptionHandler.java   |   22 +
 .../org/kohsuke/args4j/spi/LongOptionHandler.java  |   24 +
 .../org/kohsuke/args4j/spi/MapOptionHandler.java   |   32 +
 alter-lib/src/org/kohsuke/args4j/spi/Messages.java |   23 +
 .../src/org/kohsuke/args4j/spi/Messages.properties |    5 +
 .../args4j/spi/OneArgumentOptionHandler.java       |   45 +
 .../src/org/kohsuke/args4j/spi/OptionHandler.java  |   94 ++
 .../src/org/kohsuke/args4j/spi/Parameters.java     |   29 +
 alter-lib/src/org/kohsuke/args4j/spi/Setter.java   |   29 +
 .../org/kohsuke/args4j/spi/ShortOptionHandler.java |   24 +
 .../org/kohsuke/args4j/spi/StopOptionHandler.java  |   49 +
 .../kohsuke/args4j/spi/StringOptionHandler.java    |   27 +
 alter-lib/src/org/kohsuke/args4j/spi/package.html  |   14 +
 alter-lib/src/parser/AlnParser.jj                  |  265 +++++
 alter-lib/src/parser/AutodetectionParser.jj        |  184 ++++
 alter-lib/src/parser/FastaParser.jj                |  186 ++++
 alter-lib/src/parser/GdeParser.jj                  |  141 +++
 alter-lib/src/parser/MsfParser.jj                  |  284 +++++
 alter-lib/src/parser/NexusParser.jj                |  382 +++++++
 alter-lib/src/parser/PhylipParser.jj               |  348 ++++++
 alter-lib/src/parser/PirParser.jj                  |  163 +++
 alter-lib/src/parser/package.html                  |   12 +
 alter-lib/src/reader/AlnReader.java                |   79 ++
 alter-lib/src/reader/AutodetectionReader.java      |   80 ++
 alter-lib/src/reader/FastaReader.java              |   78 ++
 alter-lib/src/reader/GdeReader.java                |   79 ++
 alter-lib/src/reader/MsfReader.java                |   79 ++
 alter-lib/src/reader/NexusReader.java              |   84 ++
 alter-lib/src/reader/PhylipReader.java             |   85 ++
 alter-lib/src/reader/PirReader.java                |   81 ++
 alter-lib/src/reader/Reader.java                   |   37 +
 alter-lib/src/reader/ReaderUtils.java              |   53 +
 alter-lib/src/reader/package.html                  |   12 +
 alter-lib/src/types/Aln.java                       |   71 ++
 alter-lib/src/types/AlnSequence.java               |   37 +
 alter-lib/src/types/Checksumable.java              |   34 +
 alter-lib/src/types/DNA.java                       |   26 +
 alter-lib/src/types/DNACircular.java               |   26 +
 alter-lib/src/types/DNALinear.java                 |   26 +
 alter-lib/src/types/Describable.java               |   33 +
 alter-lib/src/types/Fasta.java                     |   70 ++
 alter-lib/src/types/FastaSequence.java             |   53 +
 alter-lib/src/types/Gde.java                       |   70 ++
 alter-lib/src/types/GdeSequence.java               |   37 +
 alter-lib/src/types/Lengthable.java                |   34 +
 alter-lib/src/types/MSA.java                       |  133 +++
 alter-lib/src/types/Msf.java                       |  137 +++
 alter-lib/src/types/MsfSequence.java               |   83 ++
 alter-lib/src/types/Nexus.java                     |  141 +++
 alter-lib/src/types/NexusSequence.java             |   37 +
 alter-lib/src/types/Nucleotide.java                |   26 +
 alter-lib/src/types/Phylip.java                    |  101 ++
 alter-lib/src/types/PhylipSequence.java            |   37 +
 alter-lib/src/types/Pir.java                       |   79 ++
 alter-lib/src/types/PirSequence.java               |   88 ++
 alter-lib/src/types/Protein.java                   |   26 +
 alter-lib/src/types/ProteinComplete.java           |   27 +
 alter-lib/src/types/ProteinFragment.java           |   27 +
 alter-lib/src/types/RNA.java                       |   27 +
 alter-lib/src/types/RNACircular.java               |   26 +
 alter-lib/src/types/RNALinear.java                 |   26 +
 alter-lib/src/types/RNAOther.java                  |   26 +
 alter-lib/src/types/RNAt.java                      |   26 +
 alter-lib/src/types/Sequence.java                  |   85 ++
 alter-lib/src/types/Taxable.java                   |   34 +
 alter-lib/src/types/Type.java                      |   27 +
 alter-lib/src/types/Typeable.java                  |   33 +
 alter-lib/src/types/Weightable.java                |   33 +
 alter-lib/src/types/package.html                   |   12 +
 alter-lib/src/writer/AlnJModelTestWriter.java      |   69 ++
 alter-lib/src/writer/AlnWriter.java                |  333 ++++++
 alter-lib/src/writer/FastaDnaSPWriter.java         |   69 ++
 alter-lib/src/writer/FastaJModelTestWriter.java    |   73 ++
 alter-lib/src/writer/FastaWriter.java              |  163 +++
 alter-lib/src/writer/GdeSeAlWriter.java            |   52 +
 alter-lib/src/writer/GdeWriter.java                |  193 ++++
 alter-lib/src/writer/MegaDnaSPWriter.java          |   69 ++
 alter-lib/src/writer/MegaWriter.java               |  196 ++++
 alter-lib/src/writer/MsfJModelTestWriter.java      |   72 ++
 alter-lib/src/writer/MsfMegaWriter.java            |   55 +
 alter-lib/src/writer/MsfSeaViewWriter.java         |   62 ++
 alter-lib/src/writer/MsfWriter.java                |  353 +++++++
 alter-lib/src/writer/NexusDnaSPWriter.java         |   70 ++
 alter-lib/src/writer/NexusJModelTestWriter.java    |   75 ++
 alter-lib/src/writer/NexusMesquiteWriter.java      |   62 ++
 alter-lib/src/writer/NexusMrBayesWriter.java       |  145 +++
 alter-lib/src/writer/NexusProtTestWriter.java      |   70 ++
 alter-lib/src/writer/NexusSplitsTreeWriter.java    |   65 ++
 alter-lib/src/writer/NexusTCSWriter.java           |   76 ++
 alter-lib/src/writer/NexusWriter.java              |  360 +++++++
 alter-lib/src/writer/PhylipBioEditWriter.java      |   52 +
 alter-lib/src/writer/PhylipCodABCWriter.java       |   89 ++
 alter-lib/src/writer/PhylipDnaSPWriter.java        |   88 ++
 alter-lib/src/writer/PhylipJModelTestWriter.java   |   74 ++
 alter-lib/src/writer/PhylipMegaWriter.java         |   92 ++
 alter-lib/src/writer/PhylipPAMLWriter.java         |   93 ++
 alter-lib/src/writer/PhylipPhyMLWriter.java        |   82 ++
 alter-lib/src/writer/PhylipProtTestWriter.java     |   88 ++
 alter-lib/src/writer/PhylipRAxMLWriter.java        |  119 +++
 alter-lib/src/writer/PhylipSplitsTreeWriter.java   |   58 +
 alter-lib/src/writer/PhylipTCSWriter.java          |   94 ++
 alter-lib/src/writer/PhylipWriter.java             |  373 +++++++
 alter-lib/src/writer/PirDnaSPWriter.java           |   69 ++
 alter-lib/src/writer/PirJModelTestWriter.java      |   73 ++
 alter-lib/src/writer/PirWriter.java                |  248 +++++
 alter-lib/src/writer/Writer.java                   |   39 +
 alter-lib/src/writer/WriterUtils.java              |  179 ++++
 alter-lib/src/writer/package.html                  |   16 +
 build.xml                                          |   18 +
 155 files changed, 15806 insertions(+)

diff --git a/COPYING.LESSER b/COPYING.LESSER
new file mode 100644
index 0000000..cca7fc2
--- /dev/null
+++ b/COPYING.LESSER
@@ -0,0 +1,165 @@
+		   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/alter-lib/MANIFEST.MF b/alter-lib/MANIFEST.MF
new file mode 100644
index 0000000..538972f
--- /dev/null
+++ b/alter-lib/MANIFEST.MF
@@ -0,0 +1,7 @@
+Manifest-Version: 1.0
+Ant-Version: Apache Ant 1.7.1
+Created-By: 14.3-b01-101 (Apple Inc.)
+Main-Class: cmdLine.Convert
+Class-Path: 
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/alter-lib/alter.sh b/alter-lib/alter.sh
new file mode 100644
index 0000000..88a0fb2
--- /dev/null
+++ b/alter-lib/alter.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+java -jar ALTER.jar $*
\ No newline at end of file
diff --git a/alter-lib/build.xml b/alter-lib/build.xml
new file mode 100644
index 0000000..e4e3ee5
--- /dev/null
+++ b/alter-lib/build.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="ALTERLIB" default="buildjar" basedir=".">
+
+  <dirname property="ALTERLIB.basedir" file="${ant.file.ALTERLIB}"/>
+  <property name="build" location="${ALTERLIB.basedir}/build"/>
+  <property name="src" location="${ALTERLIB.basedir}/src"/>  
+  <property name="dist" location="${ALTERLIB.basedir}/dist"/>    
+  <property name="javacchome" location="${ALTERLIB.basedir}/javacc-5.0"/>
+  <property name="grammars" location="${src}/parser"/>
+  <property name="javaversion" value="1.6" />
+  
+  <taskdef resource="net/sf/antcontrib/antcontrib.properties">
+    <classpath>
+      <pathelement location="${ALTERLIB.basedir}/ant-contrib/ant-contrib-1.0b3.jar"/>
+    </classpath>
+  </taskdef>
+  
+  <target name="clean">
+    <delete dir="${build}"/>
+    <delete dir="${dist}"/>
+    <delete>
+      <fileset dir="${grammars}" includes="**/*.java"/>
+    </delete>
+  </target>
+  
+  <target name="compileGrammar">
+    <javacc target="${grammar}" javacchome="${javacchome}">
+    </javacc>
+  </target>
+  
+  <target name="javacc">  
+    <foreach target="compileGrammar" param="grammar">
+	<path> 
+	  <fileset dir="${grammars}" includes="**/*.jj"/> 
+	</path> 
+    </foreach>  
+  </target>
+  
+  <target name="build" depends="javacc">
+    <mkdir dir="${build}"/>    
+    <javac srcdir="${src}" destdir="${build}" target="${javaversion}" source="${javaversion}">      
+    </javac>    
+    <copy todir="${build}">
+      <fileset dir="${src}">
+	<exclude name="**/*.java"/>
+      </fileset>
+    </copy>
+    
+  </target>
+  <target name="buildjar" depends="clean, build">
+      <mkdir dir="${dist}"/>
+      <jar destfile="${dist}/ALTER.jar"
+       basedir="${build}" manifest="${ALTERLIB.basedir}/MANIFEST.MF"/>
+  </target>
+</project>
diff --git a/alter-lib/src/alter.sh b/alter-lib/src/alter.sh
new file mode 100755
index 0000000..88a0fb2
--- /dev/null
+++ b/alter-lib/src/alter.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+java -jar ALTER.jar $*
\ No newline at end of file
diff --git a/alter-lib/src/cmdLine/CmdLineLogHandler.java b/alter-lib/src/cmdLine/CmdLineLogHandler.java
new file mode 100755
index 0000000..1cc3723
--- /dev/null
+++ b/alter-lib/src/cmdLine/CmdLineLogHandler.java
@@ -0,0 +1,64 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package cmdLine;
+
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ * Implements a handler for logging messages, printing them to the standard out stream.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public class CmdLineLogHandler extends Handler
+{
+    /**
+     * Prints messages in the adequate format.
+     * @param record Message to print.
+     */
+    @Override
+    public void publish(LogRecord record)
+    {
+        if (record.getLevel() == Level.INFO)
+            System.out.println("<INFO> : " + record.getMessage().replace("\n", "\n\t"));
+        else if (record.getLevel() == Level.WARNING)
+            System.out.println("<WARNING> : " + record.getMessage().replace("\n", "\n\t"));
+        else
+            System.err.println("<ERROR>: " + record.getMessage().replace("\n", "\n\t"));
+    }
+
+    /**
+     * Calls Sytem.out.flush() and System.err.flush().
+     */
+    @Override
+    public void flush()
+    {
+        System.out.flush();
+        System.err.flush();
+    }
+
+    /**
+     * No behaviour has been implemented for this method.
+     * @throws SecurityException If a Security Manager exists and the calling object does not have permission.
+     */
+    @Override
+    public void close() throws SecurityException
+    {
+    }
+}
diff --git a/alter-lib/src/cmdLine/CmdLineOptions.java b/alter-lib/src/cmdLine/CmdLineOptions.java
new file mode 100755
index 0000000..41e0395
--- /dev/null
+++ b/alter-lib/src/cmdLine/CmdLineOptions.java
@@ -0,0 +1,130 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package cmdLine;
+
+import java.io.File;
+import org.kohsuke.args4j.Option;
+
+/**
+ * Defines the options to be processed by args4j when ALTER is executed
+ * from the command line. Java annotations are used.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public class CmdLineOptions
+{
+    /**
+     * Inpute file.
+     */
+    @Option(name = "-i", usage = "Input file.", required = true, aliases = "--input")
+    File in;
+    /**
+     * Input operating system (Linux, MacOS or Windows).
+     */
+    @Option(name = "-io", usage = "Input operating system (Linux, MacOS or Windows).",
+    aliases = "--inputOS")
+    String inOS;
+    /**
+     * Input program (Clustal, MAFFT, MUSCLE, PROBCONS or TCoffee).
+     */
+    @Option(name = "-ip", usage = "Input program (Clustal, MAFFT, MUSCLE, PROBCONS or TCoffee).",
+    aliases = "--inputProgram")
+    String inProgram;
+    /**
+     * Inpute format (ALN, FASTA, GDE, MSF, NEXUS, PHYLIP or PIR).
+     */
+    @Option(name = "-if", usage = "Input format (ALN, FASTA, GDE, MEGA, MSF, NEXUS, PHYLIP or PIR).",
+    aliases = "--inputFormat")
+    String inFormat;
+    /**
+     * Autodetect format (other input options are omitted).
+     */
+    @Option(name = "-ia", usage = "Autodetect format (other input options are omitted).",
+    aliases = "--inputAutodetect")
+    boolean autodetect = false;
+    /**
+     * Collapse sequences to haplotypes.
+     */
+    @Option(name = "-c", usage = "Collapse sequences to haplotypes.",
+    aliases = "--collapse")
+    boolean collapse = false;
+    /**
+     * Treat gaps as missing data when collapsing.
+     */
+    @Option(name = "-cg", usage = "Treat gaps as missing data when collapsing.",
+    aliases = "--collapseGaps")
+    boolean gaps = false;
+    /**
+     * Count missing data as differences when collapsing.
+     */
+    @Option(name = "-cm", usage = "Count missing data as differences when collapsing.",
+    aliases = "--collapseMissing")
+    boolean missing = true;
+    /**
+     * Connection limit (sequences differing at <= l sites will be collapsed) (default is l=0).
+     */
+    @Option(name = "-cl", usage = "Connection limit (sequences differing at <= l sites will be collapsed) (default is l=0).",
+    aliases = "--collapseLimit")
+    int limit = 0;
+    /**
+     * Output file.
+     */
+    @Option(name = "-o", usage = "Output file.", required = true, aliases = "--output")
+    File out;
+    /**
+     * Output operating system (Linux, MacOS or Windows).
+     */
+    @Option(name = "-oo", usage = "Output operating system (Linux, MacOS or Windows).",
+    required = true, aliases = "--outputOS")
+    String outOS;
+    /**
+     * Output program (jModelTest, MrBayes, PAML, PAUP, PhyML, ProtTest, RAxML, TCS, CodABC, BioEdit, MEGA, dnaSP, Se-Al, Mesquite, SplitsTree, Clustal, MAFFT, MUSCLE, PROBCONS, TCoffee, Gblocks, SeaView, trimAl or GENERAL).
+     */
+    @Option(name = "-op", usage = "Output program (jModelTest, MrBayes, PAML, PAUP, PhyML, ProtTest, RAxML, TCS, CodABC, BioEdit, MEGA, dnaSP, Se-Al, Mesquite, SplitsTree, Clustal, MAFFT, MUSCLE, PROBCONS, TCoffee, Gblocks, SeaView, trimAl or GENERAL)",
+    required = true, aliases = "--outputProgram")
+    String outProgram;
+    /**
+     * Output format (ALN, FASTA, GDE, MEGA, MSF, NEXUS, PHYLIP or PIR).
+     */
+    @Option(name = "-of", usage = "Output format (ALN, FASTA, GDE, MEGA, MSF, NEXUS, PHYLIP or PIR).",
+    required = true, aliases = "--outputFormat")
+    String outFormat;
+    /**
+     * Lower case output.
+     */
+    @Option(name = "-ol", usage = "Lowe case output.", aliases = "--outputLowerCase")
+    boolean lowerCase = false;
+    /**
+     * Output residue numbers (only ALN format).
+     */
+    @Option(name = "-on", usage = "Output residue numbers (only ALN format).",
+    aliases = "--outputResidueNumbers")
+    boolean residueNumbers = false;
+    /**
+     * Sequential output (only NEXUS and PHYLIP formats).
+     */
+    @Option(name = "-os", usage = "Sequential output (only NEXUS and PHYLIP formats).",
+    aliases = "--outputSequential")
+    boolean sequential = false;
+    /**
+     * Output match characters.
+     */
+    @Option(name = "-om", usage = "Output match characters.",
+    aliases = "--outputMatch")
+    boolean match = false;
+}
diff --git a/alter-lib/src/cmdLine/Convert.java b/alter-lib/src/cmdLine/Convert.java
new file mode 100755
index 0000000..0683931
--- /dev/null
+++ b/alter-lib/src/cmdLine/Convert.java
@@ -0,0 +1,140 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package cmdLine;
+
+import converter.Converter;
+import converter.DefaultFactory;
+import converter.Factory;
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import parser.ParseException;
+
+/**
+ * Main class to execute ALTER from the command line.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public class Convert
+{
+    /**
+     * Main method to execute ALTER from the command line.
+     * @param args Conversion options.
+     */
+    public static void main(String args[])
+    {
+        //If there are no parameters launch the GUI version of ALTER
+        if (args.length == 0)
+            gui.MainFrame.main(args);
+
+        //In other case use the command line
+        else
+        {
+            //Initialize logger
+            Logger logger = Logger.getLogger("alter" + System.currentTimeMillis());
+            logger.setUseParentHandlers(false);
+            logger.setLevel(Level.ALL);
+            logger.addHandler(new CmdLineLogHandler());
+
+            //Parse options
+            CmdLineOptions opts = new CmdLineOptions();
+            CmdLineParser parser = new CmdLineParser(opts);
+            try
+            {
+                parser.parseArgument(args);
+            }
+            catch (CmdLineException e)
+            {
+                System.err.println(e.getMessage());
+                parser.printUsage(System.err);
+                return;
+            }
+            if (!opts.autodetect && (opts.inOS == null || opts.inProgram == null || opts.inFormat == null))
+            {
+                System.err.println("Autodetection not enabled. Input options required.");
+                parser.printUsage(System.err);
+                return;
+            }
+
+            //Load input file
+            StringBuffer in = new StringBuffer();
+            try
+            {
+                BufferedReader br = new BufferedReader(new FileReader(opts.in));
+                String s;
+                while ((s = br.readLine()) != null)
+                    in.append(s + "\r\n");
+                br.close();
+            }
+
+            catch (FileNotFoundException ex)
+            {
+                logger.log(Level.SEVERE, "Input file " + opts.in + " not found.");
+                return;
+            }
+            catch (IOException ex)
+            {
+                logger.log(Level.SEVERE, "Failure reading input file " + opts.in + ":\r\n" + ex.getMessage());
+                return;
+            }
+            //Get converter and convert
+            Factory factory = new DefaultFactory();
+            Converter converter;
+            String out = "";
+
+            try
+            {
+                converter = factory.getConverter(opts.inOS, opts.inProgram, opts.inFormat, opts.autodetect,
+                        opts.collapse, opts.gaps, opts.missing, opts.limit,
+                        opts.outOS, opts.outProgram, opts.outFormat, opts.lowerCase,
+                        opts.residueNumbers, opts.sequential, opts.match, logger.getName());
+                out = converter.convert(in.toString());
+            }
+            catch (UnsupportedOperationException ex)
+            {
+                logger.log(Level.SEVERE, ex.getMessage());
+                return;
+            }
+            catch (ParseException ex)
+            {
+                logger.log(Level.SEVERE, "Failure parsing source file:\r\n" + ex.getMessage());
+                return;
+            }
+
+            //Output to file
+            try
+            {
+                FileWriter fw = new FileWriter(opts.out);
+                fw.write(out);
+                fw.close();
+            }
+            catch (IOException ex)
+            {
+                logger.log(Level.SEVERE, "Failure writing output file:\r\n" + ex.getMessage());
+                System.err.println(ex.getMessage());
+            }
+
+        }
+    }
+}
diff --git a/alter-lib/src/cmdLine/package.html b/alter-lib/src/cmdLine/package.html
new file mode 100755
index 0000000..b235c30
--- /dev/null
+++ b/alter-lib/src/cmdLine/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    Command line interface.
+    @author Daniel Gomez Blanco
+    @version 1.0
+  </body>
+</html>
diff --git a/alter-lib/src/converter/Converter.java b/alter-lib/src/converter/Converter.java
new file mode 100755
index 0000000..d7a5a13
--- /dev/null
+++ b/alter-lib/src/converter/Converter.java
@@ -0,0 +1,36 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package converter;
+
+import parser.ParseException;
+
+/**
+ * Defines the only method needed to implement a converter.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+public interface Converter
+{
+    /**
+     * Takes as input a string and returns a converted string.
+     * @param in Input string.
+     * @return Converted string.
+     * @throws ParseException If an error occurs while parsing the input string.
+     */
+    public String convert(String in) throws ParseException;
+}
diff --git a/alter-lib/src/converter/DefaultConverter.java b/alter-lib/src/converter/DefaultConverter.java
new file mode 100755
index 0000000..dcf0c2c
--- /dev/null
+++ b/alter-lib/src/converter/DefaultConverter.java
@@ -0,0 +1,101 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package converter;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import parser.ParseException;
+import reader.Reader;
+import types.MSA;
+import writer.Writer;
+
+/**
+ * Implements the default converter.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+public class DefaultConverter implements Converter
+{
+    /**
+     * Collapse sequences to haplotypes.
+     */
+    private boolean collapse;
+    /**
+     * Treat gaps as missing characters when collapsing.
+     */
+    private boolean gapsAsMissing;
+    /**
+     * Count missing characters as differences when collapsing.
+     */
+    private boolean countMissing;
+    /**
+     * Connection limit (sequences differing at <= l sites will be collapsed) (default is l=0).
+     */
+    private int limit;
+    /**
+     * Logger to register information messages.
+     */
+    private Logger logger;
+    /**
+     * Reader to parse the input MSA.
+     */
+    private Reader reader;
+    /**
+     * Writer to output the converted MSA.
+     */
+    private Writer writer;
+
+    /**
+     * Class constructor
+     * @param reader Reader to parse the input MSA.
+     * @param writer Writer to output the converted MSA.
+     * @param collapse Collapse sequences to haplotypes.
+     * @param gapsAsMissing Treat gaps as missing characters when collapsing.
+     * @param countMissing Count missing characters as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed) (default is l=0).
+     * @param logger Name of the logger to instantiate.
+     */
+    public DefaultConverter(Reader reader, Writer writer, boolean collapse, boolean gapsAsMissing, boolean countMissing, int limit, String logger)
+    {
+        this.reader = reader;
+        this.writer = writer;
+        this.collapse = collapse;
+        this.gapsAsMissing = gapsAsMissing;
+        this.countMissing = countMissing;
+        this.limit = limit;
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Takes as input a string and returns a converted string.
+     * @param in Input string.
+     * @return Converted string.
+     * @throws ParseException If an error occurs while parsing the input string.
+     */
+    public String convert(String in) throws ParseException
+    {
+        MSA msa = reader.read(in);
+        if (collapse)
+        {
+            logger.log(Level.INFO,"*** haplotype collapse begin ***");
+            msa = msa.collapse(gapsAsMissing, countMissing, limit, logger.getName());
+            logger.log(Level.INFO,"*** haplotype collapse end ***");
+        }
+        return writer.write(msa);
+    }
+}
diff --git a/alter-lib/src/converter/DefaultFactory.java b/alter-lib/src/converter/DefaultFactory.java
new file mode 100755
index 0000000..d9ebe98
--- /dev/null
+++ b/alter-lib/src/converter/DefaultFactory.java
@@ -0,0 +1,458 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package converter;
+
+import reader.*;
+import writer.*;
+
+/**
+ * Implements the default factory for converters.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+public class DefaultFactory implements Factory
+{
+
+    /**
+     * Returns an adequate converter for the specified options.
+     * @param inO Input operating system.
+     * @param inP Input program.
+     * @param inF Input format.
+     * @param autodetect Format autodetection.
+     * @param collapse Collapse sequences to haplotypes.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @param outO Output operating system.
+     * @param outP Output program.
+     * @param outF Output format.
+     * @param lowerCase Lower case output.
+     * @param resNumbers Output residue numbers (only ALN format).
+     * @param sequential Sequential output (only NEXUS and PHYLIP formats).
+     * @param match Output match characters.
+     * @param logger Name of the logger to instantiate.
+     * @return Adequate converter for the specified options.
+     * @throws UnsupportedOperationException If the options combination is not possible.
+     */
+    public Converter getConverter(String inO, String inP, String inF, boolean autodetect,
+            boolean collapse, boolean gapsAsMissing, boolean countMissing, int limit,
+            String outO, String outP, String outF,
+            boolean lowerCase, boolean resNumbers, boolean sequential, boolean match,
+            String logger)
+            throws UnsupportedOperationException
+    {
+        Reader reader = getReader(inO, inP, inF, autodetect, logger);
+        Writer writer = getWriter(outO, outP, outF, lowerCase, resNumbers, sequential, match, logger);
+
+        return new DefaultConverter(reader, writer, collapse, gapsAsMissing, countMissing, limit, logger);
+    }
+
+    /**
+     * Returns an adequate reader for the specified input options.
+     * @param inO Input operating system.
+     * @param inP Input program.
+     * @param inF Input format.
+     * @param autodetect Format autodetection.
+     * @param logger Name of the logger to instantiate.
+     * @return Adequate reader for the specified input options.
+     * @throws UnsupportedOperationException If the options combination is not possible.
+     */
+    public Reader getReader(String inO, String inP, String inF, boolean autodetect, String logger)
+            throws UnsupportedOperationException
+    {
+        Reader reader;
+
+        if (autodetect)
+            reader = new AutodetectionReader(logger);
+        else if (inO.toLowerCase().equals("windows") || inO.toLowerCase().equals("linux") || inO.toLowerCase().equals("macos"))
+            if (inP.toLowerCase().equals("clustal"))
+                if (inF.toLowerCase().equals("aln"))
+                    reader = new AlnReader(logger);
+                else if (inF.toLowerCase().equals("fasta"))
+                    reader = new FastaReader(logger);
+                else if (inF.toLowerCase().equals("gde"))
+                    reader = new GdeReader(logger);
+                else if (inF.toLowerCase().equals("msf"))
+                    reader = new MsfReader(logger);
+                else if (inF.toLowerCase().equals("nexus"))
+                    reader = new NexusReader(logger);
+                else if (inF.toLowerCase().equals("phylip"))
+                    reader = new PhylipReader(logger);
+                else if (inF.toLowerCase().equals("pir"))
+                    reader = new PirReader(logger);
+                else
+                    throw new UnsupportedOperationException("Input format " + inF + " not supported by Clustal.");
+            else if (inP.toLowerCase().equals("mafft"))
+                if (inF.toLowerCase().equals("aln"))
+                    reader = new AlnReader(logger);
+                else if (inF.toLowerCase().equals("fasta"))
+                    reader = new FastaReader(logger);
+                else
+                    throw new UnsupportedOperationException("Input format " + inF + " not supported by Mafft.");
+            else if (inP.toLowerCase().equals("tcoffee"))
+                if (inF.toLowerCase().equals("aln"))
+                    reader = new AlnReader(logger);
+                else if (inF.toLowerCase().equals("fasta"))
+                    reader = new FastaReader(logger);
+                else if (inF.toLowerCase().equals("msf"))
+                    reader = new MsfReader(logger);
+                else if (inF.toLowerCase().equals("phylip"))
+                    reader = new PhylipReader(logger);
+                else if (inF.toLowerCase().equals("pir"))
+                    reader = new PirReader(logger);
+                else
+                    throw new UnsupportedOperationException("Input format " + inF + " not supported by TCoffee.");
+            else if (inP.toLowerCase().equals("muscle"))
+                if (inF.toLowerCase().equals("aln"))
+                    reader = new AlnReader(logger);
+                else if (inF.toLowerCase().equals("fasta"))
+                    reader = new FastaReader(logger);
+                else if (inF.toLowerCase().equals("msf"))
+                    reader = new MsfReader(logger);
+                else if (inF.toLowerCase().equals("phylip"))
+                    reader = new PhylipReader(logger);
+                else
+                    throw new UnsupportedOperationException("Input format " + inF + " not supported by MUSCLE.");
+            else if (inP.toLowerCase().equals("probcons"))
+                if (inF.toLowerCase().equals("aln"))
+                    reader = new AlnReader(logger);
+                else if (inF.toLowerCase().equals("fasta"))
+                    reader = new FastaReader(logger);
+                else
+                    throw new UnsupportedOperationException("Input format " + inF + " not supported by PROBCONS.");
+            else
+                throw new UnsupportedOperationException("Input program " + inP + " not supported.");
+        else
+            throw new UnsupportedOperationException("Input operating system " + inO + " not supported.");
+
+        return reader;
+
+    }
+
+    /**
+     * Returns an adequate writer for the specified output options.
+     * @param outO Output operating system.
+     * @param outP Output program.
+     * @param outF Output format.
+     * @param lowerCase Lower case output.
+     * @param resNumbers Output residue numbers (only ALN format).
+     * @param sequential Sequential output (only NEXUS and PHYLIP formats).
+     * @param match Output match characters.
+     * @param logger Name of the logger to instantiate.
+     * @return Adequate writer for the specified output options.
+     * @throws UnsupportedOperationException If the options combination is not possible.
+     */
+    public Writer getWriter(String outO, String outP, String outF,
+            boolean lowerCase, boolean resNumbers, boolean sequential, boolean match,
+            String logger)
+            throws UnsupportedOperationException
+    {
+        Writer writer;
+
+        if (outO.toLowerCase().equals("windows") || outO.toLowerCase().equals("linux") || outO.toLowerCase().equals("macos"))
+            if (outP.toLowerCase().equals("jmodeltest"))
+                if (outF.toLowerCase().equals("aln"))
+                    writer = new AlnJModelTestWriter(outO.toLowerCase(), lowerCase, resNumbers, match, logger);
+                else if (outF.toLowerCase().equals("fasta"))
+                    writer = new FastaJModelTestWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("msf"))
+                    writer = new MsfJModelTestWriter(outO.toLowerCase(), lowerCase, logger);
+                else if (outF.toLowerCase().equals("nexus"))
+                    writer = new NexusJModelTestWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipJModelTestWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("pir"))
+                    writer = new PirJModelTestWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by jModeltest.");
+            else if (outP.toLowerCase().equals("prottest"))
+                if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipProtTestWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("nexus"))
+                    if (sequential)
+                        writer = new NexusProtTestWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Interleaved NEXUS not supported by ProtTest.");
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by ProtTest.");
+            else if (outP.toLowerCase().equals("paml"))
+                if (outF.toLowerCase().equals("nexus"))
+                    if (sequential)
+                        writer = new NexusWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Interleaved NEXUS not supported by PAML.");
+                else if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipPAMLWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by PAML.");
+            else if (outP.toLowerCase().equals("phyml"))
+                if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipPhyMLWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by PhyML.");
+            else if (outP.toLowerCase().equals("paup"))
+                if (outF.toLowerCase().equals("mega"))
+                    writer = new MegaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("msf"))
+                    writer = new MsfWriter(outO.toLowerCase(), lowerCase, logger);
+                else if (outF.toLowerCase().equals("nexus"))
+                    writer = new NexusWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("pir"))
+                    writer = new PirWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by PAUP.");
+            else if (outP.toLowerCase().equals("raxml"))
+                if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipRAxMLWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by RAxML.");
+            else if (outP.toLowerCase().equals("mrbayes"))
+                if (match)
+                    throw new UnsupportedOperationException("Match first not supported by MrBayes.");
+                else
+                    if (outF.toLowerCase().equals("nexus"))
+                        writer = new NexusMrBayesWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Output format " + outF + " not supported by MrBayes.");
+            else if (outP.toLowerCase().equals("tcs"))
+                if (outF.toLowerCase().equals("nexus"))
+                    if (sequential)
+                        writer = new NexusTCSWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Interleaved NEXUS not supported by TCS.");
+                else if (outF.toLowerCase().equals("phylip"))
+                    if (sequential)
+                        writer = new PhylipTCSWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Interleaved PHYLIP not supported by TCS.");
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by TCS.");
+            else if (outP.toLowerCase().equals("codabc"))
+                if (outF.toLowerCase().equals("phylip"))
+                    if (sequential)
+                        writer = new PhylipCodABCWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Interleaved PHYLIP not supported by CodABC.");
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by CodABC.");
+            else if (outP.toLowerCase().equals("bioedit"))
+                if (outF.toLowerCase().equals("aln"))
+                    writer = new AlnWriter(outO.toLowerCase(), lowerCase, resNumbers, match, logger);
+                else if (outF.toLowerCase().equals("fasta"))
+                    writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("msf"))
+                    writer = new MsfWriter(outO.toLowerCase(), lowerCase, logger);
+                else if (outF.toLowerCase().equals("nexus"))
+                    writer = new NexusWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipBioEditWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("pir"))
+                    writer = new PirWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by BioEdit.");
+            else if (outP.toLowerCase().equals("mega"))
+                if (outF.toLowerCase().equals("aln"))
+                    writer = new AlnWriter(outO.toLowerCase(), lowerCase, resNumbers, match, logger);
+                else if (outF.toLowerCase().equals("fasta"))
+                    writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("mega"))
+                    writer = new MegaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("msf"))
+                    writer = new MsfMegaWriter(outO.toLowerCase(), lowerCase, logger);
+                else if (outF.toLowerCase().equals("nexus"))
+                    if (sequential)
+                        throw new UnsupportedOperationException("Sequential NEXUS not supported by MEGA.");
+                    else
+                        writer = new NexusWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipMegaWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("pir"))
+                    writer = new PirWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by MEGA.");
+            else if (outP.toLowerCase().equals("dnasp"))
+                if (outF.toLowerCase().equals("fasta"))
+                    writer = new FastaDnaSPWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("mega"))
+                    writer = new MegaDnaSPWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("nexus"))
+                    if (!match)
+                        writer = new NexusDnaSPWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Match first not supported by NEXUS for dnaSP.");
+                else if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipDnaSPWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("pir"))
+                    writer = new PirDnaSPWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by dnaSP.");
+            else if (outP.toLowerCase().equals("se-al"))
+                if (outF.toLowerCase().equals("fasta"))
+                    writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("gde"))
+                    writer = new GdeSeAlWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("msf"))
+                    writer = new MsfWriter(outO.toLowerCase(), lowerCase, logger);
+                else if (outF.toLowerCase().equals("nexus"))
+                    writer = new NexusWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("pir"))
+                    writer = new PirWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by Se-Al.");
+            else if (outP.toLowerCase().equals("mesquite"))
+                if (outF.toLowerCase().equals("nexus"))
+                    writer = new NexusMesquiteWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by Mesquite.");
+            else if (outP.toLowerCase().equals("splitstree"))
+                if (match)
+                    throw new UnsupportedOperationException("Match first not supported by SplitsTree.");
+                else
+                    if (outF.toLowerCase().equals("aln"))
+                        writer = new AlnWriter(outO.toLowerCase(), lowerCase, resNumbers, match, logger);
+                    else if (outF.toLowerCase().equals("fasta"))
+                        writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                    else if (outF.toLowerCase().equals("nexus"))
+                        writer = new NexusSplitsTreeWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else if (outF.toLowerCase().equals("phylip"))
+                        writer = new PhylipSplitsTreeWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Output format " + outF + " not supported by SplitsTree.");
+            else if (outP.toLowerCase().equals("clustal"))
+                if (match)
+                    throw new UnsupportedOperationException("Match first not supported by Clustal.");
+                else
+                    if (outF.toLowerCase().equals("aln"))
+                        writer = new AlnWriter(outO.toLowerCase(), lowerCase, resNumbers, match, logger);
+                    else if (outF.toLowerCase().equals("fasta"))
+                        writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                    else if (outF.toLowerCase().equals("gde"))
+                        writer = new GdeWriter(outO.toLowerCase(), lowerCase, match, logger);
+                    else if (outF.toLowerCase().equals("msf"))
+                        writer = new MsfWriter(outO.toLowerCase(), lowerCase, logger);
+                    else if (outF.toLowerCase().equals("pir"))
+                        writer = new PirWriter(outO.toLowerCase(), lowerCase, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Output format " + outF + " not supported by Clustal.");
+            else if (outP.toLowerCase().equals("mafft"))
+                if (match)
+                    throw new UnsupportedOperationException("Match first not supported by MAFFT.");
+                else
+                    if (outF.toLowerCase().equals("fasta"))
+                        writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Output format " + outF + " not supported by MAFFT.");
+            else if (outP.toLowerCase().equals("tcoffee"))
+                if (match)
+                    throw new UnsupportedOperationException("Match first not supported by TCoffee.");
+                else
+                    if (outF.toLowerCase().equals("aln"))
+                        writer = new AlnWriter(outO.toLowerCase(), lowerCase, resNumbers, match, logger);
+                    else if (outF.toLowerCase().equals("fasta"))
+                        writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                    else if (outF.toLowerCase().equals("msf"))
+                        writer = new MsfWriter(outO.toLowerCase(), lowerCase, logger);
+                    else if (outF.toLowerCase().equals("pir"))
+                        writer = new PirWriter(outO.toLowerCase(), lowerCase, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Output format " + outF + " not supported by TCoffee.");
+            else if (outP.toLowerCase().equals("gblocks"))
+                if (!match)
+                    if (outF.toLowerCase().equals("fasta"))
+                        writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                    else if (outF.toLowerCase().equals("pir"))
+                        writer = new PirWriter(outO.toLowerCase(), lowerCase, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Output format " + outF + " not supported by Gblocks.");
+                else
+                    throw new UnsupportedOperationException("Match first not supported by Gblocks.");
+            else if (outP.toLowerCase().equals("muscle"))
+                if (outF.toLowerCase().equals("fasta"))
+                    writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by MUSCLE.");
+            else if (outP.toLowerCase().equals("probcons"))
+                if (outF.toLowerCase().equals("fasta"))
+                    writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by PROBCONS.");
+            else if (outP.toLowerCase().equals("seaview"))
+                if (outF.toLowerCase().equals("aln"))
+                    writer = new AlnWriter(outO.toLowerCase(), lowerCase, resNumbers, match, logger);
+                else if (outF.toLowerCase().equals("fasta"))
+                    writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("msf"))
+                    writer = new MsfSeaViewWriter(outO.toLowerCase(), lowerCase, logger);
+                else if (outF.toLowerCase().equals("nexus"))
+                    writer = new NexusWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("phylip"))
+                    if (!sequential)
+                        writer = new PhylipWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Sequential PHYLIP not supported by SeaView.");
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by SeaView.");
+            else if (outP.toLowerCase().equals("trimal"))
+                if (outF.toLowerCase().equals("aln"))
+                    writer = new AlnWriter(outO.toLowerCase(), lowerCase, resNumbers, match, logger);
+                else if (outF.toLowerCase().equals("fasta"))
+                    writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("mega"))
+                    writer = new MegaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("nexus"))
+                    if (!sequential)
+                        writer = new PhylipWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                    else
+                        throw new UnsupportedOperationException("Sequential NEXUS not supported by trimAl.");
+                else if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("pir"))
+                    writer = new PirWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported by trimAl.");
+            else if (outP.toLowerCase().equals("general"))
+                if (outF.toLowerCase().equals("aln"))
+                    writer = new AlnWriter(outO.toLowerCase(), lowerCase, resNumbers, match, logger);
+                else if (outF.toLowerCase().equals("fasta"))
+                    writer = new FastaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("gde"))
+                    writer = new GdeWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("mega"))
+                    writer = new MegaWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else if (outF.toLowerCase().equals("msf"))
+                    writer = new MsfWriter(outO.toLowerCase(), lowerCase, logger);
+                else if (outF.toLowerCase().equals("nexus"))
+                    writer = new NexusWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("phylip"))
+                    writer = new PhylipWriter(outO.toLowerCase(), lowerCase, sequential, match, logger);
+                else if (outF.toLowerCase().equals("pir"))
+                    writer = new PirWriter(outO.toLowerCase(), lowerCase, match, logger);
+                else
+                    throw new UnsupportedOperationException("Output format " + outF + " not supported.");
+            else
+                throw new UnsupportedOperationException("Output program " + outP + " not supported.");
+        else
+            throw new UnsupportedOperationException("Output operating system " + outO + " not supported.");
+
+        return writer;
+    }
+}
diff --git a/alter-lib/src/converter/Factory.java b/alter-lib/src/converter/Factory.java
new file mode 100755
index 0000000..601b99e
--- /dev/null
+++ b/alter-lib/src/converter/Factory.java
@@ -0,0 +1,90 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package converter;
+
+import reader.Reader;
+import writer.Writer;
+
+/**
+ * Defines the methods needed to implement a converter factory.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+public interface Factory
+{
+
+    /**
+     * Returns an adequate converter for the specified options.
+     * @param inO Input operating system.
+     * @param inP Input program.
+     * @param inF Input format.
+     * @param autodetect Format autodetection.
+     * @param collapse Collapse sequences to haplotypes.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @param outO Output operating system.
+     * @param outP Output program.
+     * @param outF Output format.
+     * @param lowerCase Lower case output.
+     * @param resNumbers Output residue numbers (only ALN format).
+     * @param sequential Sequential output (only NEXUS and PHYLIP formats).
+     * @param match Output match characters.
+     * @param logger Name of the logger to instantiate.
+     * @return Adequate converter for the specified options.
+     * @throws UnsupportedOperationException If the options combination is not possible.
+     */
+    public Converter getConverter(String inO, String inP, String inF, boolean autodetect,
+            boolean collapse, boolean gapsAsMissing, boolean countMissing, int limit,
+            String outO, String outP, String outF,
+            boolean lowerCase, boolean resNumbers, boolean sequential, boolean match,
+            String logger)
+            throws UnsupportedOperationException;
+
+    /**
+     * Returns an adequate reader for the specified input options.
+     * @param inO Input operating system.
+     * @param inP Input program.
+     * @param inF Input format.
+     * @param autodetect Format autodetection.
+     * @param logger Name of the logger to instantiate.
+     * @return Adequate reader for the specified input options.
+     * @throws UnsupportedOperationException If the options combination is not possible.
+     */
+    public Reader getReader(String inO, String inP, String inF, boolean autodetect,
+            String logger)
+            throws UnsupportedOperationException;
+
+    /**
+     * Returns an adequate writer for the specified output options.
+     * @param outO Output operating system.
+     * @param outP Output program.
+     * @param outF Output format.
+     * @param lowerCase Lower case output.
+     * @param resNumbers Output residue numbers (only ALN format).
+     * @param sequential Sequential output (only NEXUS and PHYLIP formats).
+     * @param match Output match characters.
+     * @param logger Name of the logger to instantiate.
+     * @return Adequate writer for the specified output options.
+     * @throws UnsupportedOperationException If the options combination is not possible.
+     */
+    public Writer getWriter(String outO, String outP, String outF,
+            boolean lowerCase, boolean resNumbers, boolean sequential, boolean match,
+            String logger)
+            throws UnsupportedOperationException;
+}
diff --git a/alter-lib/src/converter/ProgramOptions.java b/alter-lib/src/converter/ProgramOptions.java
new file mode 100644
index 0000000..6070efa
--- /dev/null
+++ b/alter-lib/src/converter/ProgramOptions.java
@@ -0,0 +1,409 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package converter;
+
+import java.util.*;
+
+/**
+ * Provides methods to check the supported programs and formats, as well as
+ * the possible options for each one of them.
+ * @author Daniel Gonzalez Peña
+ */
+public class ProgramOptions{
+
+  /**
+   * Supported operating systems.
+   * @return List of strings containing the supported operating systems.
+   */
+  public static List<String> getSO(){
+    List<String> so = new LinkedList<String>();
+    so.add("windows");
+    so.add("linux");
+    so.add("macos");
+    return so;
+
+  }
+
+  /**
+   * Supported input programs.
+   * @return List of strings containing the supported input programs.
+   */
+  public static List<String> getInputPrograms(){
+    List<String> in_programs = new LinkedList<String>();
+    in_programs.add("clustal");
+    in_programs.add("mafft");
+    in_programs.add("tcoffee");
+    in_programs.add("muscle");
+    in_programs.add("probcons");
+    return in_programs;
+  }
+
+  /**
+   * Supported input formats.
+   * @return List of strings containing the supported input formats.
+   */
+  public static List<String> getInputFormats(){
+    List<String> in_formats = new LinkedList<String>();
+    in_formats.add("aln");
+    in_formats.add("fasta");
+    in_formats.add("gde");
+    in_formats.add("msf");
+    in_formats.add("nexus");
+    in_formats.add("phylip");
+    in_formats.add("pir");
+    return in_formats;
+  }
+
+  /**
+   * Supported output programs.
+   * @return List of strings containing the supported output programs.
+   */
+  public static List<String> getOutputPrograms(){
+    List<String> out_programs = new LinkedList<String>();
+    out_programs.add("general");
+    out_programs.add("jmodeltest");
+    out_programs.add("mrbayes");
+    out_programs.add("paml");
+    out_programs.add("paup");
+    out_programs.add("phyml");
+    out_programs.add("prottest");
+    out_programs.add("raxml");
+    out_programs.add("tcs");
+    out_programs.add("bioedit");
+    out_programs.add("se-al");
+    out_programs.add("mega");
+    out_programs.add("mesquite");
+    out_programs.add("splitstree");
+    out_programs.add("dnasp");
+    out_programs.add("codabc");
+    out_programs.add("clustal");
+    out_programs.add("mafft");
+    out_programs.add("muscle");
+    out_programs.add("probcons");
+    out_programs.add("tcoffee");
+    out_programs.add("gblocks");
+    out_programs.add("seaview");
+    out_programs.add("trimal");
+    return out_programs;
+  }
+
+  /**
+   * Supported output formats.
+   * @return List of strings containing the supported output formats.
+   */
+  public static List<String> getOutputFormats(){
+    List<String> out_formats = new LinkedList<String>();
+    out_formats.add("aln");
+    out_formats.add("fasta");
+    out_formats.add("gde");
+    out_formats.add("mega");
+    out_formats.add("msf");
+    out_formats.add("nexus");
+    out_formats.add("phylip");
+    out_formats.add("pir");
+    return out_formats;
+  }
+
+  /**
+   * Supported output options.
+   * @return List of strings containing the supported output options.
+   */
+  public static List<String> getOutOptions(){
+    List<String> out_options = new LinkedList<String>();
+    out_options.add("sequential");
+    out_options.add("interleaved");
+    out_options.add("lowercase");
+    out_options.add("match");
+    out_options.add("residue");
+
+    return out_options;
+  }
+
+  /**
+   * Supported formats depending on the input program.
+   * @param program Input program.
+   * @return List of strings containing the supported input formats.
+   */
+  public static List<String> getInputProgramFormats(String program){
+    List<String> formats = new LinkedList<String>();
+    if (program.equalsIgnoreCase("clustal")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("gde");
+      formats.add("msf");
+      formats.add("nexus");
+      formats.add("phylip");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("mafft")){
+      formats.add("aln");
+      formats.add("fasta");
+    }else if (program.equalsIgnoreCase("tcoffee")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("msf");
+      formats.add("phylip");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("muscle")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("msf");
+      formats.add("phylip");
+    }else if (program.equalsIgnoreCase("probcons")){
+      formats.add("aln");
+      formats.add("fasta");
+    }else{
+      throw new IllegalArgumentException("Input program not found: "+program);
+    }
+    return formats;
+  }
+
+  /**
+   * Supported formats depending on the output program.
+   * @param program Output program.
+   * @return List of strings containing the supported output formats.
+   */
+  public static List<String> getOutputProgramFormats(String program){
+    List<String> formats = new LinkedList<String>();
+    if (program.equalsIgnoreCase("jmodeltest")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("msf");
+      formats.add("nexus");
+      formats.add("phylip");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("mrbayes")){
+      formats.add("nexus");
+    }else if (program.equalsIgnoreCase("paml")){
+      formats.add("nexus");
+      formats.add("phylip");
+    }else if (program.equalsIgnoreCase("paup")){
+      formats.add("mega");
+      formats.add("msf");
+      formats.add("nexus");
+      formats.add("phylip");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("phyml")){
+      formats.add("phylip");
+    }else if (program.equalsIgnoreCase("prottest")){
+      formats.add("nexus");
+      formats.add("phylip");
+    }else if (program.equalsIgnoreCase("raxml")){
+      formats.add("phyplip");
+    }else if (program.equalsIgnoreCase("tcs")){
+      formats.add("nexus");
+      formats.add("phylip");
+    }else if (program.equalsIgnoreCase("codabc")){
+      formats.add("phylip");
+    }else if (program.equalsIgnoreCase("bioedit")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("msf");
+      formats.add("nexus");
+      formats.add("phylip");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("se-al")){
+      formats.add("fasta");
+      formats.add("gde");
+      formats.add("nexus");
+      formats.add("phylip");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("mega")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("mega");
+      formats.add("msf");
+      formats.add("nexus");
+      formats.add("phylip");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("mesquite")){
+      formats.add("nexus");
+    }else if (program.equalsIgnoreCase("splitstree")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("nexus");
+      formats.add("phylip");
+    }else if (program.equalsIgnoreCase("dnasp")){
+      formats.add("fasta");
+      formats.add("mega");
+      formats.add("nexus");
+      formats.add("phylip");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("clustal")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("gde");
+      formats.add("msf");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("mafft")){
+      formats.add("fasta");
+    }else if (program.equalsIgnoreCase("muscle")){
+      formats.add("fasta");
+    }else if (program.equalsIgnoreCase("probcons")){
+      formats.add("fasta");
+    }else if (program.equalsIgnoreCase("tcoffee")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("msf");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("gblocks")){
+      formats.add("fasta");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("seaview")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("msf");
+      formats.add("nexus");
+      formats.add("phylip");
+    }else if (program.equalsIgnoreCase("trimal")){
+      formats.add("aln");
+      formats.add("fasta");
+      formats.add("mega");
+      formats.add("nexus");
+      formats.add("phylip");
+      formats.add("pir");
+    }else if (program.equalsIgnoreCase("general")){
+      formats.addAll(getOutputFormats());
+    }else{
+      throw new IllegalArgumentException("Output program not found: "+program);
+    }
+    return formats;
+  }
+
+  /**
+   * Possible options depending on output program and format.
+   * @param program Output program.
+   * @param format Output format.
+   * @return
+   */
+  public static List<String> getOutputProgramOptions(String program, String format){
+    List<String> options = new LinkedList<String>();
+    if (!getOutputPrograms().contains(program)){
+      throw new IllegalArgumentException("Output program not found: "+program);
+    }
+    if (!getOutputFormats().contains(format)){
+      throw new IllegalArgumentException("Output format not found: "+format);
+    }
+    if (!getOutputProgramFormats(program).contains(format)){
+      throw new IllegalArgumentException("Output Program "+program+" does not work with "+format+" format");
+    }
+
+
+    //Almost all programs work with lowercase and match
+    options.add("lowercase");
+    options.add("match");
+
+    if (program.equalsIgnoreCase("mrbayes")){
+      options.remove("match");
+    }else if (program.equalsIgnoreCase("splitstree")){
+      options.remove("match");
+    }else if (program.equalsIgnoreCase("dnasp") && format.equalsIgnoreCase("nexus")){
+      options.remove("match");
+    }else if (program.equalsIgnoreCase("clustal")){
+      options.remove("match");
+    }else if (program.equalsIgnoreCase("mafft")){
+      options.remove("match");
+    }else if (program.equalsIgnoreCase("tcoffee")){
+      options.remove("match");
+    }else if (program.equalsIgnoreCase("gblocks")){
+      options.remove("match");
+    }
+
+    //All programs accepting ALN accept residue
+    if (format.equalsIgnoreCase("aln")){
+      options.add("residue");
+    }
+
+    if(format.equalsIgnoreCase("nexus")){
+      options.add("sequential");
+      if (program.equalsIgnoreCase("phyml")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("raxml")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("mega")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("clustal")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("mafft")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("tcoffee")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("trimal")){
+	options.remove("sequential");
+      }
+
+      options.add("interleaved");
+      if (program.equalsIgnoreCase("paml")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("phyml")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("prottest")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("raxml")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("tcs")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("codabc")){
+        options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("clustal")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("mafft")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("tcoffee")){
+	options.remove("interleaved");
+      }
+    }
+
+    if(format.equalsIgnoreCase("phylip")){
+      options.add("sequential");
+      if (program.equalsIgnoreCase("mrbayes")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("mesquite")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("clustal")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("mafft")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("tcoffee")){
+	options.remove("sequential");
+      } else if (program.equalsIgnoreCase("seaview")){
+	options.remove("sequential");
+      }
+
+      options.add("interleaved");
+      if (program.equalsIgnoreCase("mrbayes")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("tcs")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("codabc")){
+        options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("mesquite")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("clustal")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("mafft")){
+	options.remove("interleaved");
+      } else if (program.equalsIgnoreCase("tcoffee")){
+	options.remove("interleaved");
+      }
+    }
+    return options;
+  }
+
+
+
+}
diff --git a/alter-lib/src/converter/package.html b/alter-lib/src/converter/package.html
new file mode 100755
index 0000000..899ff0a
--- /dev/null
+++ b/alter-lib/src/converter/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    Converter factory.
+    @author Daniel Gomez Blanco
+    @version 1.1
+  </body>
+</html>
diff --git a/alter-lib/src/gui/ConvertPanel.form b/alter-lib/src/gui/ConvertPanel.form
new file mode 100755
index 0000000..980c095
--- /dev/null
+++ b/alter-lib/src/gui/ConvertPanel.form
@@ -0,0 +1,428 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <Properties>
+    <Property name="name" type="java.lang.String" value="Convert MSA" noResource="true"/>
+  </Properties>
+  <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="inputPanel" alignment="0" max="32767" attributes="1"/>
+          <Component id="outputPanel" alignment="0" max="32767" attributes="1"/>
+          <Component id="collapsePanel" 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="inputPanel" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="collapsePanel" min="-2" max="-2" attributes="0"/>
+              <EmptySpace max="-2" attributes="0"/>
+              <Component id="outputPanel" min="-2" max="-2" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="inputPanel">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
+            <TitledBorder title="Input"/>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" attributes="0">
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" attributes="0">
+                          <Component id="inputOSLabel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="inputOS" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                          <Component id="inputProgramLabel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="inputProgram" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                          <Component id="inputFormatLabel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="inputFormat" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <Component id="inputAutodetect" alignment="0" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace pref="29" max="32767" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" attributes="0">
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="inputOSLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="inputOS" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="inputProgramLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="inputProgram" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="inputFormatLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="inputFormat" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace pref="7" max="32767" attributes="0"/>
+                  <Component id="inputAutodetect" min="-2" max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JComboBox" name="inputOS">
+          <Properties>
+            <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+              <StringArray count="3">
+                <StringItem index="0" value="Linux"/>
+                <StringItem index="1" value="MacOS"/>
+                <StringItem index="2" value="Windows"/>
+              </StringArray>
+            </Property>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="inputOSLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="OS"/>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="inputProgramLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Program"/>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JComboBox" name="inputProgram">
+          <Properties>
+            <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+              <StringArray count="5">
+                <StringItem index="0" value="Clustal"/>
+                <StringItem index="1" value="MAFFT"/>
+                <StringItem index="2" value="MUSCLE"/>
+                <StringItem index="3" value="PROBCONS"/>
+                <StringItem index="4" value="TCoffee"/>
+              </StringArray>
+            </Property>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="inputProgramActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JLabel" name="inputFormatLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Format"/>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JComboBox" name="inputFormat">
+          <Properties>
+            <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+              <StringArray count="7">
+                <StringItem index="0" value="ALN"/>
+                <StringItem index="1" value="FASTA"/>
+                <StringItem index="2" value="GDE"/>
+                <StringItem index="3" value="MSF"/>
+                <StringItem index="4" value="NEXUS"/>
+                <StringItem index="5" value="PHYLIP"/>
+                <StringItem index="6" value="PIR"/>
+              </StringArray>
+            </Property>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JCheckBox" name="inputAutodetect">
+          <Properties>
+            <Property name="selected" type="boolean" value="true"/>
+            <Property name="text" type="java.lang.String" value="Autodetect"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="inputAutodetectActionPerformed"/>
+          </Events>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="outputPanel">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
+            <TitledBorder title="Output"/>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <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">
+                      <Group type="102" alignment="0" attributes="0">
+                          <Component id="outputOSLabel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="outputOS" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                          <Component id="outputProgramLabel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="outputProgram" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                          <Component id="outputFormatLabel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="outputFormat" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <Group type="102" alignment="0" attributes="0">
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Component id="outputResidueNumbers" alignment="0" min="-2" max="-2" attributes="0"/>
+                              <Component id="outputLowerCase" alignment="0" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Group type="103" groupAlignment="0" attributes="0">
+                              <Component id="outputMatch" alignment="0" min="-2" max="-2" attributes="0"/>
+                              <Component id="outputSequential" alignment="0" min="-2" max="-2" attributes="0"/>
+                          </Group>
+                      </Group>
+                  </Group>
+                  <EmptySpace pref="28" max="32767" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="outputOSLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="outputOS" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="outputProgramLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="outputProgram" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="outputFormatLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="outputFormat" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="outputLowerCase" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="outputMatch" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="outputResidueNumbers" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="outputSequential" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JLabel" name="outputProgramLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Program"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JComboBox" name="outputProgram">
+          <Properties>
+            <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+              <StringArray count="23">
+                <StringItem index="0" value="GENERAL"/>
+                <StringItem index="1" value="Clustal"/>
+                <StringItem index="2" value="MAFFT"/>
+                <StringItem index="3" value="MUSCLE"/>
+                <StringItem index="4" value="PROBCONS"/>
+                <StringItem index="5" value="TCoffee"/>
+                <StringItem index="6" value="BioEdit"/>
+                <StringItem index="7" value="Se-Al"/>
+                <StringItem index="8" value="Gblocks"/>
+                <StringItem index="9" value="trimAl"/>
+                <StringItem index="10" value="jModelTest"/>
+                <StringItem index="11" value="ProtTest"/>
+                <StringItem index="12" value="MEGA"/>
+                <StringItem index="13" value="Mesquite"/>
+                <StringItem index="14" value="MrBayes"/>
+                <StringItem index="15" value="PAML"/>
+                <StringItem index="16" value="PAUP"/>
+                <StringItem index="17" value="PhyML"/>
+                <StringItem index="18" value="RAxML"/>
+                <StringItem index="19" value="SeaView"/>
+                <StringItem index="20" value="SplitsTree"/>
+                <StringItem index="21" value="TCS"/>
+                <StringItem index="22" value="dnaSP"/>
+		<StringItem index="23" value="CodABC"/>
+              </StringArray>
+            </Property>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="outputProgramActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JLabel" name="outputFormatLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Format"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JComboBox" name="outputFormat">
+          <Properties>
+            <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+              <StringArray count="8">
+                <StringItem index="0" value="ALN"/>
+                <StringItem index="1" value="FASTA"/>
+                <StringItem index="2" value="GDE"/>
+                <StringItem index="3" value="MEGA"/>
+                <StringItem index="4" value="MSF"/>
+                <StringItem index="5" value="NEXUS"/>
+                <StringItem index="6" value="PHYLIP"/>
+                <StringItem index="7" value="PIR"/>
+              </StringArray>
+            </Property>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="outputFormatActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JCheckBox" name="outputLowerCase">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Lower case"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JCheckBox" name="outputResidueNumbers">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Residue numbers"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="outputOSLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="OS"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JComboBox" name="outputOS">
+          <Properties>
+            <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor">
+              <StringArray count="3">
+                <StringItem index="0" value="Linux"/>
+                <StringItem index="1" value="MacOS"/>
+                <StringItem index="2" value="Windows"/>
+              </StringArray>
+            </Property>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JCheckBox" name="outputSequential">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Sequential"/>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JCheckBox" name="outputMatch">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Match first"/>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="collapsePanel">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
+            <TitledBorder title="Collapse"/>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" attributes="0">
+                  <EmptySpace min="-2" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" alignment="0" attributes="0">
+                          <Component id="collapse" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
+                          <Component id="collapseLimitLabel" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace min="-2" max="-2" attributes="0"/>
+                          <Component id="collapseLimit" pref="125" max="32767" attributes="0"/>
+                          <EmptySpace min="93" pref="93" max="93" attributes="0"/>
+                      </Group>
+                      <Group type="102" alignment="0" attributes="0">
+                          <Component id="collapseGaps" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace type="unrelated" max="-2" attributes="0"/>
+                          <Component id="collapseMissing" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                  </Group>
+                  <EmptySpace min="-2" max="-2" attributes="0"/>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="collapse" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="collapseLimitLabel" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="collapseLimit" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="collapseGaps" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="collapseMissing" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JCheckBox" name="collapse">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Collapse sequences to haplotypes"/>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="collapseActionPerformed"/>
+          </Events>
+        </Component>
+        <Component class="javax.swing.JCheckBox" name="collapseGaps">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Treat gaps as missing data"/>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JSpinner" name="collapseLimit">
+          <Properties>
+            <Property name="model" type="javax.swing.SpinnerModel" editor="org.netbeans.modules.form.editors2.SpinnerModelEditor">
+              <SpinnerModel initial="0" minimum="0" numberType="java.lang.Integer" stepSize="1" type="number"/>
+            </Property>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="collapseLimitLabel">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Limit"/>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JCheckBox" name="collapseMissing">
+          <Properties>
+            <Property name="selected" type="boolean" value="true"/>
+            <Property name="text" type="java.lang.String" value="Count missing data as differences"/>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/alter-lib/src/gui/ConvertPanel.java b/alter-lib/src/gui/ConvertPanel.java
new file mode 100755
index 0000000..15fe8ed
--- /dev/null
+++ b/alter-lib/src/gui/ConvertPanel.java
@@ -0,0 +1,791 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package gui;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.SwingUtilities;
+
+/**
+ * Panel that contains the conversion options.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+public class ConvertPanel extends javax.swing.JPanel
+{
+
+    /**
+     * Class constructor.
+     */
+    public ConvertPanel()
+    {
+        initComponents();
+    }
+
+    /**
+     * Returns the selected input operating system.
+     * @return Input operating system.
+     */
+    public String getInputOS()
+    {
+        return (String) inputOS.getItemAt(inputOS.getSelectedIndex());
+    }
+
+    /**
+     * Returns the selected input program.
+     * @return Input program.
+     */
+    public String getInputProgram()
+    {
+        return (String) inputProgram.getItemAt(inputProgram.getSelectedIndex());
+    }
+
+    /**
+     * Returns the selected input format.
+     * @return Input format.
+     */
+    public String getInputFormat()
+    {
+        return (String) inputFormat.getItemAt(inputFormat.getSelectedIndex());
+    }
+
+    /**
+     * Returns the state of the autodetection option.
+     * @return Autodetection checked or not.
+     */
+    public boolean getInputAutodetect()
+    {
+        return inputAutodetect.isSelected();
+    }
+
+    /**
+     * Returns the state of the collapse option.
+     * @return Collapse checked or not.
+     */
+    public boolean getCollapse()
+    {
+        return collapse.isSelected();
+    }
+
+    /**
+     * Returns the limit to collapse.
+     * @return Limit to collapse.
+     */
+    public int getCollapseLimit()
+    {
+        return ((Integer) collapseLimit.getModel().getValue()).intValue();
+    }
+
+    /**
+     * Returns the state of treat gaps as missing data.
+     * @return Treat gaps as missing data checked or not.
+     */
+    public boolean getCollapseGaps()
+    {
+        return collapseGaps.isSelected();
+    }
+
+    /**
+     * Returns the state of count missing data as differences.
+     * @return Count missing data as differences checked or not.
+     */
+    public boolean getCollapseMissing()
+    {
+        return collapseMissing.isSelected();
+    }
+    /**
+     * Returns the selected output operating system.
+     * @return Selected output operating system.
+     */
+    public String getOutputOS()
+    {
+        return (String) outputOS.getItemAt(outputOS.getSelectedIndex());
+    }
+
+    /**
+     * Returns the selected output program.
+     * @return Selected output program.
+     */
+    public String getOutputProgram()
+    {
+        return (String) outputProgram.getItemAt(outputProgram.getSelectedIndex());
+    }
+
+    /**
+     * Returns the selected output format.
+     * @return Selected output format.
+     */
+    public String getOutputFormat()
+    {
+        return (String) outputFormat.getItemAt(outputFormat.getSelectedIndex());
+    }
+
+    /**
+     * Returns the state of lowercase output.
+     * @return Lowercase output checked or not.
+     */
+    public boolean getOutputLowerCase()
+    {
+        return outputLowerCase.isSelected();
+    }
+
+    /**
+     * Returns the state of output residue numbers.
+     * @return Output residue numbers checked or not.
+     */
+    public boolean getOutputResidueNumbers()
+    {
+        return outputResidueNumbers.isSelected();
+    }
+
+    /**
+     * Returns the state of sequential output.
+     * @return Sequential output checked or not.
+     */
+    public boolean getOutputSequential()
+    {
+        return outputSequential.isSelected();
+    }
+
+    /**
+     * Returns the state of output match characters.
+     * @return Output match characters checked or not.
+     */
+    public boolean getOutputMatch()
+    {
+        return outputMatch.isSelected();
+    }
+
+    /** Method called in the constructor to initialize components.
+     * This method was created by Netbeans IDE and it's not meant to be modified.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        inputPanel = new javax.swing.JPanel();
+        inputOS = new javax.swing.JComboBox();
+        inputOSLabel = new javax.swing.JLabel();
+        inputProgramLabel = new javax.swing.JLabel();
+        inputProgram = new javax.swing.JComboBox();
+        inputFormatLabel = new javax.swing.JLabel();
+        inputFormat = new javax.swing.JComboBox();
+        inputAutodetect = new javax.swing.JCheckBox();
+        outputPanel = new javax.swing.JPanel();
+        outputProgramLabel = new javax.swing.JLabel();
+        outputProgram = new javax.swing.JComboBox();
+        outputFormatLabel = new javax.swing.JLabel();
+        outputFormat = new javax.swing.JComboBox();
+        outputLowerCase = new javax.swing.JCheckBox();
+        outputResidueNumbers = new javax.swing.JCheckBox();
+        outputOSLabel = new javax.swing.JLabel();
+        outputOS = new javax.swing.JComboBox();
+        outputSequential = new javax.swing.JCheckBox();
+        outputMatch = new javax.swing.JCheckBox();
+        collapsePanel = new javax.swing.JPanel();
+        collapse = new javax.swing.JCheckBox();
+        collapseGaps = new javax.swing.JCheckBox();
+        collapseLimit = new javax.swing.JSpinner();
+        collapseLimitLabel = new javax.swing.JLabel();
+        collapseMissing = new javax.swing.JCheckBox();
+
+        setName("Convert MSA"); // NOI18N
+
+        inputPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Input"));
+
+        inputOS.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Linux", "MacOS", "Windows" }));
+        inputOS.setEnabled(false);
+
+        inputOSLabel.setText("OS");
+        inputOSLabel.setEnabled(false);
+
+        inputProgramLabel.setText("Program");
+        inputProgramLabel.setEnabled(false);
+
+        inputProgram.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Clustal", "MAFFT", "MUSCLE", "PROBCONS", "TCoffee" }));
+        inputProgram.setEnabled(false);
+        inputProgram.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                inputProgramActionPerformed(evt);
+            }
+        });
+
+        inputFormatLabel.setText("Format");
+        inputFormatLabel.setEnabled(false);
+
+        inputFormat.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "ALN", "FASTA", "GDE", "MSF", "NEXUS", "PHYLIP", "PIR" }));
+        inputFormat.setEnabled(false);
+
+        inputAutodetect.setSelected(true);
+        inputAutodetect.setText("Autodetect");
+        inputAutodetect.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                inputAutodetectActionPerformed(evt);
+            }
+        });
+
+        javax.swing.GroupLayout inputPanelLayout = new javax.swing.GroupLayout(inputPanel);
+        inputPanel.setLayout(inputPanelLayout);
+        inputPanelLayout.setHorizontalGroup(
+            inputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(inputPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(inputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(inputPanelLayout.createSequentialGroup()
+                        .addComponent(inputOSLabel)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(inputOS, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(inputProgramLabel)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(inputProgram, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(inputFormatLabel)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(inputFormat, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addComponent(inputAutodetect))
+                .addContainerGap(29, Short.MAX_VALUE))
+        );
+        inputPanelLayout.setVerticalGroup(
+            inputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(inputPanelLayout.createSequentialGroup()
+                .addGroup(inputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(inputOSLabel)
+                    .addComponent(inputOS, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(inputProgramLabel)
+                    .addComponent(inputProgram, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(inputFormatLabel)
+                    .addComponent(inputFormat, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 7, Short.MAX_VALUE)
+                .addComponent(inputAutodetect))
+        );
+
+        outputPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Output"));
+
+        outputProgramLabel.setText("Program");
+
+        outputProgram.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "GENERAL", "Clustal", "MAFFT", "MUSCLE", "PROBCONS", "TCoffee", "BioEdit", "Se-Al", "Gblocks", "trimAl", "jModelTest", "ProtTest", "MEGA", "Mesquite", "MrBayes", "PAML", "PAUP", "PhyML", "RAxML", "SeaView", "SplitsTree", "TCS", "dnaSP", "CodABC" }));
+        outputProgram.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                outputProgramActionPerformed(evt);
+            }
+        });
+
+        outputFormatLabel.setText("Format");
+
+        outputFormat.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "ALN", "FASTA", "GDE", "MEGA", "MSF", "NEXUS", "PHYLIP", "PIR" }));
+        outputFormat.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                outputFormatActionPerformed(evt);
+            }
+        });
+
+        outputLowerCase.setText("Lower case");
+
+        outputResidueNumbers.setText("Residue numbers");
+
+        outputOSLabel.setText("OS");
+
+        outputOS.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Linux", "MacOS", "Windows" }));
+
+        outputSequential.setText("Sequential");
+        outputSequential.setEnabled(false);
+
+        outputMatch.setText("Match first");
+
+        javax.swing.GroupLayout outputPanelLayout = new javax.swing.GroupLayout(outputPanel);
+        outputPanel.setLayout(outputPanelLayout);
+        outputPanelLayout.setHorizontalGroup(
+            outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(outputPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(outputPanelLayout.createSequentialGroup()
+                        .addComponent(outputOSLabel)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(outputOS, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(outputProgramLabel)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(outputProgram, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(outputFormatLabel)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(outputFormat, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addGroup(outputPanelLayout.createSequentialGroup()
+                        .addGroup(outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(outputResidueNumbers)
+                            .addComponent(outputLowerCase))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(outputMatch)
+                            .addComponent(outputSequential))))
+                .addContainerGap(28, Short.MAX_VALUE))
+        );
+        outputPanelLayout.setVerticalGroup(
+            outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(outputPanelLayout.createSequentialGroup()
+                .addGroup(outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(outputOSLabel)
+                    .addComponent(outputOS, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(outputProgramLabel)
+                    .addComponent(outputProgram, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(outputFormatLabel)
+                    .addComponent(outputFormat, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addGroup(outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(outputLowerCase)
+                    .addComponent(outputMatch))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(outputResidueNumbers)
+                    .addComponent(outputSequential)))
+        );
+
+        collapsePanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Collapse"));
+
+        collapse.setText("Collapse sequences to haplotypes");
+        collapse.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                collapseActionPerformed(evt);
+            }
+        });
+
+        collapseGaps.setText("Treat gaps as missing data");
+        collapseGaps.setEnabled(false);
+
+        collapseLimit.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(0), Integer.valueOf(0), null, Integer.valueOf(1)));
+        collapseLimit.setEnabled(false);
+
+        collapseLimitLabel.setText("Limit");
+        collapseLimitLabel.setEnabled(false);
+
+        collapseMissing.setSelected(true);
+        collapseMissing.setText("Count missing data as differences");
+        collapseMissing.setEnabled(false);
+
+        javax.swing.GroupLayout collapsePanelLayout = new javax.swing.GroupLayout(collapsePanel);
+        collapsePanel.setLayout(collapsePanelLayout);
+        collapsePanelLayout.setHorizontalGroup(
+            collapsePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(collapsePanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(collapsePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(collapsePanelLayout.createSequentialGroup()
+                        .addComponent(collapse)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(collapseLimitLabel)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(collapseLimit, javax.swing.GroupLayout.DEFAULT_SIZE, 125, Short.MAX_VALUE)
+                        .addGap(93, 93, 93))
+                    .addGroup(collapsePanelLayout.createSequentialGroup()
+                        .addComponent(collapseGaps)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(collapseMissing)))
+                .addContainerGap())
+        );
+        collapsePanelLayout.setVerticalGroup(
+            collapsePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(collapsePanelLayout.createSequentialGroup()
+                .addGroup(collapsePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(collapse)
+                    .addComponent(collapseLimitLabel)
+                    .addComponent(collapseLimit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(collapsePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(collapseGaps)
+                    .addComponent(collapseMissing)))
+        );
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(inputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+            .addComponent(outputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+            .addComponent(collapsePanel, 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(inputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(collapsePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(outputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+    /**
+     * Updates the supported output formats depending on the selected output program.
+     * @param evt Event generated when selecting an output program.
+     */
+    private void outputProgramActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_outputProgramActionPerformed
+    {//GEN-HEADEREND:event_outputProgramActionPerformed
+        SwingUtilities.invokeLater(new Runnable()
+        {
+
+            public void run()
+            {
+                String program = (String) outputProgram.getItemAt(outputProgram.getSelectedIndex());
+                if (program.equals("GENERAL"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN", "FASTA", "GDE", "MEGA", "MSF", "NEXUS", "PHYLIP", "PIR"
+                            }));
+                else if (program.equals("jModelTest"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN","FASTA", "MSF", "NEXUS", "PHYLIP", "PIR"
+                            }));
+                else if (program.equals("MrBayes"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "NEXUS"
+                            }));
+                else if (program.equals("PAML"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "NEXUS", "PHYLIP"
+                            }));
+                else if (program.equals("PAUP"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "MEGA", "MSF", "NEXUS", "PHYLIP", "PIR"
+                            }));
+                else if (program.equals("PhyML"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "PHYLIP"
+                            }));
+                else if (program.equals("ProtTest"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "NEXUS","PHYLIP"
+                            }));
+                else if (program.equals("RAxML"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "PHYLIP"
+                            }));
+                else if (program.equals("RAxML"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "NEXUS", "PHYLIP"
+                            }));
+                else if (program.equals("TCS"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "NEXUS", "PHYLIP"
+                            }));
+                else if (program.equals("CodABC"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "PHYLIP"
+                            }));
+                else if (program.equals("BioEdit"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN","FASTA", "MSF", "NEXUS", "PHYLIP", "PIR"
+                            }));
+                else if (program.equals("MEGA"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN","FASTA", "MEGA","MSF", "NEXUS", "PHYLIP", "PIR"
+                            }));
+                else if (program.equals("dnaSP"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "FASTA", "MEGA","NEXUS", "PHYLIP", "PIR"
+                            }));
+                else if (program.equals("Se-Al"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "FASTA","GDE","NEXUS","PHYLIP","PIR"
+                            }));
+                else if (program.equals("Mesquite"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "NEXUS"
+                            }));
+                else if (program.equals("SplitsTree"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN","FASTA","NEXUS","PHYLIP"
+                            }));
+                else if (program.equals("Clustal"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN","FASTA","GDE","MSF","PIR"
+                            }));
+                else if (program.equals("MAFFT"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "FASTA"
+                            }));
+                else if (program.equals("MUSCLE"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "FASTA"
+                            }));
+                else if (program.equals("PROBCONS"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "FASTA"
+                            }));
+                else if (program.equals("TCoffee"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN","FASTA","MSF","PIR"
+                            }));
+                else if (program.equals("Gblocks"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "FASTA","PIR"
+                            }));
+                else if (program.equals("SeaView"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN","FASTA","MSF","NEXUS","PHYLIP"
+                            }));
+                else if (program.equals("trimAl"))
+                    outputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN","FASTA","MEGA","NEXUS","PHYLIP","PIR"
+                            }));
+            }
+        });
+        outputFormatActionPerformed(evt);
+    }//GEN-LAST:event_outputProgramActionPerformed
+
+    /**
+     * Updates the supported output options depending on the selected output program and format.
+     * @param evt Event generated when selecting an output format.
+     */
+    private void outputFormatActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_outputFormatActionPerformed
+    {//GEN-HEADEREND:event_outputFormatActionPerformed
+        SwingUtilities.invokeLater(new Runnable()
+        {
+            public void run()
+            {
+                String format = (String) outputFormat.getItemAt(outputFormat.getSelectedIndex());
+                String program = (String) outputProgram.getItemAt(outputProgram.getSelectedIndex());
+                
+                //Checkbox for residueNumbers
+                if (format.equals("ALN"))
+                {
+                    outputResidueNumbers.setEnabled(true);
+                }
+                else
+                {
+                    outputResidueNumbers.setSelected(false);
+                    outputResidueNumbers.setEnabled(false);
+                }
+
+                //Checkbox for sequential
+                if (format.equals("PHYLIP"))
+                {
+                    if (program.equals("TCS"))
+                    {
+                        outputSequential.setSelected(true);
+                        outputSequential.setEnabled(false);
+                    }
+                    else if (program.equals("CodABC"))
+                    {
+                        outputSequential.setSelected(true);
+                        outputSequential.setEnabled(false);
+                    }	
+                    else if (program.equals("SeaView"))
+                    {
+                        outputSequential.setSelected(false);
+                        outputSequential.setEnabled(false);
+                    }
+                    else
+                    {
+                        outputSequential.setEnabled(true);
+                    }
+                }
+                else if (format.equals("NEXUS"))
+                {
+                    
+                    if (program.equals("PAML") || program.equals("ProtTest")
+                            || program.equals("TCS"))
+                    {
+                        outputSequential.setSelected(true);
+                        outputSequential.setEnabled(false);
+                    }
+                    else if (program.equals("MEGA") || program.equals("trimAl"))
+                    {
+                        outputSequential.setSelected(false);
+                        outputSequential.setEnabled(false);
+                    }
+                    else
+                    {
+                        outputSequential.setEnabled(true);
+                    }
+                }
+                else
+                {
+                    outputSequential.setSelected(false);
+                    outputSequential.setEnabled(false);
+                }
+
+                //Checkbox for match
+                if (format.equals("MSF") || program.equals("MrBayes")
+                        || program.equals("SplitsTree") || program.equals("Clustal")
+                        || program.equals("MAFFT") || program.equals("Gblocks")
+                        || (program.equals("dnaSP") && format.equals("NEXUS")))
+                {
+                    outputMatch.setSelected(false);
+                    outputMatch.setEnabled(false);
+                }
+                else
+                {
+                    outputMatch.setEnabled(true);
+                }
+            }
+        });
+    }//GEN-LAST:event_outputFormatActionPerformed
+
+    /**
+     * Disables input options in case autodetection is checked. Enables them in other case.
+     * @param evt Event generated when checking or unchecking autodetection.
+     */
+    private void inputAutodetectActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_inputAutodetectActionPerformed
+    {//GEN-HEADEREND:event_inputAutodetectActionPerformed
+        SwingUtilities.invokeLater(new Runnable()
+        {
+
+            public void run()
+            {
+                if (inputAutodetect.isSelected())
+                {
+                    inputOSLabel.setEnabled(false);
+                    inputOS.setEnabled(false);
+                    inputProgramLabel.setEnabled(false);
+                    inputProgram.setEnabled(false);
+                    inputFormatLabel.setEnabled(false);
+                    inputFormat.setEnabled(false);
+                }
+                else
+                {
+                    inputOSLabel.setEnabled(true);
+                    inputOS.setEnabled(true);
+                    inputProgramLabel.setEnabled(true);
+                    inputProgram.setEnabled(true);
+                    inputFormatLabel.setEnabled(true);
+                    inputFormat.setEnabled(true);
+                }
+            }
+        });
+    }//GEN-LAST:event_inputAutodetectActionPerformed
+
+    /**
+     * Enables collapse options in case collapse is checked. Disables them in other case.
+     * @param evt Event generated when checking or unchecking the collapse option.
+     */
+    private void collapseActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_collapseActionPerformed
+    {//GEN-HEADEREND:event_collapseActionPerformed
+        SwingUtilities.invokeLater(new Runnable()
+        {
+            public void run()
+            {
+                if (collapse.isSelected())
+                {
+                    collapseLimitLabel.setEnabled(true);
+                    collapseLimit.setEnabled(true);
+                    collapseGaps.setEnabled(true);
+                    collapseMissing.setEnabled(true);
+                }
+                else
+                {
+                    collapseLimitLabel.setEnabled(false);
+                    collapseLimit.setEnabled(false);
+                    collapseGaps.setEnabled(false);
+                    collapseMissing.setEnabled(false);
+                }
+            }
+        });
+    }//GEN-LAST:event_collapseActionPerformed
+
+    /**
+     * Updates the supported input formats when selecting an input program.
+     * @param evt Event generated when selecting an input program.
+     */
+    private void inputProgramActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_inputProgramActionPerformed
+        SwingUtilities.invokeLater(new Runnable()
+        {
+            public void run()
+            {
+                String program = (String) inputProgram.getItemAt(inputProgram.getSelectedIndex());
+                if (program.equals("Clustal"))
+                    inputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN", "FASTA", "GDE", "MSF", "NEXUS", "PHYLIP", "PIR"
+                            }));
+                else if (program.equals("MAFFT"))
+                    inputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN", "FASTA"
+                            }));
+                else if (program.equals("MUSCLE"))
+                    inputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN", "FASTA", "MSF", "PHYLIP"
+                            }));
+                else if (program.equals("PROBCONS"))
+                    inputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN", "FASTA"
+                            }));
+                else if (program.equals("TCoffee"))
+                    inputFormat.setModel(new DefaultComboBoxModel(new String[]
+                            {
+                                "ALN", "FASTA", "MSF", "PHYLIP", "PIR"
+                            }));
+            }
+        });
+    }//GEN-LAST:event_inputProgramActionPerformed
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JCheckBox collapse;
+    private javax.swing.JCheckBox collapseGaps;
+    private javax.swing.JSpinner collapseLimit;
+    private javax.swing.JLabel collapseLimitLabel;
+    private javax.swing.JCheckBox collapseMissing;
+    private javax.swing.JPanel collapsePanel;
+    private javax.swing.JCheckBox inputAutodetect;
+    private javax.swing.JComboBox inputFormat;
+    private javax.swing.JLabel inputFormatLabel;
+    private javax.swing.JComboBox inputOS;
+    private javax.swing.JLabel inputOSLabel;
+    private javax.swing.JPanel inputPanel;
+    private javax.swing.JComboBox inputProgram;
+    private javax.swing.JLabel inputProgramLabel;
+    private javax.swing.JComboBox outputFormat;
+    private javax.swing.JLabel outputFormatLabel;
+    private javax.swing.JCheckBox outputLowerCase;
+    private javax.swing.JCheckBox outputMatch;
+    private javax.swing.JComboBox outputOS;
+    private javax.swing.JLabel outputOSLabel;
+    private javax.swing.JPanel outputPanel;
+    private javax.swing.JComboBox outputProgram;
+    private javax.swing.JLabel outputProgramLabel;
+    private javax.swing.JCheckBox outputResidueNumbers;
+    private javax.swing.JCheckBox outputSequential;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/alter-lib/src/gui/GUILogHandler.java b/alter-lib/src/gui/GUILogHandler.java
new file mode 100755
index 0000000..4cc5b7e
--- /dev/null
+++ b/alter-lib/src/gui/GUILogHandler.java
@@ -0,0 +1,96 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package gui;
+
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+/**
+ * Implements a handler for logging messages, printing them in a JTextArea
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public class GUILogHandler extends Handler
+{
+    /**
+     * JTextArea where messages will be printed.
+     */
+    private JTextArea log;
+
+    /**
+     * Class constructor.
+     * @param log JTextArea where messages will be printed.
+     */
+    public GUILogHandler(JTextArea log)
+    {
+        this.log = log;
+    }
+
+    /**
+     * Prints messages in the JTextArea
+     * @param record Message to print.
+     */
+    @Override
+    public void publish(final LogRecord record)
+    {
+        if (record.getLevel() == Level.INFO)
+            SwingUtilities.invokeLater(new Runnable()
+            {
+                public void run()
+                {
+                    log.append("<INFO> : " + record.getMessage().replace("\n", "\n\t") + "\n");
+                }
+            });
+        else if (record.getLevel() == Level.WARNING)
+            SwingUtilities.invokeLater(new Runnable()
+            {
+                public void run()
+                {
+                    log.append("<WARNING> : " + record.getMessage().replace("\n", "\n\t") + "\n");
+                }
+            });
+        else
+            SwingUtilities.invokeLater(new Runnable()
+            {
+
+                public void run()
+                {
+                    log.append("<ERROR>: " + record.getMessage().replace("\n", "\n\t") + "\n");
+                }
+            });
+    }
+
+    /**
+     * No implemented behaviour.
+     */
+    @Override
+    public void flush()
+    {}
+
+    /**
+     * No implemented behaviour.
+     * @throws SecurityException If a Security Manager exists and the calling object does not have permission.
+     */
+    @Override
+    public void close() throws SecurityException
+    {
+    }
+}
diff --git a/alter-lib/src/gui/HelpPanel.form b/alter-lib/src/gui/HelpPanel.form
new file mode 100755
index 0000000..255a5a7
--- /dev/null
+++ b/alter-lib/src/gui/HelpPanel.form
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
+  <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="0" attributes="0">
+              <Component id="scrollPane" min="-2" pref="594" max="-2" attributes="0"/>
+              <EmptySpace max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="scrollPane" min="-2" pref="484" max="-2" attributes="0"/>
+              <EmptySpace max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JScrollPane" name="scrollPane">
+      <AuxValues>
+        <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+      </AuxValues>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JTextPane" name="textPane">
+          <Properties>
+            <Property name="contentType" type="java.lang.String" value="text/html"/>
+            <Property name="editable" type="boolean" value="false"/>
+            <Property name="text" type="java.lang.String" value="<html>&#xd;&#xa;  <head>&#xd;&#xa;&#xd;&#xa;  </head>&#xd;&#xa;  <body>&#xd;&#xa;    <h2>&#xa;&#x9;ALTER (ALignment Transformation EnviRonment) v1.1</h2>&#xa;<p>&#xa;&#x9;The following document provides information on how to use the desktop version of ALTER, an evironment for alignment transformation. ALTER aims to solve the existing problem with different formats and different prog [...]
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/alter-lib/src/gui/HelpPanel.java b/alter-lib/src/gui/HelpPanel.java
new file mode 100755
index 0000000..d69ebe4
--- /dev/null
+++ b/alter-lib/src/gui/HelpPanel.java
@@ -0,0 +1,84 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package gui;
+
+import javax.swing.SwingUtilities;
+
+/**
+ * Help panel.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public class HelpPanel extends javax.swing.JPanel {
+
+    /** Creates new form HelpPanel */
+    public HelpPanel() {
+        initComponents();
+    }
+
+    public void scrollUp()
+    {
+        SwingUtilities.invokeLater(new Runnable()
+        {
+            public void run()
+            {
+                scrollPane.getVerticalScrollBar().setValue(0);
+            }
+        });
+    }
+
+    /** 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() {
+
+        scrollPane = new javax.swing.JScrollPane();
+        textPane = new javax.swing.JTextPane();
+
+        textPane.setContentType("text/html");
+        textPane.setEditable(false);
+        textPane.setText("<html>\r\n  <head>\r\n\r\n  </head>\r\n  <body>\r\n    <h2>\n\tALTER (ALignment Transformation EnviRonment) v1.1</h2>\n<p>\n\tThe following document provides information on how to use the desktop version of ALTER, an evironment for alignment transformation. ALTER aims to solve the existing problem with different formats and different programs for multiple sequences alignments. It converts multiple sequences alignments between known formats so they can be process [...]
+        scrollPane.setViewportView(textPane);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+        this.setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(scrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 594, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(scrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 484, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+    }// </editor-fold>//GEN-END:initComponents
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JScrollPane scrollPane;
+    private javax.swing.JTextPane textPane;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/alter-lib/src/gui/MainFrame.form b/alter-lib/src/gui/MainFrame.form
new file mode 100755
index 0000000..9cf81f1
--- /dev/null
+++ b/alter-lib/src/gui/MainFrame.form
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JFrameFormInfo">
+  <NonVisualComponents>
+    <Menu class="javax.swing.JMenuBar" name="menu">
+      <SubComponents>
+        <Menu class="javax.swing.JMenu" name="fileMenu">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="File"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="loadMsaMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Load Input MSA..."/>
+              </Properties>
+            </MenuItem>
+            <MenuItem class="javax.swing.JSeparator" name="separator1">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="convertMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Convert"/>
+              </Properties>
+            </MenuItem>
+            <MenuItem class="javax.swing.JSeparator" name="separator2">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="saveInputMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Save Input MSA"/>
+              </Properties>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="saveInputAsMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Save Input MSA As..."/>
+              </Properties>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="saveOutputMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Save Output MSA"/>
+              </Properties>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="saveOutputAsMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Save Output MSA As..."/>
+              </Properties>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="saveAllMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Save Both"/>
+              </Properties>
+            </MenuItem>
+            <MenuItem class="javax.swing.JSeparator" name="separator3">
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="exitMenu">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Exit"/>
+              </Properties>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+        <Menu class="javax.swing.JMenu" name="helpMenu">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Help"/>
+          </Properties>
+          <SubComponents>
+            <MenuItem class="javax.swing.JMenuItem" name="helpContents">
+              <Properties>
+                <Property name="text" type="java.lang.String" value="Help Contents"/>
+              </Properties>
+            </MenuItem>
+            <MenuItem class="javax.swing.JMenuItem" name="about">
+              <Properties>
+                <Property name="action" type="javax.swing.Action" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+                  <Connection code="new AboutAction("About...", null, "Information about Corpus Administrator", null)" type="code"/>
+                </Property>
+                <Property name="text" type="java.lang.String" value="About"/>
+              </Properties>
+            </MenuItem>
+          </SubComponents>
+        </Menu>
+      </SubComponents>
+    </Menu>
+  </NonVisualComponents>
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="0"/>
+    <Property name="title" type="java.lang.String" value="ALTER (ALignment Transformation EnviRonment) v1.1"/>
+    <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
+      <Color id="Cursor predeterminado"/>
+    </Property>
+    <Property name="locationByPlatform" type="boolean" value="true"/>
+    <Property name="name" type="java.lang.String" value="mainFrame" noResource="true"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="menuBar" type="java.lang.String" value="menu"/>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+  </SyntheticProperties>
+  <Events>
+    <EventHandler event="windowClosing" listener="java.awt.event.WindowListener" parameters="java.awt.event.WindowEvent" handler="formWindowClosing"/>
+  </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">
+          <Group type="102" alignment="0" attributes="0">
+              <Component id="inputPanel" max="32767" attributes="0"/>
+              <EmptySpace min="-2" max="-2" attributes="1"/>
+              <Component id="outputPanel" max="32767" attributes="0"/>
+          </Group>
+          <Component id="logPanel" alignment="1" max="32767" attributes="0"/>
+      </Group>
+    </DimensionLayout>
+    <DimensionLayout dim="1">
+      <Group type="103" groupAlignment="0" attributes="0">
+          <Group type="102" alignment="0" attributes="0">
+              <Group type="103" groupAlignment="0" attributes="0">
+                  <Component id="inputPanel" max="32767" attributes="2"/>
+                  <Component id="outputPanel" alignment="0" max="32767" attributes="2"/>
+              </Group>
+              <EmptySpace min="-2" max="-2" attributes="0"/>
+              <Component id="logPanel" max="32767" attributes="0"/>
+          </Group>
+      </Group>
+    </DimensionLayout>
+  </Layout>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="inputPanel">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
+            <TitledBorder title="Input"/>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="0" attributes="0">
+                  <EmptySpace min="-2" max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Component id="inputScroll" alignment="0" pref="495" max="32767" attributes="0"/>
+                      <Group type="102" alignment="0" attributes="0">
+                          <Component id="loadMsaButton" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="saveInputButton" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="saveInputAsButton" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="convertButton" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="inputPosition" pref="98" max="32767" attributes="0"/>
+                      </Group>
+                  </Group>
+              </Group>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" alignment="1" attributes="0">
+                  <Component id="inputScroll" pref="418" max="32767" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="3" attributes="0">
+                      <Component id="loadMsaButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="saveInputButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="inputPosition" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="saveInputAsButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                      <Component id="convertButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Container class="javax.swing.JScrollPane" name="inputScroll">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JTextArea" name="input">
+              <Properties>
+                <Property name="columns" type="int" value="2147483647"/>
+                <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+                  <Font name="Lucida Console" size="11" style="0"/>
+                </Property>
+                <Property name="rows" type="int" value="5"/>
+              </Properties>
+              <Events>
+                <EventHandler event="caretUpdate" listener="javax.swing.event.CaretListener" parameters="javax.swing.event.CaretEvent" handler="inputCaretUpdate"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Component class="javax.swing.JButton" name="loadMsaButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Load..."/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="saveInputButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Save"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="convertButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Convert..."/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="inputPosition">
+          <Properties>
+            <Property name="horizontalAlignment" type="int" value="4"/>
+            <Property name="text" type="java.lang.String" value="Ln: 1 Col: 1"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="saveInputAsButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Save As..."/>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="outputPanel">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
+            <TitledBorder title="Output"/>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Group type="102" attributes="0">
+                  <Group type="103" groupAlignment="0" attributes="0">
+                      <Group type="102" attributes="0">
+                          <Component id="saveOutputButton" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="saveOutputAsButton" min="-2" max="-2" attributes="0"/>
+                          <EmptySpace max="-2" attributes="0"/>
+                          <Component id="outputPosition" pref="260" max="32767" attributes="0"/>
+                      </Group>
+                      <Component id="outputScroll" alignment="0" pref="454" max="32767" 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="1" attributes="0">
+                  <Component id="outputScroll" pref="418" max="32767" attributes="0"/>
+                  <EmptySpace max="-2" attributes="0"/>
+                  <Group type="103" groupAlignment="1" attributes="0">
+                      <Group type="103" groupAlignment="3" attributes="0">
+                          <Component id="saveOutputButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                          <Component id="saveOutputAsButton" alignment="3" min="-2" max="-2" attributes="0"/>
+                      </Group>
+                      <Component id="outputPosition" min="-2" max="-2" attributes="0"/>
+                  </Group>
+              </Group>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Component class="javax.swing.JButton" name="saveOutputButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Save"/>
+          </Properties>
+        </Component>
+        <Container class="javax.swing.JScrollPane" name="outputScroll">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JTextArea" name="output">
+              <Properties>
+                <Property name="columns" type="int" value="2147483647"/>
+                <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+                  <Font name="Lucida Console" size="11" style="0"/>
+                </Property>
+                <Property name="rows" type="int" value="5"/>
+                <Property name="enabled" type="boolean" value="false"/>
+              </Properties>
+              <Events>
+                <EventHandler event="caretUpdate" listener="javax.swing.event.CaretListener" parameters="javax.swing.event.CaretEvent" handler="outputCaretUpdate"/>
+              </Events>
+            </Component>
+          </SubComponents>
+        </Container>
+        <Component class="javax.swing.JLabel" name="outputPosition">
+          <Properties>
+            <Property name="horizontalAlignment" type="int" value="4"/>
+            <Property name="text" type="java.lang.String" value="Ln: 0 Col:0"/>
+            <Property name="enabled" type="boolean" value="false"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JButton" name="saveOutputAsButton">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="Save As..."/>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="logPanel">
+      <Properties>
+        <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
+          <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
+            <TitledBorder title="Log"/>
+          </Border>
+        </Property>
+      </Properties>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Component id="logScroll" alignment="1" pref="1001" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <Component id="logScroll" alignment="1" pref="129" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+      <SubComponents>
+        <Container class="javax.swing.JScrollPane" name="logScroll">
+
+          <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
+          <SubComponents>
+            <Component class="javax.swing.JTextArea" name="log">
+              <Properties>
+                <Property name="columns" type="int" value="2147483647"/>
+                <Property name="editable" type="boolean" value="false"/>
+                <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
+                  <Font name="Lucida Console" size="11" style="0"/>
+                </Property>
+                <Property name="rows" type="int" value="5"/>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/alter-lib/src/gui/MainFrame.java b/alter-lib/src/gui/MainFrame.java
new file mode 100755
index 0000000..7e24815
--- /dev/null
+++ b/alter-lib/src/gui/MainFrame.java
@@ -0,0 +1,1115 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.GraphicsEnvironment;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import javax.swing.AbstractAction;
+import javax.swing.ImageIcon;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.KeyStroke;
+import converter.*;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+import javax.swing.border.TitledBorder;
+import javax.swing.text.BadLocationException;
+import parser.ParseException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Implements the main form to execute ALTER as a GUI application.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+public class MainFrame extends javax.swing.JFrame
+{
+    /**
+     * Logger to register information messages.
+     */
+    private Logger logger;
+
+    /**
+     * Input file.
+     */
+    private File inputFile = null;
+
+    /**
+     * Output file.
+     */
+    private File outputFile = null;
+
+    /**
+     * Current input folder.
+     */
+    private File inputCurDir = null;
+
+    /**
+     * Current output folder.
+     */
+    private File outputCurDir = null;
+
+    /**
+     * Java Action to display the application information.
+     */
+    private AboutAction aboutAction;
+
+    /**
+     * Java Action to display the application help.
+     */
+    private HelpAction helpAction;
+
+    /**
+     * Java Action to load a MSA from a file.
+     */
+    private LoadMsaAction loadMsaAction;
+
+    /**
+     * Java Action to save the input MSA in the selected input file.
+     */
+    private SaveInputAction saveInputAction;
+
+    /**
+     * Java Action to save the input MSA in a file after selecting it.
+     */
+    private SaveInputAsAction saveInputAsAction;
+
+    /**
+     * Java Action to save the output MSA in the selected output file.
+     */
+    private SaveOutputAction saveOutputAction;
+
+    /**
+     * Java Action to save the output MSA in a file after selecting it.
+     */
+    private SaveOutputAsAction saveOutputAsAction;
+
+    /**
+     * Java Action to save both MSAs in their respective files.
+     */
+    private SaveAllAction saveAllAction;
+
+    /**
+     * Java Action to convert the input MSA.
+     */
+    private ConvertAction convertAction;
+
+    /**
+     * Java Action to exit the application asking for confirmation.
+     */
+    private ExitAction exitAction;
+
+    /**
+     * Panel with the conversion options.
+     */
+    ConvertPanel convertPanel;
+
+    /**
+     * Class constructor.
+     */
+    public MainFrame()
+    {
+        //Try changing Look-And-Feel to Nimbus (do nothing in case is not installed)
+        try
+        {
+            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
+        }
+        catch (UnsupportedLookAndFeelException e)
+        {
+            // handle exception
+        }
+        catch (ClassNotFoundException e)
+        {
+            // handle exception
+        }
+        catch (InstantiationException e)
+        {
+            // handle exception
+        }
+        catch (IllegalAccessException e)
+        {
+            // handle exception
+        }
+
+        //Initialize the convert panel
+        convertPanel = new ConvertPanel();
+        //Initialize Java Actions
+        aboutAction = new AboutAction("About", null, "Information about ALTER", KeyEvent.VK_A);
+        helpAction = new HelpAction("Help Contents", null, "", KeyEvent.VK_C);
+        loadMsaAction = new LoadMsaAction("Load...", null, "Load a new input MSA", KeyEvent.VK_L);
+        saveInputAction = new SaveInputAction("Save", null, "Save input MSA", KeyEvent.VK_S);
+        saveInputAsAction = new SaveInputAsAction("Save As...", null, "Save input MSA as...", KeyEvent.VK_I);
+        saveOutputAction = new SaveOutputAction("Save", null, "Save output MSA", KeyEvent.VK_V);
+        saveOutputAsAction = new SaveOutputAsAction("Save As...", null, "Save output MSA as...", KeyEvent.VK_O);
+        saveAllAction = new SaveAllAction("Save All", null, "Save both input and output MSAs", KeyEvent.VK_A);
+        convertAction = new ConvertAction("Convert...", null, "Convert MSA", KeyEvent.VK_C);
+        exitAction = new ExitAction("Exit", null, "Exit ALTER", KeyEvent.VK_E);
+
+        //Initialize components
+        initComponents();
+
+        //Assing Java Actions to components
+        about.setAction(aboutAction);
+
+        helpContents.setAction(helpAction);
+
+        loadMsaButton.setAction(loadMsaAction);
+        loadMsaMenu.setAction(loadMsaAction);
+        loadMsaMenu.setText("Load Input MSA...");
+        loadMsaMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.CTRL_MASK));
+
+        saveInputMenu.setAction(saveInputAction);
+        saveInputMenu.setText("Save Input MSA");
+        saveInputMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK));
+        saveInputButton.setAction(saveInputAction);
+
+        saveInputAsMenu.setAction(saveInputAsAction);
+        saveInputAsMenu.setText("Save Input MSA As...");
+        saveInputAsButton.setAction(saveInputAsAction);
+
+        saveOutputMenu.setAction(saveOutputAction);
+        saveOutputMenu.setText("Save Output MSA");
+        saveOutputMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
+        saveOutputButton.setAction(saveOutputAction);
+
+        saveOutputAsMenu.setAction(saveOutputAsAction);
+        saveOutputAsMenu.setText("Save Output MSA As...");
+        saveOutputAsButton.setAction(saveOutputAsAction);
+
+        saveAllMenu.setAction(saveAllAction);
+        saveAllMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK));
+
+        convertMenu.setAction(convertAction);
+        convertMenu.setText("Convert MSA...");
+        convertMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK));
+        convertButton.setAction(convertAction);
+
+        exitMenu.setAction(exitAction);
+
+        //Maximize window
+        GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        this.setMaximizedBounds(env.getMaximumWindowBounds ());
+        this.setExtendedState(this.getExtendedState() | JFrame.MAXIMIZED_BOTH);
+
+        //Initialize logger
+        logger = Logger.getLogger("alter" + System.currentTimeMillis());
+        //Add logger handler
+        logger.addHandler(new GUILogHandler(log));
+    }
+
+    /** 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() {
+
+        inputPanel = new javax.swing.JPanel();
+        inputScroll = new javax.swing.JScrollPane();
+        input = new javax.swing.JTextArea();
+        loadMsaButton = new javax.swing.JButton();
+        saveInputButton = new javax.swing.JButton();
+        convertButton = new javax.swing.JButton();
+        inputPosition = new javax.swing.JLabel();
+        saveInputAsButton = new javax.swing.JButton();
+        outputPanel = new javax.swing.JPanel();
+        saveOutputButton = new javax.swing.JButton();
+        outputScroll = new javax.swing.JScrollPane();
+        output = new javax.swing.JTextArea();
+        outputPosition = new javax.swing.JLabel();
+        saveOutputAsButton = new javax.swing.JButton();
+        logPanel = new javax.swing.JPanel();
+        logScroll = new javax.swing.JScrollPane();
+        log = new javax.swing.JTextArea();
+        menu = new javax.swing.JMenuBar();
+        fileMenu = new javax.swing.JMenu();
+        loadMsaMenu = new javax.swing.JMenuItem();
+        separator1 = new javax.swing.JSeparator();
+        convertMenu = new javax.swing.JMenuItem();
+        separator2 = new javax.swing.JSeparator();
+        saveInputMenu = new javax.swing.JMenuItem();
+        saveInputAsMenu = new javax.swing.JMenuItem();
+        saveOutputMenu = new javax.swing.JMenuItem();
+        saveOutputAsMenu = new javax.swing.JMenuItem();
+        saveAllMenu = new javax.swing.JMenuItem();
+        separator3 = new javax.swing.JSeparator();
+        exitMenu = new javax.swing.JMenuItem();
+        helpMenu = new javax.swing.JMenu();
+        helpContents = new javax.swing.JMenuItem();
+        about = new javax.swing.JMenuItem();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
+        setTitle("ALTER (ALignment Transformation EnviRonment) v1.1");
+        setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
+        setLocationByPlatform(true);
+        setName("mainFrame"); // NOI18N
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosing(java.awt.event.WindowEvent evt) {
+                formWindowClosing(evt);
+            }
+        });
+
+        inputPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Input"));
+
+        input.setColumns(2147483647);
+        input.setFont(new java.awt.Font("Lucida Console", 0, 11));
+        input.setRows(5);
+        input.addCaretListener(new javax.swing.event.CaretListener() {
+            public void caretUpdate(javax.swing.event.CaretEvent evt) {
+                inputCaretUpdate(evt);
+            }
+        });
+        inputScroll.setViewportView(input);
+
+        loadMsaButton.setText("Load...");
+
+        saveInputButton.setText("Save");
+
+        convertButton.setText("Convert...");
+
+        inputPosition.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        inputPosition.setText("Ln: 1 Col: 1");
+
+        saveInputAsButton.setText("Save As...");
+
+        javax.swing.GroupLayout inputPanelLayout = new javax.swing.GroupLayout(inputPanel);
+        inputPanel.setLayout(inputPanelLayout);
+        inputPanelLayout.setHorizontalGroup(
+            inputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(inputPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(inputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(inputScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 410, Short.MAX_VALUE)
+                    .addGroup(inputPanelLayout.createSequentialGroup()
+                        .addComponent(loadMsaButton)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(saveInputButton)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(saveInputAsButton)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(convertButton)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(inputPosition, javax.swing.GroupLayout.DEFAULT_SIZE, 98, Short.MAX_VALUE))))
+        );
+        inputPanelLayout.setVerticalGroup(
+            inputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, inputPanelLayout.createSequentialGroup()
+                .addComponent(inputScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 418, Short.MAX_VALUE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(inputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(loadMsaButton)
+                    .addComponent(saveInputButton)
+                    .addComponent(inputPosition)
+                    .addComponent(saveInputAsButton)
+                    .addComponent(convertButton)))
+        );
+
+        outputPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Output"));
+
+        saveOutputButton.setText("Save");
+
+        output.setColumns(2147483647);
+        output.setFont(new java.awt.Font("Lucida Console", 0, 11));
+        output.setRows(5);
+        output.setEnabled(false);
+        output.addCaretListener(new javax.swing.event.CaretListener() {
+            public void caretUpdate(javax.swing.event.CaretEvent evt) {
+                outputCaretUpdate(evt);
+            }
+        });
+        outputScroll.setViewportView(output);
+
+        outputPosition.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        outputPosition.setText("Ln: 0 Col:0");
+        outputPosition.setEnabled(false);
+
+        saveOutputAsButton.setText("Save As...");
+
+        javax.swing.GroupLayout outputPanelLayout = new javax.swing.GroupLayout(outputPanel);
+        outputPanel.setLayout(outputPanelLayout);
+        outputPanelLayout.setHorizontalGroup(
+            outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(outputPanelLayout.createSequentialGroup()
+                .addGroup(outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(outputPanelLayout.createSequentialGroup()
+                        .addComponent(saveOutputButton)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(saveOutputAsButton)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(outputPosition, javax.swing.GroupLayout.DEFAULT_SIZE, 260, Short.MAX_VALUE))
+                    .addComponent(outputScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 410, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        outputPanelLayout.setVerticalGroup(
+            outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, outputPanelLayout.createSequentialGroup()
+                .addComponent(outputScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 418, Short.MAX_VALUE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addGroup(outputPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                        .addComponent(saveOutputButton)
+                        .addComponent(saveOutputAsButton))
+                    .addComponent(outputPosition)))
+        );
+
+        logPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Log"));
+
+        log.setColumns(2147483647);
+        log.setEditable(false);
+        log.setFont(new java.awt.Font("Lucida Console", 0, 11));
+        log.setRows(5);
+        logScroll.setViewportView(log);
+
+        javax.swing.GroupLayout logPanelLayout = new javax.swing.GroupLayout(logPanel);
+        logPanel.setLayout(logPanelLayout);
+        logPanelLayout.setHorizontalGroup(
+            logPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(logScroll, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 858, Short.MAX_VALUE)
+        );
+        logPanelLayout.setVerticalGroup(
+            logPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(logScroll, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE)
+        );
+
+        fileMenu.setText("File");
+
+        loadMsaMenu.setText("Load Input MSA...");
+        fileMenu.add(loadMsaMenu);
+        fileMenu.add(separator1);
+
+        convertMenu.setText("Convert");
+        fileMenu.add(convertMenu);
+        fileMenu.add(separator2);
+
+        saveInputMenu.setText("Save Input MSA");
+        fileMenu.add(saveInputMenu);
+
+        saveInputAsMenu.setText("Save Input MSA As...");
+        fileMenu.add(saveInputAsMenu);
+
+        saveOutputMenu.setText("Save Output MSA");
+        fileMenu.add(saveOutputMenu);
+
+        saveOutputAsMenu.setText("Save Output MSA As...");
+        fileMenu.add(saveOutputAsMenu);
+
+        saveAllMenu.setText("Save Both");
+        fileMenu.add(saveAllMenu);
+        fileMenu.add(separator3);
+
+        exitMenu.setText("Exit");
+        fileMenu.add(exitMenu);
+
+        menu.add(fileMenu);
+
+        helpMenu.setText("Help");
+
+        helpContents.setText("Help Contents");
+        helpMenu.add(helpContents);
+
+        about.setAction(new AboutAction("About...", null, "Information about Corpus Administrator", null));
+        about.setText("About");
+        helpMenu.add(about);
+
+        menu.add(helpMenu);
+
+        setJMenuBar(menu);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(inputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(outputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+            .addComponent(logPanel, javax.swing.GroupLayout.Alignment.TRAILING, 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()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(inputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(outputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(logPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    /**
+     * Calls exitAction.actionPerformed(null) to ask for confirmation before exiting the application.
+     * @param evt Event generated when closing the window.
+     */
+    private void formWindowClosing(java.awt.event.WindowEvent evt)//GEN-FIRST:event_formWindowClosing
+    {//GEN-HEADEREND:event_formWindowClosing
+        exitAction.actionPerformed(null);
+    }//GEN-LAST:event_formWindowClosing
+
+    /**
+     * Updates line and column numbers when the input caret position changes.
+     * @param evt Event generated when the caret position changes.
+     */
+    private void inputCaretUpdate(javax.swing.event.CaretEvent evt)//GEN-FIRST:event_inputCaretUpdate
+    {//GEN-HEADEREND:event_inputCaretUpdate
+        try
+        {
+            int caretPos = input.getCaretPosition();
+            int line = input.getLineOfOffset(caretPos);
+            int column = caretPos - input.getLineStartOffset(line);
+            line += 1;
+            column += 1;
+            inputPosition.setText("Ln: " + line + " Col: " + column);
+        }
+        catch (BadLocationException ex)
+        {}
+    }//GEN-LAST:event_inputCaretUpdate
+
+    /**
+     * Updates line and column numbers when the output caret position changes.
+     * @param evt Event generated when the caret position changes.
+     */
+    private void outputCaretUpdate(javax.swing.event.CaretEvent evt)//GEN-FIRST:event_outputCaretUpdate
+    {//GEN-HEADEREND:event_outputCaretUpdate
+        try
+        {
+            int caretPos = output.getCaretPosition();
+            int line = output.getLineOfOffset(caretPos);
+            int column = caretPos - output.getLineStartOffset(line);
+            line += 1;
+            column += 1;
+            outputPosition.setText("Ln: " + line + " Col: " + column);
+        }
+        catch (BadLocationException ex)
+        {}
+    }//GEN-LAST:event_outputCaretUpdate
+
+    /**
+     * Main method that creates and shows the form
+     * @param args Command line arguments
+     */
+    public static void main(String args[])
+    {
+
+        java.awt.EventQueue.invokeLater(new Runnable()
+        {
+
+            public void run()
+            {
+                MainFrame frame = new MainFrame();
+                frame.setVisible(true);
+            }
+        });
+    }
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JMenuItem about;
+    private javax.swing.JButton convertButton;
+    private javax.swing.JMenuItem convertMenu;
+    private javax.swing.JMenuItem exitMenu;
+    private javax.swing.JMenu fileMenu;
+    private javax.swing.JMenuItem helpContents;
+    private javax.swing.JMenu helpMenu;
+    private javax.swing.JTextArea input;
+    private javax.swing.JPanel inputPanel;
+    private javax.swing.JLabel inputPosition;
+    private javax.swing.JScrollPane inputScroll;
+    private javax.swing.JButton loadMsaButton;
+    private javax.swing.JMenuItem loadMsaMenu;
+    private javax.swing.JTextArea log;
+    private javax.swing.JPanel logPanel;
+    private javax.swing.JScrollPane logScroll;
+    private javax.swing.JMenuBar menu;
+    private javax.swing.JTextArea output;
+    private javax.swing.JPanel outputPanel;
+    private javax.swing.JLabel outputPosition;
+    private javax.swing.JScrollPane outputScroll;
+    private javax.swing.JMenuItem saveAllMenu;
+    private javax.swing.JButton saveInputAsButton;
+    private javax.swing.JMenuItem saveInputAsMenu;
+    private javax.swing.JButton saveInputButton;
+    private javax.swing.JMenuItem saveInputMenu;
+    private javax.swing.JButton saveOutputAsButton;
+    private javax.swing.JMenuItem saveOutputAsMenu;
+    private javax.swing.JButton saveOutputButton;
+    private javax.swing.JMenuItem saveOutputMenu;
+    private javax.swing.JSeparator separator1;
+    private javax.swing.JSeparator separator2;
+    private javax.swing.JSeparator separator3;
+    // End of variables declaration//GEN-END:variables
+
+    /**
+     * Java Action to show the application information.
+     */
+    private class AboutAction extends AbstractAction
+    {
+
+        /**Class constructor.
+         *@param text Text to display.
+         *@param icon Action's icon.
+         *@param desc Brief description.
+         *@param mnemonic Keyboard shortcut.
+         */
+        public AboutAction(String text, ImageIcon icon, String desc, Integer mnemonic)
+        {
+            //Initialize action
+            super(text, icon);
+            putValue(SHORT_DESCRIPTION, desc);
+            putValue(MNEMONIC_KEY, mnemonic);
+        }
+
+        /**Implements action.
+         *@param e Event that triggers the action.
+         */
+        public void actionPerformed(ActionEvent e)
+        {
+            JOptionPane.showMessageDialog(new JFrame(),
+                    "ALTER (ALlignment Transformation EnviRonment)\n" +
+                    "Developed by Daniel Gomez Blanco\n\n" +
+                    "Email: nanodgb at gmail.com\n",
+                    "About ALTER",
+                    JOptionPane.PLAIN_MESSAGE);
+        }
+    }
+
+    /**
+     * Java Action to show the application help.
+     */
+    private class HelpAction extends AbstractAction
+    {
+
+        /**Class constructor.
+         *@param text Text to display.
+         *@param icon Action's icon.
+         *@param desc Brief description.
+         *@param mnemonic Keyboard shortcut.
+         */
+        public HelpAction(String text, ImageIcon icon, String desc, Integer mnemonic)
+        {
+            //Initialize action
+            super(text, icon);
+            putValue(SHORT_DESCRIPTION, desc);
+            putValue(MNEMONIC_KEY, mnemonic);
+        }
+
+        /**Implements action.
+         *@param e Event that triggers the action.
+         */
+        public void actionPerformed(ActionEvent e)
+        {
+            JFrame help = new JFrame("ALTER Help");
+            help.setLocationByPlatform(true);
+            HelpPanel helpPanel = new HelpPanel();
+            help.add(helpPanel);
+            help.pack();
+            help.setVisible(true);
+            helpPanel.scrollUp();
+        }
+    }
+
+    /**
+     * Java Action to load a MSA from a file after selecting it.
+     */
+    private class LoadMsaAction extends AbstractAction
+    {
+
+        /**Class constructor.
+         *@param text Text to display.
+         *@param icon Action's icon.
+         *@param desc Brief description.
+         *@param mnemonic Keyboard shortcut.
+         */
+        public LoadMsaAction(String text, ImageIcon icon, String desc, Integer mnemonic)
+        {
+            //Initialize action
+            super(text, icon);
+            putValue(SHORT_DESCRIPTION, desc);
+            putValue(MNEMONIC_KEY, mnemonic);
+        }
+
+        /**Implements action.
+         *@param e Event that triggers the action.
+         */
+        public void actionPerformed(ActionEvent e)
+        {
+            //Create file chooser
+            JFileChooser chooser = new JFileChooser();
+
+            //Only files are to be chosen
+            chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+            chooser.setMultiSelectionEnabled(false);
+            chooser.setDialogTitle("Load Input MSA");
+            chooser.setDialogType(JFileChooser.OPEN_DIALOG);
+            if (inputCurDir != null)
+                chooser.setCurrentDirectory(inputCurDir);
+            //Display chooser
+            int returnVal = chooser.showOpenDialog(new javax.swing.JFrame());
+
+            //If the user accepts
+            if (returnVal == JFileChooser.APPROVE_OPTION)
+            {
+                //Get input file
+                inputFile = chooser.getSelectedFile();
+                //Get input folder
+                inputCurDir = inputFile.getParentFile();
+                //Copy file's contents to a string
+                StringBuffer text = new StringBuffer();
+                try
+                {
+                    BufferedReader br = new BufferedReader(new FileReader(inputFile));
+                    String s;
+                    while ((s = br.readLine()) != null)
+                        text.append(s + "\r\n");
+                    br.close();
+                }
+                catch (FileNotFoundException ex)
+                {
+                    logger.log(Level.SEVERE,"Input MSA file not found.");
+                    return;
+                }
+                catch (IOException ex)
+                {
+                    logger.log(Level.SEVERE, "Failure reading input MSA file:\n" + ex.getMessage());
+                    return;
+                }
+                
+                //Update interface
+                input.setText(text.toString());
+                
+                SwingUtilities.invokeLater(new Runnable()
+                {
+                    public void run()
+                    {
+                        ((TitledBorder) inputPanel.getBorder()).setTitle("Input - " + inputFile.getName());
+                        inputPanel.repaint();
+                        inputScroll.getVerticalScrollBar().setValue(0);
+                        inputScroll.getHorizontalScrollBar().setValue(0);
+                    }
+                });
+                logger.log(Level.INFO, "MSA loaded from " + inputFile.getAbsolutePath() + ".");
+            }
+        }
+    }
+
+    /**
+     * Java Action to save the input MSA into the selected file.
+     */
+    private class SaveInputAction extends AbstractAction
+    {
+        /**Class constructor.
+         *@param text Text to display.
+         *@param icon Action's icon.
+         *@param desc Brief description.
+         *@param mnemonic Keyboard shortcut.
+         */
+        public SaveInputAction(String text, ImageIcon icon, String desc, Integer mnemonic)
+        {
+            //Initialize action
+            super(text, icon);
+            putValue(SHORT_DESCRIPTION, desc);
+            putValue(MNEMONIC_KEY, mnemonic);
+        }
+
+        /**Implements action.
+         *@param e Event that triggers the action.
+         */
+        public void actionPerformed(ActionEvent e)
+        {
+            //If no file had been selected call saveInputAsAction
+            if (inputFile == null)
+                saveInputAsAction.actionPerformed(e);
+            else
+            {
+                //Save text to file
+                try
+                {
+                    FileWriter fw = new FileWriter(inputFile);
+                    fw.write(input.getText());
+                    fw.close();
+                }
+                catch (IOException ex)
+                {
+                    logger.log(Level.SEVERE, "Failure saving input MSA file:\n" + ex.getMessage());
+                    return;
+                }
+                logger.log(Level.INFO, "Input MSA saved to " + inputFile.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Java Action to save input MSA in a different file.
+     */
+    private class SaveInputAsAction extends AbstractAction
+    {
+
+        /**Class constructor.
+         *@param text Text to display.
+         *@param icon Action's icon.
+         *@param desc Brief description.
+         *@param mnemonic Keyboard shortcut.
+         */
+        public SaveInputAsAction(String text, ImageIcon icon, String desc, Integer mnemonic)
+        {
+            //Initialize action
+            super(text, icon);
+            putValue(SHORT_DESCRIPTION, desc);
+            putValue(MNEMONIC_KEY, mnemonic);
+        }
+
+        /**Implements action.
+         *@param e Event that triggers the action.
+         */
+        public void actionPerformed(ActionEvent e)
+        {        
+            //Show file chooser
+            JFileChooser chooser = new JFileChooser();
+            chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+            chooser.setMultiSelectionEnabled(false);
+            chooser.setDialogTitle("Save Input MSA As...");
+            chooser.setDialogType(JFileChooser.SAVE_DIALOG);
+            int returnVal = chooser.showOpenDialog(new javax.swing.JFrame());
+
+            //If user accepts
+            if (returnVal == JFileChooser.APPROVE_OPTION)
+            {
+                //Save file
+                inputFile = chooser.getSelectedFile();
+                if (!inputFile.exists())
+                    inputFile = new File(inputFile.getPath());
+                inputCurDir = inputFile.getParentFile();
+
+                try
+                {
+                    FileWriter fw = new FileWriter(inputFile);
+                    fw.write(input.getText());
+                    fw.close();
+                }
+                catch (IOException ex)
+                {
+                    logger.log(Level.SEVERE, "Failure saving input MSA file:\n" + ex.getMessage());
+                    return;
+                }
+
+                SwingUtilities.invokeLater(new Runnable()
+                {
+                    public void run()
+                    {
+                        ((TitledBorder) inputPanel.getBorder()).setTitle("Input - " + inputFile.getName());
+                        inputPanel.repaint();
+                    }
+                });
+                logger.log(Level.INFO, "Input MSA saved to " + inputFile.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Java Action to save the output MSA to the selected file.
+     */
+    private class SaveOutputAction extends AbstractAction
+    {
+
+        /**Class constructor.
+         *@param text Text to display.
+         *@param icon Action's icon.
+         *@param desc Brief description.
+         *@param mnemonic Keyboard shortcut.
+         */
+        public SaveOutputAction(String text, ImageIcon icon, String desc, Integer mnemonic)
+        {
+            //Incializar la accion
+            super(text, icon);
+            putValue(SHORT_DESCRIPTION, desc);
+            putValue(MNEMONIC_KEY, mnemonic);
+            this.setEnabled(false);
+        }
+
+        /**Implements action
+         *@param e Event that triggers the action
+         */
+        public void actionPerformed(ActionEvent e)
+        {
+            //If no file had been selected call saveOutputAsAction
+            if (outputFile == null)
+                saveOutputAsAction.actionPerformed(e);
+            else
+            {
+                //Save file
+                try
+                {
+                    FileWriter fw = new FileWriter(outputFile);
+                    fw.write(output.getText());
+                    fw.close();
+                }
+                catch (IOException ex)
+                {
+                    logger.log(Level.SEVERE, "Failure saving output MSA file:\n" + ex.getMessage());
+                    return;
+                }
+                logger.log(Level.INFO, "Output MSA saved to " + outputFile.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Java Action to save the output MSA to a different file.
+     */
+    private class SaveOutputAsAction extends AbstractAction
+    {
+
+        /**Class constructor.
+         *@param text Text to display.
+         *@param icon Action's icon.
+         *@param desc Brief description.
+         *@param mnemonic Keyboard shortcut.
+         */
+        public SaveOutputAsAction(String text, ImageIcon icon, String desc, Integer mnemonic)
+        {
+            //Initialize action
+            super(text, icon);
+            putValue(SHORT_DESCRIPTION, desc);
+            putValue(MNEMONIC_KEY, mnemonic);
+            this.setEnabled(false);
+        }
+
+        /**Implements action.
+         *@param e Event that triggers the action.
+         */
+        public void actionPerformed(ActionEvent e)
+        {
+            //Show file chooser
+            JFileChooser chooser = new JFileChooser();
+            chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+            chooser.setMultiSelectionEnabled(false);
+            chooser.setDialogTitle("Save Output MSA As...");
+            chooser.setDialogType(JFileChooser.SAVE_DIALOG);
+            if (outputCurDir != null)
+                chooser.setCurrentDirectory(outputCurDir);
+            int returnVal = chooser.showOpenDialog(new javax.swing.JFrame());
+
+            //If user accepts
+            if (returnVal == JFileChooser.APPROVE_OPTION)
+            {
+                //Save file
+                outputFile = chooser.getSelectedFile();
+                if (!outputFile.exists())
+                    outputFile = new File(outputFile.getPath());
+                outputCurDir = outputFile.getParentFile();
+
+                try
+                {
+                    FileWriter fw = new FileWriter(outputFile);
+                    fw.write(output.getText());
+                    fw.close();
+                }
+                catch (IOException ex)
+                {
+                    logger.log(Level.SEVERE, "Failure saving output MSA file:\n" + ex.getMessage());
+                    return;
+                }
+                SwingUtilities.invokeLater(new Runnable()
+                {
+                    public void run()
+                    {
+                        ((TitledBorder) outputPanel.getBorder()).setTitle("Output - " + outputFile.getName());
+                        outputPanel.repaint();
+                    }
+                });
+                logger.log(Level.INFO,"Output MSA saved to " + outputFile.getAbsolutePath());
+            }
+        }
+    }
+
+    /**
+     * Java Action to save both input and output MSA to their respective files.
+     */
+    private class SaveAllAction extends AbstractAction
+    {
+        /**Class constructor.
+         *@param text Text to display.
+         *@param icon Action's icon.
+         *@param desc Brief description.
+         *@param mnemonic Keyboard shortcut.
+         */
+        public SaveAllAction(String text, ImageIcon icon, String desc, Integer mnemonic)
+        {
+            //Initialize action
+            super(text, icon);
+            putValue(SHORT_DESCRIPTION, desc);
+            putValue(MNEMONIC_KEY, mnemonic);
+            this.setEnabled(false);
+        }
+
+        /**Implements action
+         *@param e Event that triggers the action
+         */
+        public void actionPerformed(ActionEvent e)
+        {
+            saveInputAction.actionPerformed(e);
+            saveOutputAction.actionPerformed(e);
+        }
+    }
+
+    /**
+     * Java Action to convert the input MSA.
+     */
+    private class ConvertAction extends AbstractAction
+    {
+
+        /**Class constructor.
+         *@param text Text to display.
+         *@param icon Action's icon.
+         *@param desc Brief description.
+         *@param mnemonic Keyboard shortcut.
+         */
+        public ConvertAction(String text, ImageIcon icon, String desc, Integer mnemonic)
+        {
+            //Initialize action
+            super(text, icon);
+            putValue(SHORT_DESCRIPTION, desc);
+            putValue(MNEMONIC_KEY, mnemonic);
+        }
+
+        /**Implements action
+         *@param e Event that triggers the action
+         */
+        public void actionPerformed(ActionEvent e)
+        {
+            //Show options panel
+            int n = JOptionPane.showConfirmDialog(new JFrame(),
+                    convertPanel,
+                    "Convert MSA",
+                    JOptionPane.OK_CANCEL_OPTION,
+                    JOptionPane.PLAIN_MESSAGE);
+
+            //If user accepts
+            if (n == JOptionPane.OK_OPTION)
+            {
+                //Get options
+                String in = input.getText();
+                String inO = convertPanel.getInputOS();
+                String inP = convertPanel.getInputProgram();
+                String inF = convertPanel.getInputFormat();
+                boolean autodetect = convertPanel.getInputAutodetect();
+                boolean collapse = convertPanel.getCollapse();
+                boolean gaps = convertPanel.getCollapseGaps();
+                boolean missing = convertPanel.getCollapseMissing();
+                int limit = convertPanel.getCollapseLimit();
+                String out = "";
+                String outO = convertPanel.getOutputOS();
+                String outP = convertPanel.getOutputProgram();
+                String outF = convertPanel.getOutputFormat();
+                boolean lower = convertPanel.getOutputLowerCase();
+                boolean numbers = convertPanel.getOutputResidueNumbers();
+                boolean sequential = convertPanel.getOutputSequential();
+                boolean match = convertPanel.getOutputMatch();
+
+                //Get converter and convert MSA
+                Factory factory = new DefaultFactory();
+                Converter converter;
+
+                try
+                {
+                    converter = factory.getConverter(inO, inP, inF, autodetect,
+                            collapse, gaps, missing, limit,
+                            outO, outP, outF, lower, numbers, sequential, match, logger.getName());
+                    out = converter.convert(in);
+                }
+                catch (UnsupportedOperationException ex)
+                {
+                    logger.log(Level.SEVERE, ex.getMessage());
+                    return;
+                }
+                catch (ParseException ex)
+                {
+                    logger.log(Level.SEVERE, "Failure parsing input file: \n" + ex.getMessage());
+                    return;
+                }
+                
+                //Update interface
+                output.setText(out);
+                SwingUtilities.invokeLater(new Runnable()
+                {
+
+                    public void run()
+                    {
+                        output.setEnabled(true);
+                        outputPosition.setEnabled(true);
+                        outputScroll.getVerticalScrollBar().setValue(0);
+                        outputScroll.getHorizontalScrollBar().setValue(0);
+                        saveOutputAsAction.setEnabled(true);
+                        saveOutputAction.setEnabled(true);
+                        saveAllAction.setEnabled(true);
+                    }
+                });
+            }
+        }
+    }
+
+    /**
+     * Java Action to ask for confirmation before exiting the application.
+     */
+    private class ExitAction extends AbstractAction
+    {
+
+        /**Class constructor
+         *@param text Text to display
+         *@param icon Action's icon
+         *@param desc Brief description
+         *@param mnemonic Keyboard shortcut
+         */
+        public ExitAction(String text, ImageIcon icon, String desc, Integer mnemonic)
+        {
+            //Initialize action
+            super(text, icon);
+            putValue(SHORT_DESCRIPTION, desc);
+            putValue(MNEMONIC_KEY, mnemonic);
+        }
+
+        /**Implements action
+         *@param e Event that triggers the action
+         */
+        public void actionPerformed(ActionEvent e)
+        {
+            //Show confirm dialog
+            int n = JOptionPane.showConfirmDialog(
+                    new JFrame(),
+                    "Are you sure you want to exit ALTER?",
+                    "Exit",
+                    JOptionPane.YES_NO_OPTION,
+                    JOptionPane.QUESTION_MESSAGE);
+            //If user confirms exit
+            if (n == JOptionPane.YES_OPTION)
+                System.exit(0);
+        }
+    }
+}
diff --git a/alter-lib/src/gui/package.html b/alter-lib/src/gui/package.html
new file mode 100755
index 0000000..5acfdaa
--- /dev/null
+++ b/alter-lib/src/gui/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    Graphical user interface implemented with SWING.
+    @author Daniel Gomez Blanco
+    @version 1.1
+  </body>
+</html>
diff --git a/alter-lib/src/org/kohsuke/args4j/Argument.java b/alter-lib/src/org/kohsuke/args4j/Argument.java
new file mode 100755
index 0000000..3c809be
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/Argument.java
@@ -0,0 +1,33 @@
+package org.kohsuke.args4j;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import org.kohsuke.args4j.spi.OptionHandler;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+
+/**
+ * Argument of the command line.
+ *
+ * This works mostly like {@link Option} except the following differences.
+ *
+ * <ol>
+ *  <li>Arguments have an index about their relative position on the command line.
+ * </ol>
+ * 
+ * @author Kohsuke Kawaguchi
+ * @author Mark Sinke
+ */
+ at Retention(RUNTIME)
+ at Target({FIELD,METHOD})
+public @interface Argument {
+    String usage() default "";
+    String metaVar() default "";
+    boolean required() default false;
+    Class<? extends OptionHandler> handler() default OptionHandler.class;
+    int index() default 0;
+    boolean multiValued() default false;
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/CmdLineException.java b/alter-lib/src/org/kohsuke/args4j/CmdLineException.java
new file mode 100755
index 0000000..6375de7
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/CmdLineException.java
@@ -0,0 +1,22 @@
+package org.kohsuke.args4j;
+
+/**
+ * Signals an error in the user input.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class CmdLineException extends Exception {
+	private static final long serialVersionUID = -8574071211991372980L;
+
+	public CmdLineException(String message) {
+        super(message);
+    }
+
+    public CmdLineException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public CmdLineException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/CmdLineParser.java b/alter-lib/src/org/kohsuke/args4j/CmdLineParser.java
new file mode 100755
index 0000000..d147159
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/CmdLineParser.java
@@ -0,0 +1,599 @@
+package org.kohsuke.args4j;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.kohsuke.args4j.spi.BooleanOptionHandler;
+import org.kohsuke.args4j.spi.ByteOptionHandler;
+import org.kohsuke.args4j.spi.CharOptionHandler;
+import org.kohsuke.args4j.spi.DoubleOptionHandler;
+import org.kohsuke.args4j.spi.EnumOptionHandler;
+import org.kohsuke.args4j.spi.FileOptionHandler;
+import org.kohsuke.args4j.spi.FloatOptionHandler;
+import org.kohsuke.args4j.spi.IntOptionHandler;
+import org.kohsuke.args4j.spi.LongOptionHandler;
+import org.kohsuke.args4j.spi.MapOptionHandler;
+import org.kohsuke.args4j.spi.OptionHandler;
+import org.kohsuke.args4j.spi.Parameters;
+import org.kohsuke.args4j.spi.Setter;
+import org.kohsuke.args4j.spi.ShortOptionHandler;
+import org.kohsuke.args4j.spi.StringOptionHandler;
+
+
+/**
+ * Command line argument owner.
+ *
+ * <p>
+ * For a typical usage, see <a href="https://args4j.dev.java.net/source/browse/args4j/args4j/examples/SampleMain.java?view=markup">this example</a>.
+ *
+ * @author
+ *     Kohsuke Kawaguchi (kk at kohsuke.org)
+ */
+public class CmdLineParser {
+    /**
+     * Option bean instance.
+     */
+    private final Object bean;
+
+    /**
+     * Discovered {@link OptionHandler}s for options.
+     */
+    private final List<OptionHandler> options = new ArrayList<OptionHandler>();
+
+    /**
+     * Discovered {@link OptionHandler}s for arguments.
+     */
+    private final List<OptionHandler> arguments = new ArrayList<OptionHandler>();
+    
+    private boolean parsingOptions = true;
+    private OptionHandler currentOptionHandler = null;
+
+	/**
+	 *  The length of a usage line. 
+	 *  If the usage message is longer than this value, the parser
+	 *  wraps the line. Defaults to 80.
+	 */
+	private int usageWidth = 80;
+
+    /**
+     * Creates a new command line owner that
+     * parses arguments/options and set them into
+     * the given object.
+     *
+     * @param bean
+     *      instance of a class annotated by {@link Option} and {@link Argument}.
+     *      this object will receive values.
+     *
+     * @throws IllegalAnnotationError
+     *      if the option bean class is using args4j annotations incorrectly.
+     */
+    public CmdLineParser(Object bean) {
+        this.bean = bean;
+
+        // recursively process all the methods/fields.
+        for( Class c=bean.getClass(); c!=null; c=c.getSuperclass()) {
+            for( Method m : c.getDeclaredMethods() ) {
+                Option o = m.getAnnotation(Option.class);
+                if(o!=null) {
+                    addOption(new MethodSetter(bean,m),o);
+                }
+                Argument a = m.getAnnotation(Argument.class);
+                if(a!=null) {
+                    addArgument(new MethodSetter(bean,m),a);
+                }
+            }
+
+            for( Field f : c.getDeclaredFields() ) {
+                Option o = f.getAnnotation(Option.class);
+                if(o!=null) {
+                    addOption(createFieldSetter(f),o);
+                }
+                Argument a = f.getAnnotation(Argument.class);
+                if(a!=null) {
+                    addArgument(createFieldSetter(f),a);
+                }
+            }
+        }
+        for (int i=0;i<arguments.size();++i) {
+        	if (arguments.get(i)==null) {
+                throw new IllegalAnnotationError("No argument annotation for index "+i);
+        	}
+        }
+
+        // for display purposes, we like the arguments in argument order, but the options in alphabetical order
+        Collections.sort(options, new Comparator<OptionHandler>() {
+			public int compare(OptionHandler o1, OptionHandler o2) {
+				return o1.option.toString().compareTo(o2.option.toString());
+			} 
+		});
+    }
+
+    private Setter createFieldSetter(Field f) {
+        if(List.class.isAssignableFrom(f.getType()))
+            return new MultiValueFieldSetter(bean,f);
+        else if(Map.class.isAssignableFrom(f.getType()))
+            return new MapSetter(bean,f);
+        else
+            return new FieldSetter(bean,f);
+    }
+
+    private void addArgument(Setter setter, Argument a) {
+        OptionHandler h = createOptionHandler(new OptionDef(a,setter.isMultiValued()),setter);
+    	int index = a.index();
+    	// make sure the argument will fit in the list
+    	while (index >= arguments.size()) {
+    		arguments.add(null);
+    	}
+    	if(arguments.get(index)!=null) {
+            throw new IllegalAnnotationError("Argument with index "+index+" is used more than once");
+        }
+    	arguments.set(index,h);
+    }
+
+    private void addOption(Setter setter, Option o) {
+        OptionHandler h = createOptionHandler(new NamedOptionDef(o,setter.isMultiValued()),setter);
+        checkOptionNotInMap(o.name());
+        for (String alias : o.aliases()) {
+        	checkOptionNotInMap(alias);
+        }
+        options.add(h);
+    }
+
+	private void checkOptionNotInMap(String name) throws IllegalAnnotationError {
+		if(findOptionByName(name)!=null) {
+            throw new IllegalAnnotationError("Option name "+name+" is used more than once");
+        }
+	}
+
+    /**
+     * Creates an {@link OptionHandler} that handles the given {@link Option} annotation
+     * and the {@link Setter} instance.
+     */
+    protected OptionHandler createOptionHandler(OptionDef o, Setter setter) {
+
+        Constructor<? extends OptionHandler> handlerType;
+        Class<? extends OptionHandler> h = o.handler();
+        if(h==OptionHandler.class) {
+            // infer the type
+
+            // enum is the special case
+            Class t = setter.getType();
+            if(Enum.class.isAssignableFrom(t))
+                return new EnumOptionHandler(this,o,setter,t);
+
+            handlerType = handlerClasses.get(t);
+            if(handlerType==null)
+                throw new IllegalAnnotationError("No OptionHandler is registered to handle "+t);
+        } else {
+            handlerType = getConstructor(h);
+        }
+
+        try {
+            return handlerType.newInstance(this,o,setter);
+        } catch (InstantiationException e) {
+            throw new IllegalAnnotationError(e);
+        } catch (IllegalAccessException e) {
+            throw new IllegalAnnotationError(e);
+        } catch (InvocationTargetException e) {
+            throw new IllegalAnnotationError(e);
+        }
+    }
+
+    /**
+     * Formats a command line example into a string.
+     *
+     * See {@link #printExample(ExampleMode, ResourceBundle)} for more details.
+     *
+     * @param mode
+     *      must not be null.
+     * @return
+     *      always non-null.
+     */
+    public String printExample(ExampleMode mode) {
+        return printExample(mode,null);
+    }
+
+    /**
+     * Formats a command line example into a string.
+     *
+     * <p>
+     * This method produces a string like " -d <dir> -v -b",
+     * which is useful for printing a command line example, perhaps
+     * as a part of the usage screen.
+     *
+     *
+     * @param mode
+     *      One of the {@link ExampleMode} constants. Must not be null.
+     *      This determines what option should be a part of the returned string.
+     * @param rb
+     *      If non-null, meta variables (<dir> in the above example)
+     *      is treated as a key to this resource bundle, and the associated
+     *      value is printed. See {@link Option#metaVar()}. This is to support
+     *      localization.
+     *
+     *      Passing <tt>null</tt> would print {@link Option#metaVar()} directly.
+     * @return
+     *      always non-null. If there's no option, this method returns
+     *      just the empty string "". Otherwise, this method returns a
+     *      string that contains a space at the beginning (but not at the end.)
+     *      This allows you to do something like:
+     *
+     *      <pre>System.err.println("java -jar my.jar"+parser.printExample(REQUIRED)+" arg1 arg2");</pre> 
+     */
+    public String printExample(ExampleMode mode,ResourceBundle rb) {
+        StringBuilder buf = new StringBuilder();
+
+        for (OptionHandler h : options) {
+            OptionDef option = h.option;
+            if(option.usage().length()==0)  continue;   // ignore
+            if(!mode.print(option))         continue;
+
+            buf.append(' ');
+            buf.append(h.getNameAndMeta(rb));
+        }
+
+        return buf.toString();
+    }
+
+    /**
+     * Prints the list of options and their usages to the screen.
+     *
+     * <p>
+     * This is a convenience method for calling {@code printUsage(new OutputStreamWriter(out),null)}
+     * so that you can do {@code printUsage(System.err)}.
+     */
+    public void printUsage(OutputStream out) {
+        printUsage(new OutputStreamWriter(out),null);
+    }
+    /**
+     * Prints the list of options and their usages to the screen.
+     *
+     * @param rb
+     *      if this is non-null, {@link Option#usage()} is treated
+     *      as a key to obtain the actual message from this resource bundle.
+     */
+    public void printUsage(Writer out, ResourceBundle rb) {
+        PrintWriter w = new PrintWriter(out);
+        // determine the length of the option + metavar first
+        int len = 0;
+        for (OptionHandler h : arguments) {
+            int curLen = getPrefixLen(h, rb);
+            len = Math.max(len,curLen);
+        }
+        for (OptionHandler h: options) {
+            int curLen = getPrefixLen(h, rb);
+            len = Math.max(len,curLen);
+        }
+
+        // then print
+        for (OptionHandler h : arguments) {
+        	printOption(w, h, len, rb);
+        }
+        for (OptionHandler h : options) {
+        	printOption(w, h, len, rb);
+        }
+
+        w.flush();
+    }
+    
+    private void printOption(PrintWriter w, OptionHandler h, int len, ResourceBundle rb) {
+        int descriptionWidth = usageWidth-len-4;    // 3 for " : " + 1 for left-most SP
+
+        String usage = h.option.usage();
+        if(usage.length()==0)   return;   // ignore
+
+        String nameAndMeta = h.getNameAndMeta(rb);
+        w.print(' ');
+       	w.print(nameAndMeta);
+       	for (int i = nameAndMeta.length(); i < len; ++i) {
+            w.print(' ');
+       	}
+        w.print(" : ");
+
+        if(rb!=null)
+            usage = rb.getString(usage);
+
+        while(usage!=null && usage.length()>0) {
+            int idx = usage.indexOf('\n');
+            if(idx>=0 && idx<=descriptionWidth) {
+                w.println(usage.substring(0,idx));
+                usage = usage.substring(idx+1);
+                if(usage.length()>0)
+                    indent(w,len+4);
+                continue;
+            }
+            if(usage.length()<=descriptionWidth) {
+                w.println(usage);
+                break;
+            }
+
+            w.println(usage.substring(0,descriptionWidth));
+            usage = usage.substring(descriptionWidth);
+            indent(w,len+4);
+        }
+    }
+
+	private int getPrefixLen(OptionHandler h, ResourceBundle rb) {
+		if(h.option.usage().length()==0)
+			return 0;
+         
+		return h.getNameAndMeta(rb).length();
+	}
+
+    private void indent(PrintWriter w, int i) {
+        for( ; i>0; i-- )
+            w.print(' ');
+    }
+
+
+    /**
+     * Essentially a pointer over a {@link String} array.
+     * Can move forward, can look ahead.
+     */
+    private class CmdLineImpl implements Parameters {
+        private final String[] args;
+        private int pos;
+
+        CmdLineImpl( String[] args ) {
+            this.args = args;
+            pos = 0;
+        }
+
+        protected boolean hasMore() {
+            return pos<args.length;
+        }
+
+        protected String getCurrentToken() {
+            return args[pos];
+        }
+
+        private void proceed( int n ) {
+            pos += n;
+        }
+
+        public String getParameter(int idx) throws CmdLineException {
+			if( pos+idx>=args.length )
+                throw new CmdLineException(Messages.MISSING_OPERAND.format(getOptionName()));
+            return args[pos+idx];
+        }
+    }
+
+    private String getOptionName() {
+        return currentOptionHandler.option.toString();
+    }
+
+    /**
+     * Parses the command line arguments and set them to the option bean
+     * given in the constructor.
+     * 
+     * @param args arguments to parse
+     *
+     * @throws CmdLineException
+     *      if there's any error parsing arguments, or if
+     *      {@link Option#required() required} option was not given.
+     */
+    public void parseArgument(final String... args) throws CmdLineException {
+        CmdLineImpl cmdLine = new CmdLineImpl(args);
+
+        Set<OptionHandler> present = new HashSet<OptionHandler>();
+        int argIndex = 0;
+
+        while( cmdLine.hasMore() ) {
+            String arg = cmdLine.getCurrentToken();
+            if( isOption(arg) ) {
+            	boolean isKeyValuePair = arg.indexOf('=')!=-1; 
+                // parse this as an option.
+                currentOptionHandler = isKeyValuePair ? findOptionHandler(arg) : findOptionByName(arg);
+                
+                if(currentOptionHandler==null) {
+                    // TODO: insert dynamic handler processing
+                    throw new CmdLineException(Messages.UNDEFINED_OPTION.format(arg));
+                }
+
+                // known option; skip its name
+                cmdLine.proceed(1);
+            } else {
+            	if (argIndex >= arguments.size()) {
+            		Messages msg = arguments.size() == 0 ? Messages.NO_ARGUMENT_ALLOWED : Messages.TOO_MANY_ARGUMENTS;
+                    throw new CmdLineException(msg.format(arg));
+            	}
+
+            	// known argument
+            	currentOptionHandler = arguments.get(argIndex); 
+            	if (!currentOptionHandler.option.isMultiValued())
+            		argIndex++;
+            }
+        	int diff = currentOptionHandler.parseArguments(cmdLine);
+        	cmdLine.proceed(diff);
+        	present.add(currentOptionHandler);
+        }
+
+        // make sure that all mandatory options are present
+        for (OptionHandler handler : options)
+            if(handler.option.required() && !present.contains(handler))
+                throw new CmdLineException(Messages.REQUIRED_OPTION_MISSING.format(handler.option.toString()));
+
+        // make sure that all mandatory arguments are present
+        for (OptionHandler handler : arguments)
+            if(handler.option.required() && !present.contains(handler))
+                throw new CmdLineException(Messages.REQUIRED_ARGUMENT_MISSING.format(handler.option.toString()));
+    }
+    
+	private OptionHandler findOptionHandler(String name) {
+		OptionHandler handler = findOptionByName(name);
+		if (handler==null) {
+			// Have not found by its name, maybe its a property?
+			// Search for parts of the name (=prefix) - most specific first 
+			for (int i=name.length(); i>1; i--) {
+				String prefix = name.substring(0, i);
+				Map<String,OptionHandler> possibleHandlers = filter(options, prefix);
+				handler = possibleHandlers.get(prefix);
+				if (handler!=null) return handler;
+			}
+		}
+		return handler;
+	}
+	
+	private OptionHandler findOptionByName(String name) {
+		for (OptionHandler h : options) {
+			NamedOptionDef option = (NamedOptionDef)h.option;
+			if (name.equals(option.name())) {
+				return h;
+			}
+			for (String alias : option.aliases()) {
+				if (name.equals(alias)) {
+					return h;
+				}
+			}
+		}
+		return null;
+	}
+	
+	
+	private Map<String,OptionHandler> filter(List<OptionHandler> opt, String keyFilter) {
+		Map<String,OptionHandler> rv = new TreeMap<String,OptionHandler>();
+		for (OptionHandler h : opt) {
+			if (opt.toString().startsWith(keyFilter)) rv.put(opt.toString(), h);
+		}
+		return rv;
+	}
+
+	
+    /**
+     * Returns true if the given token is an option
+     * (as opposed to an argument.)
+     */
+    protected boolean isOption(String arg) {
+        return parsingOptions && arg.startsWith("-");
+    }
+
+
+    /**
+     * All {@link OptionHandler}s known to the {@link CmdLineParser}.
+     *
+     * Constructors of {@link OptionHandler}-derived class keyed by their supported types.
+     */
+    private static final Map<Class,Constructor<? extends OptionHandler>> handlerClasses =
+            Collections.synchronizedMap(new HashMap<Class,Constructor<? extends OptionHandler>>());
+
+    /**
+     * Registers a user-defined {@link OptionHandler} class with args4j.
+     *
+     * <p>
+     * This method allows users to extend the behavior of args4j by writing
+     * their own {@link OptionHandler} implementation.
+     *
+     * @param valueType
+     *      The specified handler is used when the field/method annotated by {@link Option}
+     *      is of this type.
+     * @param handlerClass
+     *      This class must have the constructor that has the same signature as
+     *      {@link OptionHandler#OptionHandler(CmdLineParser, NamedOptionDef, Setter)}.
+     */
+    public static void registerHandler( Class valueType, Class<? extends OptionHandler> handlerClass ) {
+        if(valueType==null || handlerClass==null)
+            throw new IllegalArgumentException();
+        if(!OptionHandler.class.isAssignableFrom(handlerClass))
+            throw new IllegalArgumentException("Not an OptionHandler class");
+
+        Constructor<? extends OptionHandler> c = getConstructor(handlerClass);
+        handlerClasses.put(valueType,c);
+    }
+
+    private static Constructor<? extends OptionHandler> getConstructor(Class<? extends OptionHandler> handlerClass) {
+        try {
+            return handlerClass.getConstructor(CmdLineParser.class, OptionDef.class, Setter.class);
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException(handlerClass+" does not have the proper constructor");
+        }
+    }
+
+    static {
+        registerHandler(Boolean.class,BooleanOptionHandler.class);
+        registerHandler(boolean.class,BooleanOptionHandler.class);
+        registerHandler(File.class,FileOptionHandler.class);
+        registerHandler(Integer.class,IntOptionHandler.class);
+        registerHandler(int.class,IntOptionHandler.class);
+        registerHandler(Double.class, DoubleOptionHandler.class);
+        registerHandler(double.class,DoubleOptionHandler.class);
+        registerHandler(String.class,StringOptionHandler.class);
+        registerHandler(Byte.class, ByteOptionHandler.class);
+        registerHandler(byte.class, ByteOptionHandler.class);
+        registerHandler(Character.class, CharOptionHandler.class);
+        registerHandler(char.class, CharOptionHandler.class);
+        registerHandler(Float.class, FloatOptionHandler.class);
+        registerHandler(float.class, FloatOptionHandler.class);
+        registerHandler(Long.class, LongOptionHandler.class);
+        registerHandler(long.class, LongOptionHandler.class);
+        registerHandler(Short.class, ShortOptionHandler.class);
+        registerHandler(short.class, ShortOptionHandler.class);
+        // enum is a special case
+        registerHandler(Map.class,MapOptionHandler.class);
+    }
+
+	public void setUsageWidth(int usageWidth) {
+		this.usageWidth = usageWidth;
+	}
+	
+	public void stopOptionParsing() {
+		parsingOptions = false;
+	}
+
+    /**
+     * Prints a single-line usage to the screen.
+     *
+     * <p>
+     * This is a convenience method for calling {@code printUsage(new OutputStreamWriter(out),null)}
+     * so that you can do {@code printUsage(System.err)}.
+     */
+	public void printSingleLineUsage(OutputStream out) {
+		printSingleLineUsage(new OutputStreamWriter(out),null);
+	}
+	
+    /**
+     * Prints a single-line usage to the screen.
+     *
+     * @param rb
+     *      if this is non-null, {@link Option#usage()} is treated
+     *      as a key to obtain the actual message from this resource bundle.
+     */
+	public void printSingleLineUsage(Writer w, ResourceBundle rb) {
+		PrintWriter pw = new PrintWriter(w);
+		for (OptionHandler h : arguments) {
+			printSingleLineOption(pw, h, rb);
+		}
+		for (OptionHandler h : options) {
+			printSingleLineOption(pw, h, rb);
+		}
+		pw.flush();
+	}
+
+	private void printSingleLineOption(PrintWriter pw, OptionHandler h, ResourceBundle rb) {
+		pw.print(' ');
+		if (!h.option.required())
+			pw.print('[');
+		pw.print(h.getNameAndMeta(rb));
+		if (h.option.isMultiValued()) {
+			pw.print(" ...");
+		}
+		if (!h.option.required())
+			pw.print(']');
+	} 
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/ExampleMode.java b/alter-lib/src/org/kohsuke/args4j/ExampleMode.java
new file mode 100755
index 0000000..c3a4b18
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/ExampleMode.java
@@ -0,0 +1,33 @@
+package org.kohsuke.args4j;
+
+/**
+ * Used with {@link CmdLineParser#printExample(ExampleMode)}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public enum ExampleMode {
+    /**
+     * Print all defined options in the example.
+     *
+     * <p>
+     * This would be useful only when you have small number of options.
+     */
+    ALL() {
+    	@Override
+        /*package*/ boolean print(OptionDef o) {
+            return true;
+        }
+    },
+
+    /**
+     * Print all {@link Option#required() required} option.
+     */
+    REQUIRED() {
+    	@Override
+        /*package*/ boolean print(OptionDef o) {
+            return o.required();
+        }
+    };
+
+    /*package*/ abstract boolean print(OptionDef o);
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/FieldSetter.java b/alter-lib/src/org/kohsuke/args4j/FieldSetter.java
new file mode 100755
index 0000000..b1ff1b7
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/FieldSetter.java
@@ -0,0 +1,42 @@
+package org.kohsuke.args4j;
+
+import org.kohsuke.args4j.spi.Setter;
+
+import java.lang.reflect.Field;
+
+/**
+ * {@link Setter} that sets to a {@link Field}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+final class FieldSetter implements Setter {
+    private final Field f;
+    private final Object bean;
+
+    public FieldSetter(Object bean, Field f) {
+        this.bean = bean;
+        this.f = f;
+    }
+
+    public Class getType() {
+        return f.getType();
+    }
+    
+    public boolean isMultiValued() {
+    	return false;
+    }
+
+    public void addValue(Object value) {
+        try {
+            f.set(bean,value);
+        } catch (IllegalAccessException e) {
+            // try again
+            f.setAccessible(true);
+            try {
+                f.set(bean,value);
+            } catch (IllegalAccessException e2) {
+                throw new IllegalAccessError(e2.getMessage());
+            }
+        }
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/IllegalAnnotationError.java b/alter-lib/src/org/kohsuke/args4j/IllegalAnnotationError.java
new file mode 100755
index 0000000..d7fab10
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/IllegalAnnotationError.java
@@ -0,0 +1,27 @@
+package org.kohsuke.args4j;
+
+/**
+ * Signals an incorrect use of args4j annotations.
+ *
+ * <p>
+ * This only happens when there's something wrong with the way you use
+ * args4j in your code, not when the arguments supplied by the user is
+ * wrong. Hence this class is an {@link Error}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class IllegalAnnotationError extends Error {
+	private static final long serialVersionUID = 2397757838147693218L;
+
+	public IllegalAnnotationError(String message) {
+        super(message);
+    }
+
+    public IllegalAnnotationError(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public IllegalAnnotationError(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/MapSetter.java b/alter-lib/src/org/kohsuke/args4j/MapSetter.java
new file mode 100755
index 0000000..f84f07a
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/MapSetter.java
@@ -0,0 +1,65 @@
+package org.kohsuke.args4j;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.kohsuke.args4j.spi.Setter;
+
+public class MapSetter implements Setter {
+    private final Field f;
+    private final Object bean;
+    
+    
+    public MapSetter(Object bean, Field f) {
+		super();
+		this.f = f;
+		this.bean = bean;
+	}
+
+	public Class getType() {
+        return f.getType();
+    }
+    
+    public boolean isMultiValued() {
+    	return false;
+    }
+
+    public void addValue(Object value) {
+    	if (String.valueOf(value).indexOf('=') == -1) {
+    		throw new RuntimeException("An argument for setting a Map must contain a '='");
+    	}
+    	
+    	String[] parts = String.valueOf(value).split("=");
+    	String mapKey   = parts[0];
+    	String mapValue = (parts.length > 1) ? parts[1] : null;
+    	
+    	if (mapKey == null || mapKey.length()==0) {
+    		throw new RuntimeException("A key must be set.");
+    	}
+    	
+        try {
+            addValue(mapKey, mapValue);
+        } catch (IllegalAccessException e) {
+            // try again
+            f.setAccessible(true);
+            try {
+                addValue(mapKey, mapValue);
+            } catch (IllegalAccessException e2) {
+                throw new IllegalAccessError(e2.getMessage());
+            }
+        }
+    }
+    
+    private void addValue(Object key, Object value) throws IllegalArgumentException, IllegalAccessException {
+    	Map map = (Map) f.get(bean);
+    	if (map == null) {
+    		// Field is null so set it to an empty Map
+    		map = new HashMap();
+    		// and reset the field on the bean not just the local reference
+    		f.set(bean,	map);
+    	}
+    	map.put(key, value);
+    }
+
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/Messages.java b/alter-lib/src/org/kohsuke/args4j/Messages.java
new file mode 100755
index 0000000..327756b
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/Messages.java
@@ -0,0 +1,29 @@
+package org.kohsuke.args4j;
+
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+/**
+ * @author Kohsuke Kawaguchi
+ */
+enum Messages {
+    MISSING_OPERAND,
+    UNDEFINED_OPTION,
+    NO_ARGUMENT_ALLOWED,
+    ILLEGAL_METHOD_SIGNATURE,
+    ILLEGAL_FIELD_SIGNATURE,
+    REQUIRED_OPTION_MISSING,
+    TOO_MANY_ARGUMENTS,
+    REQUIRED_ARGUMENT_MISSING
+    ;
+
+    private static ResourceBundle rb;
+
+    public String format( Object... args ) {
+        synchronized(Messages.class) {
+            if(rb==null)
+                rb = ResourceBundle.getBundle(Messages.class.getName());
+            return MessageFormat.format(rb.getString(name()),args);
+        }
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/Messages.properties b/alter-lib/src/org/kohsuke/args4j/Messages.properties
new file mode 100755
index 0000000..b4aa038
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/Messages.properties
@@ -0,0 +1,25 @@
+MISSING_OPERAND = \
+    Option "{0}" takes an operand
+
+UNDEFINED_OPTION = \
+    "{0}" is not a valid option
+
+NO_ARGUMENT_ALLOWED = \
+    No argument is allowed: {0}
+
+ILLEGAL_METHOD_SIGNATURE = \
+    Method {0} takes more than one parameter
+
+ILLEGAL_FIELD_SIGNATURE = \
+    Field of type {0} isn't supported by args4j 
+
+REQUIRED_OPTION_MISSING = \
+    Option "{0}" is required
+    
+REQUIRED_ARGUMENT_MISSING = \
+    Argument "{0}" is required
+    
+TOO_MANY_ARGUMENTS = \
+    Too many arguments: {0}
+
+    
\ No newline at end of file
diff --git a/alter-lib/src/org/kohsuke/args4j/MethodSetter.java b/alter-lib/src/org/kohsuke/args4j/MethodSetter.java
new file mode 100755
index 0000000..15b5763
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/MethodSetter.java
@@ -0,0 +1,61 @@
+package org.kohsuke.args4j;
+
+import org.kohsuke.args4j.spi.Setter;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * {@link Setter} that sets to a {@link Method}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+final class MethodSetter implements Setter {
+    private final Object bean;
+    private final Method m;
+
+    public MethodSetter(Object bean, Method m) {
+        this.bean = bean;
+        this.m = m;
+        if(m.getParameterTypes().length!=1)
+            throw new IllegalAnnotationError(Messages.ILLEGAL_METHOD_SIGNATURE.format(m));
+    }
+
+    public Class getType() {
+        return m.getParameterTypes()[0];
+    }
+
+    public boolean isMultiValued() {
+    	return false;
+    }
+
+    public void addValue(Object value) throws CmdLineException {
+        try {
+            try {
+                m.invoke(bean,value);
+            } catch (IllegalAccessException e) {
+                // try again
+                m.setAccessible(true);
+                try {
+                    m.invoke(bean,value);
+                } catch (IllegalAccessException e2) {
+                    throw new IllegalAccessError(e2.getMessage());
+                }
+            }
+        } catch (InvocationTargetException e) {
+            Throwable t = e.getTargetException();
+            if(t instanceof RuntimeException)
+                throw (RuntimeException)t;
+            if(t instanceof Error)
+                throw (Error)t;
+            if(t instanceof CmdLineException)
+                throw (CmdLineException)t;
+
+            // otherwise wrap
+            if(t!=null)
+                throw new CmdLineException(t);
+            else
+                throw new CmdLineException(e);
+        }
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/MultiValueFieldSetter.java b/alter-lib/src/org/kohsuke/args4j/MultiValueFieldSetter.java
new file mode 100755
index 0000000..5f05ad2
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/MultiValueFieldSetter.java
@@ -0,0 +1,69 @@
+package org.kohsuke.args4j;
+
+import org.kohsuke.args4j.spi.Setter;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@link Setter} that sets multiple values to a collection {@link Field}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+final class MultiValueFieldSetter  implements Setter {
+    private final Object bean;
+    private final Field f;
+
+    public MultiValueFieldSetter(Object bean, Field f) {
+        this.bean = bean;
+        this.f = f;
+
+        if(!List.class.isAssignableFrom(f.getType()))
+            throw new IllegalAnnotationError(Messages.ILLEGAL_FIELD_SIGNATURE.format(f.getType()));
+    }
+
+    public boolean isMultiValued() {
+    	return true;
+    }
+
+    public Class getType() {
+        // TODO: compute this correctly
+        Type t = f.getGenericType();
+        if(t instanceof ParameterizedType) {
+            ParameterizedType pt = (ParameterizedType)t;
+            t = pt.getActualTypeArguments()[0];
+            if(t instanceof Class)
+                return (Class)t;
+        }
+        return Object.class;
+    }
+
+    public void addValue(Object value) {
+        try {
+            doAddValue(bean, value);
+        } catch (IllegalAccessException e) {
+            // try again
+            f.setAccessible(true);
+            try {
+                doAddValue(bean,value);
+            } catch (IllegalAccessException e2) {
+                throw new IllegalAccessError(e2.getMessage());
+            }
+        }
+    }
+
+    private void doAddValue(Object bean, Object value) throws IllegalAccessException {
+        Object o = f.get(bean);
+        if(o==null) {
+            o = new ArrayList();
+            f.set(bean,o);
+        }
+        if(!(o instanceof List))
+            throw new IllegalAnnotationError("type of "+f+" is not a List");
+
+        ((List)o).add(value);
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/NamedOptionDef.java b/alter-lib/src/org/kohsuke/args4j/NamedOptionDef.java
new file mode 100755
index 0000000..5ad895a
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/NamedOptionDef.java
@@ -0,0 +1,44 @@
+package org.kohsuke.args4j;
+
+/**
+ * Run-time copy of the Option or Argument annotation.
+ */
+public final class NamedOptionDef extends OptionDef {
+    private final String name;
+	private final String[] aliases;
+    
+    public NamedOptionDef(Option o, boolean forceMultiValued) {
+    	super(o.usage(),o.metaVar(),o.required(),o.handler(),o.multiValued() || forceMultiValued);
+    	
+    	this.name = o.name();
+    	this.aliases = o.aliases();
+    }
+    
+    public String name() {
+    	return name;
+    }
+    
+    public String[] aliases() {
+    	return aliases;
+    }
+    
+    @Override
+    public String toString() {
+    	if (aliases.length > 0) {
+    		String str = "";
+    		for (String alias : aliases) {
+    			if (str.length() > 0) {
+    				str += ", ";
+    			}
+    			str += alias;
+    		}
+    		return name() + " (" + str + ")";
+    	}
+    	return name();
+    }
+    
+    @Override
+    public boolean isArgument() {
+    	return false;
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/Option.java b/alter-lib/src/org/kohsuke/args4j/Option.java
new file mode 100755
index 0000000..05433ad
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/Option.java
@@ -0,0 +1,167 @@
+package org.kohsuke.args4j;
+
+import org.kohsuke.args4j.spi.OptionHandler;
+
+import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.lang.reflect.AccessibleObject;
+import java.util.ResourceBundle;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Marks a field/setter that receives a command line switch value.
+ *
+ * <p>
+ * This annotation can be placed on a field of type T or the method
+ * of the form <tt>void <i>methodName</i>(T value)</tt>. Its access
+ * modified can be anything, but if it's not public, your application
+ * needs to run in a security context that allows args4j to access
+ * the field/method (see {@link AccessibleObject#setAccessible(boolean)}.
+ *
+ * <p>
+ * The behavior of the annotation differs depending on T --- the type
+ * of the field or the parameter of the method.
+ *
+ * <h2>Boolean Switch</h2>
+ * <p>
+ * When T is boolean , it represents
+ * a boolean option that takes the form of "-OPT". When this option is set,
+ * the property will be set to true.
+ *
+ * <h2>String Switch</h2>
+ * <p>
+ * When T is {@link String}, it represents
+ * an option that takes one operand. The value of the operand is set
+ * to the property.
+ *
+ * <h2>Enum Switch</h2>
+ * <p>
+ * When T is derived from {@link Enum}, it represents an option that takes
+ * an operand, which must be one of the enum constant. The comparion between
+ * the operand and the enum constant name is done in a case insensitive fashion.
+ * <p>
+ * For example, the following definition will represent command line options
+ * like "-coin penny" or "-coin DIME" but things like "-coin" or "-coin abc" are
+ * errors.
+ *
+ * <pre>
+ * enum Coin { PENNY,NICKEL,DIME,QUARTER }
+ *
+ * class Option {
+ *   @Option(name="-coin")
+ *   public Coin coin;
+ * }
+ * </pre>
+ *
+ * <h2>File Switch</h2>
+ * <p>
+ * When T is a {@link File}, it represents an option that takes a file/directory
+ * name as an operand.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+ at Retention(RUNTIME)
+ at Target({FIELD,METHOD})
+public @interface Option {
+    /**
+     * Name of the option, such as "-foo" or "-bar".
+     */
+    String name();
+    
+    /**
+     * Aliases for the options, such as "--long-option-name".
+     */
+    String[] aliases() default { };
+
+    /**
+     * Help string used to display the usage screen.
+     *
+     * <p>
+     * This parameter works in two ways. For a simple use,
+     * you can just encode the human-readable help string directly,
+     * and that will be used as the message. This is easier,
+     * but it doesn't support localization.
+     *
+     * <p>
+     * For more advanced use, this property is set to a key of a
+     * {@link ResourceBundle}. The actual message is obtained
+     * by querying a {@link ResourceBundle} instance supplied to
+     * {@link CmdLineParser} by this key. This allows the usage
+     * screen to be properly localized.
+     *
+     * <p>
+     * If this value is empty, the option will not be displayed
+     * in the usage screen.
+     */
+    String usage() default "";
+
+    /**
+     * When the option takes an operand, the usage screen will show something like this:
+     * <pre>
+     * -x FOO  : blah blah blah
+     * </pre>
+     * You can replace the 'FOO' token by using this parameter.
+     *
+     * <p>
+     * If left unspecifiied, this value is infered from the type of the option.
+     *
+     * <p>
+     * Just like {@link #usage()}, normally, this value is printed as is.
+     * But if a {@link ResourceBundle} is given to the {@link CmdLineParser},
+     * it will be used to obtain the locale-specific value.
+     */
+    String metaVar() default "";
+
+    /**
+     * Specify that the option is mandatory.
+     *
+     * <p>
+     * At the end of {@link CmdLineParser#parseArgument(String...)},
+     * a {@link CmdLineException} will be thrown if a required option
+     * is not present.
+     *
+     * <p>
+     * Note that in most of the command line interface design principles,
+     * options should be really optional. So use caution when using this
+     * flag.
+     */
+    boolean required() default false;
+
+    /**
+     * Specify the {@link OptionHandler} that processes the command line arguments.
+     *
+     * <p>
+     * The default value {@link OptionHandler} indicates that
+     * the {@link OptionHandler} will be infered from
+     * the type of the field/method where a {@link Option} annotation
+     * is placed.
+     *
+     * <p>
+     * If this annotation element is used, it overrides the inference
+     * and determines the handler to be used. This is convenient for
+     * defining a non-standard option parsing semantics.
+     *
+     * <h3>Example</h3>
+     * <pre>
+     * // this is a normal "-r" option
+     * @Option(name="-r")
+     * boolean value;
+     *
+     * // this causes arg4j to use MyHandler, not the default
+     * // handler provided for boolean
+     * @Option(name="-b",handler=MyHandler.class)
+     * boolean value;
+     * </pre>
+     */
+    Class<? extends OptionHandler> handler() default OptionHandler.class;
+    
+    /**
+     * Whether the option is multi-valued.
+     * For mappings to List<...>, this defaults to true, otherwise false 
+     */
+    boolean multiValued() default false;
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/OptionDef.java b/alter-lib/src/org/kohsuke/args4j/OptionDef.java
new file mode 100755
index 0000000..6192e14
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/OptionDef.java
@@ -0,0 +1,63 @@
+/**
+ * (c) 2006 forcare BV
+ * All rights reserved.
+ */
+package org.kohsuke.args4j;
+
+import org.kohsuke.args4j.spi.OptionHandler;
+
+/**
+ * Run-time copy of the Option or Argument annotation. By definition, unnamed options
+ * are arguments (and instances of this class). Named options are actually a subclass.
+ * 
+ * @author Mark Sinke
+ */
+public class OptionDef {
+	private final String usage;
+	private final String metaVar;
+	private final boolean required;
+	private final boolean multiValued;
+	private final Class<? extends OptionHandler> handler;
+
+	public OptionDef(Argument a, boolean forceMultiValued) {
+		this(a.usage(), a.metaVar(), a.required(), a.handler(), a.multiValued() || forceMultiValued);
+	}
+
+	protected OptionDef(String usage, String metaVar, boolean required,
+			Class<? extends OptionHandler> handler, boolean multiValued) {
+		this.usage = usage;
+		this.metaVar = metaVar;
+		this.required = required;
+		this.handler = handler;
+		this.multiValued = multiValued;
+	}
+
+	public String usage() {
+		return usage;
+	}
+
+	public String metaVar() {
+		return metaVar;
+	}
+
+	public boolean required() {
+		return required;
+	}
+
+	public Class<? extends OptionHandler> handler() {
+		return handler;
+	}
+
+	public boolean isMultiValued() {
+		return multiValued;
+	}
+	
+	public boolean isArgument() {
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return metaVar() != null ? metaVar() : "ARG";
+	}
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/Starter.java b/alter-lib/src/org/kohsuke/args4j/Starter.java
new file mode 100755
index 0000000..25de6a3
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/Starter.java
@@ -0,0 +1,109 @@
+package org.kohsuke.args4j;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Starter class which uses reflection to instantiate the business
+ * class, parse the command line parameters, sets the fields of the
+ * business class and doing the help message handling.
+ *  
+ * @author Jan Materne
+ */
+public class Starter {
+	
+	/**
+	 * The name of the JavaVM property which stores the class name of
+	 * the business class.
+	 * {@value} 
+	 */
+	public static final String PARAMETER_NAME = "mainclass";
+
+	public static void main(String[] args) {
+		String classname = System.getProperty(PARAMETER_NAME);
+		CmdLineParser parser = null;
+		boolean classHasArgument = false;
+		boolean classHasOptions  = false;
+		
+		// Check the requirement: must specify the class to start
+		if (classname == null || "".equals(classname)) {
+			System.err.println("The system property '" 
+					+ PARAMETER_NAME
+					+ "' must contain the classname to start.");
+			System.exit(-1);
+		}
+		
+		try {
+			Class clazz = Class.forName(classname);
+			Object bean = clazz.newInstance();
+			parser = new CmdLineParser(bean);
+			
+			// for help output
+			classHasArgument = hasAnnotation(clazz, Argument.class);
+			classHasOptions  = hasAnnotation(clazz, Option.class);
+			
+			parser.parseArgument(args);
+			
+			// try starting   run()
+			Method m;
+			boolean couldInvoke = false;
+			try {
+				m = clazz.getMethod("run", (Class[]) null);
+				m.invoke(bean, (Object[]) null);
+				couldInvoke = true;
+			} catch (SecurityException e) {
+			} catch (IllegalArgumentException e) {
+			} catch (NoSuchMethodException e) {
+			} catch (IllegalAccessException e) {
+			} catch (InvocationTargetException e) {
+			}
+
+			// try starting   run(String[])
+			if (!couldInvoke) try {
+				m = clazz.getMethod("run", String[].class);		
+				m.invoke(bean, new Object[]{args});
+				couldInvoke = true;
+			} catch (SecurityException e) {
+			} catch (IllegalArgumentException e) {
+				e.printStackTrace();
+			} catch (NoSuchMethodException e) {
+			} catch (IllegalAccessException e) {
+			} catch (InvocationTargetException e) {
+			}
+		} catch (ClassNotFoundException e) {
+			// wrong classpath setting
+			System.err.println("Cant find the class '" 
+					+ classname
+					+ "' as specified in the system property '"
+					+ PARAMETER_NAME + "'.");
+		} catch (CmdLineException e) {
+			// wrong argument enteres, so print the usage message as
+			// supplied by args4j
+			System.err.println(e.getMessage());
+			System.err.print(classname);
+			if (classHasOptions)  System.err.print(" [options]");
+			if (classHasArgument) System.err.print(" arguments");
+			System.err.println();
+			if (parser != null)
+				parser.printUsage(System.err);
+		} catch (Exception e) {
+			// Must be an unhandled business exception, so we can only
+			// print stacktraces.
+			e.printStackTrace();
+		}
+	}
+
+	public static boolean hasAnnotation(Class clazz, Class<? extends Annotation> annotation) {
+		if (clazz.getAnnotation(annotation)!=null) return true;
+		for (Field f : clazz.getFields()) {
+			if (f.getAnnotation(annotation)!=null) return true;
+		}
+		for (Method m : clazz.getMethods()) {
+			if (m.getAnnotation(annotation)!=null) return true;
+		}
+		return false;
+	}
+	
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/package.html b/alter-lib/src/org/kohsuke/args4j/package.html
new file mode 100755
index 0000000..5723201
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/package.html
@@ -0,0 +1,14 @@
+<!--
+To change this template, choose Tools | Templates
+and open the template in the editor.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    Paquete principal del parseador de línea de comandos args4j.
+  </body>
+</html>
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/BooleanOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/BooleanOptionHandler.java
new file mode 100755
index 0000000..2a0356f
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/BooleanOptionHandler.java
@@ -0,0 +1,43 @@
+package org.kohsuke.args4j.spi;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * Boolean {@link OptionHandler}.
+ * 
+ * @author Kohsuke Kawaguchi
+ */
+public class BooleanOptionHandler extends OptionHandler<Boolean> {
+	private static final List<String> ACCEPTABLE_VALUES = Arrays.asList(new String[] { "true", "on", "yes", "1",
+			"false", "off", "no", "0" });
+	
+	public BooleanOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Boolean> setter) {
+        super(parser, option, setter);
+    }
+
+    @Override
+    public int parseArguments(Parameters params) throws CmdLineException {
+    	if (option.isArgument()) {
+    		String valueStr = params.getParameter(0).toLowerCase();
+    		int index = ACCEPTABLE_VALUES.indexOf(valueStr);
+    		if (index == -1) {
+    			throw new CmdLineException(Messages.ILLEGAL_BOOLEAN.format(valueStr));
+    		}
+    		setter.addValue(index < ACCEPTABLE_VALUES.size() / 2);
+    		return 1;
+    	} else {
+    		setter.addValue(true);
+    		return 0;
+    	}
+    }
+
+    @Override
+    public String getDefaultMetaVariable() {
+        return null;
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/ByteOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/ByteOptionHandler.java
new file mode 100755
index 0000000..4bff552
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/ByteOptionHandler.java
@@ -0,0 +1,24 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link Byte}
+ * {@link OptionHandler}
+ * {@link OneArgumentOptionHandler}
+ * @author Jan Materne
+ * @since 2.0.9
+ */
+public class ByteOptionHandler extends OneArgumentOptionHandler<Byte> {
+
+	public ByteOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Byte> setter) {
+		super(parser, option, setter);
+	}
+
+	@Override
+	protected Byte parse(String argument) throws NumberFormatException {
+		return Byte.parseByte(argument);
+	}
+
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/CharOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/CharOptionHandler.java
new file mode 100755
index 0000000..a242985
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/CharOptionHandler.java
@@ -0,0 +1,23 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link Char}
+ * {@link OptionHandler}
+ * {@link OneArgumentOptionHandler}
+ * @author Jan Materne
+ * @since 2.0.9
+ */
+public class CharOptionHandler extends OneArgumentOptionHandler<Character> {
+
+	public CharOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Character> setter) {
+		super(parser, option, setter);
+	}
+
+	@Override
+	protected Character parse(String argument) throws NumberFormatException {
+		return argument.charAt(0);
+	}
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/DoubleOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/DoubleOptionHandler.java
new file mode 100755
index 0000000..10f0dcc
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/DoubleOptionHandler.java
@@ -0,0 +1,21 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link Double} 
+ * {@link OptionHandler}.
+ * {@link OneArgumentOptionHandler}
+ * @author Leif Wickland
+ */
+public class DoubleOptionHandler extends OneArgumentOptionHandler<Double> {
+    public DoubleOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Double> setter) {
+        super(parser, option, setter);
+    }
+
+    @Override
+    protected Double parse(String argument) throws NumberFormatException {
+    	return Double.parseDouble(argument);
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/EnumOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/EnumOptionHandler.java
new file mode 100755
index 0000000..d1f52a5
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/EnumOptionHandler.java
@@ -0,0 +1,53 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link Enum} {@link OptionHandler}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class EnumOptionHandler<T extends Enum<T>> extends OptionHandler<T> {
+
+    private final Class<T> enumType;
+
+    public EnumOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super T> setter, Class<T> enumType) {
+        super(parser, option, setter);
+        this.enumType = enumType;
+    }
+
+    @Override
+    public int parseArguments(Parameters params) throws CmdLineException {
+        String s = params.getParameter(0);
+        T value = null;
+        for( T o : enumType.getEnumConstants() )
+            if(o.name().equalsIgnoreCase(s)) {
+                value = o;
+                break;
+            }
+
+        if(value==null)
+            throw new CmdLineException(Messages.ILLEGAL_OPERAND.format(option.toString(),s));
+        setter.addValue(value);
+        return 1;
+    }
+
+    /* 
+     * Returns all values of an enum type split by pipe.
+     * <tt>[ one | two | three]</tt>
+     * @see org.kohsuke.args4j.spi.OptionHandler#getDefaultMetaVariable()
+     */
+    @Override
+    public String getDefaultMetaVariable() {
+    	StringBuffer rv = new StringBuffer();
+    	rv.append("[");
+    	for (T t : enumType.getEnumConstants()) {
+			rv.append(t).append(" | ");
+		}
+    	rv.delete(rv.length()-3, rv.length());
+    	rv.append("]");
+    	return rv.toString();
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/FileOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/FileOptionHandler.java
new file mode 100755
index 0000000..e1c23ab
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/FileOptionHandler.java
@@ -0,0 +1,29 @@
+package org.kohsuke.args4j.spi;
+
+import java.io.File;
+
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+
+/**
+ * {@link File} {@link OptionHandler}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class FileOptionHandler extends OptionHandler<File> {
+    public FileOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super File> setter) {
+        super(parser, option, setter);
+    }
+
+    @Override
+    public int parseArguments(Parameters params) throws CmdLineException {
+        setter.addValue(new File(params.getParameter(0)));
+        return 1;
+    }
+
+    @Override
+    public String getDefaultMetaVariable() {
+        return "FILE";
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/FloatOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/FloatOptionHandler.java
new file mode 100755
index 0000000..6442328
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/FloatOptionHandler.java
@@ -0,0 +1,26 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link Float} 
+ * {@link OptionHandler}
+ * {@link OneArgumentOptionHandler}
+ * 
+ * @author Jan Materne
+ * @since 2.0.9
+ */
+public class FloatOptionHandler extends OneArgumentOptionHandler<Float> {
+
+	public FloatOptionHandler(CmdLineParser parser, OptionDef option,
+			Setter<? super Float> setter) {
+		super(parser, option, setter);
+	}
+
+	@Override
+	protected Float parse(String argument) throws NumberFormatException {
+		return Float.parseFloat(argument);
+	}
+
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/IntOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/IntOptionHandler.java
new file mode 100755
index 0000000..d26ffe6
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/IntOptionHandler.java
@@ -0,0 +1,22 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link Integer} 
+ * {@link OptionHandler}.
+ * {@link OneArgumentOptionHandler}
+ * 
+ * @author Kohsuke Kawaguchi
+ */
+public class IntOptionHandler extends OneArgumentOptionHandler<Integer> {
+	public IntOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Integer> setter) {
+		super(parser, option, setter);
+	}
+
+	@Override
+	protected Integer parse(String argument) throws NumberFormatException {
+		return Integer.parseInt(argument);
+	}
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/LongOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/LongOptionHandler.java
new file mode 100755
index 0000000..e139996
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/LongOptionHandler.java
@@ -0,0 +1,24 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link Long}
+ * {@link OptionHandler}
+ * {@link OneArgumentOptionHandler}
+ * @author Jan Materne
+ * @since 2.0.9
+ */
+public class LongOptionHandler extends OneArgumentOptionHandler<Long> {
+
+	public LongOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Long> setter) {
+		super(parser, option, setter);
+	}
+
+	@Override
+	protected Long parse(String argument) throws NumberFormatException {
+		return Long.parseLong(argument);
+	}
+
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/MapOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/MapOptionHandler.java
new file mode 100755
index 0000000..dad6870
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/MapOptionHandler.java
@@ -0,0 +1,32 @@
+package org.kohsuke.args4j.spi;
+
+import java.util.Map;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.MapSetter;
+import org.kohsuke.args4j.OptionDef;
+
+public class MapOptionHandler extends OptionHandler<Map<?,?>> {
+
+	public MapOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Map<?,?>> setter) {
+		super(parser, option, setter);
+	}
+
+	@Override
+	public String getDefaultMetaVariable() {
+		return null;
+	}
+
+	@Override
+	public int parseArguments(Parameters params) throws CmdLineException {
+		MapSetter mapSetter = (MapSetter)setter;
+		try {
+			mapSetter.addValue(params.getParameter(0));
+		} catch (RuntimeException e) {
+			throw new CmdLineException(e.getMessage());
+		}
+        return 1;
+	}
+
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/Messages.java b/alter-lib/src/org/kohsuke/args4j/spi/Messages.java
new file mode 100755
index 0000000..a4681e2
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/Messages.java
@@ -0,0 +1,23 @@
+package org.kohsuke.args4j.spi;
+
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+/**
+ * @author Kohsuke Kawaguchi
+ */
+enum Messages {
+    ILLEGAL_OPERAND,
+    ILLEGAL_BOOLEAN
+    ;
+
+    private static ResourceBundle rb;
+
+    public String format( Object... args ) {
+        synchronized(Messages.class) {
+            if(rb==null)
+                rb = ResourceBundle.getBundle(Messages.class.getName());
+            return MessageFormat.format(rb.getString(name()),args);
+        }
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/Messages.properties b/alter-lib/src/org/kohsuke/args4j/spi/Messages.properties
new file mode 100755
index 0000000..c98fb98
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/Messages.properties
@@ -0,0 +1,5 @@
+ILLEGAL_OPERAND = \
+    "{1}" is not a valid value for "{0}"
+ILLEGAL_BOOLEAN = \
+	"{0}" is not a legal boolean value
+    
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/OneArgumentOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/OneArgumentOptionHandler.java
new file mode 100755
index 0000000..80ffb57
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/OneArgumentOptionHandler.java
@@ -0,0 +1,45 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * OptionHandler which handles an option with exactly one argument, like "-foo bar".
+ * @author Jan Materne
+ * @since 2.0.9
+ * @param <T> Type of the Setter-class
+ */
+public abstract class OneArgumentOptionHandler<T> extends OptionHandler<T> {
+
+	public OneArgumentOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super T> setter) {
+		super(parser, option, setter);
+	}
+	
+	@Override
+	public String getDefaultMetaVariable() {
+		return "N";
+	}
+
+	@Override
+	public int parseArguments(Parameters params) throws CmdLineException {
+        String token = params.getParameter(0);
+        try {
+            T value = parse(token);
+            setter.addValue(value);
+        }
+        catch (NumberFormatException ex) {
+            throw new CmdLineException(Messages.ILLEGAL_OPERAND.format(option.toString(),token));
+        }
+        return 1;
+	}	
+	
+	/**
+	 * Parses a string to a real value of Type <T>.
+	 * @param argument String value to parse
+	 * @return the parsed value
+	 * @throws NumberFormatException if parsing is not possible
+	 */
+	protected abstract T parse(String argument) throws NumberFormatException;
+
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/OptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/OptionHandler.java
new file mode 100755
index 0000000..3697c5c
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/OptionHandler.java
@@ -0,0 +1,94 @@
+package org.kohsuke.args4j.spi;
+
+import java.util.ResourceBundle;
+
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.NamedOptionDef;
+
+
+/**
+ * Code that parses operands of an option into Java.
+ *
+ * <p>
+ * This class can be extended by application to support additional Java datatypes in option operands.
+ *
+ * <p>
+ * Implementation of this class needs to be registered to args4j by using
+ * {@link CmdLineParser#registerHandler(Class,Class)} 
+ *
+ * @param <T>
+ *      The type of the field that this {@link OptionHandler} works with.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public abstract class OptionHandler<T> {
+    /**
+     * The annotation.
+     */
+    public final OptionDef option;
+    /**
+     * Object to be used for setting value.
+     */
+    public final Setter<? super T> setter;
+    /**
+     * The owner to which this handler belongs to.
+     */
+    public final CmdLineParser owner;
+
+    protected OptionHandler(CmdLineParser parser, OptionDef option, Setter<? super T> setter) {
+        this.owner = parser;
+        this.option = option;
+        this.setter = setter;
+    }
+
+    /**
+     * Called if the option that this owner recognizes is found.
+     *
+     * @param params
+     *      The rest of the arguments. This method can use this
+     *      object to access the arguments of the option if necessary.
+     *
+     *      The object is valid only during the method call.
+     *
+     * @return
+     *      The number of arguments consumed. For example, return 0
+     *      if this option doesn't take any parameter.
+     */
+    public abstract int parseArguments( Parameters params ) throws CmdLineException;
+
+    /**
+     * Gets the default meta variable name used to print the usage screen.
+     *
+     * @return null to hide a meta variable.
+     */
+    public abstract String getDefaultMetaVariable();
+
+    public final String getMetaVariable(ResourceBundle rb) {
+        String token = option.metaVar();
+        if(token.length()==0)
+            token = getDefaultMetaVariable();
+        if(token==null) return null;
+
+        if(rb!=null) {
+            String localized = rb.getString(token);
+            if(localized!=null)
+                token = localized;
+        }
+
+        return token;
+    }
+    
+    public final String getNameAndMeta(ResourceBundle rb) {
+    	String str = option.isArgument() ? "" : option.toString(); 
+    	String meta = getMetaVariable(rb);
+    	if (meta != null) {
+    		if (str.length() > 0) {
+    			str += " ";
+    		}
+    		str += meta;
+    	}
+    	return str;
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/Parameters.java b/alter-lib/src/org/kohsuke/args4j/spi/Parameters.java
new file mode 100755
index 0000000..419ac95
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/Parameters.java
@@ -0,0 +1,29 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineException;
+
+/**
+ * List of arguments.
+ *
+ * <p>
+ * Object of this interface is passed to
+ * {@link OptionHandler}s to make it easy/safe to parse
+ * additional parameters for options.
+ */
+public interface Parameters  {
+    /**
+     * Gets the additional parameter to this option.
+     *
+     * @param idx
+     *      specifying 0 will retrieve the token next to the option.
+     *      For example, if the command line looks like "-o abc -d x",
+     *      then <code>getParameter(0)</code> for "-o" returns "abc"
+     *      and <code>getParameter(1)</code> will return "-d".
+     *
+     * @return
+     *      Always return non-null valid String. If an attempt is
+     *      made to access a non-existent index, this method throws
+     *      appropriate {@link org.kohsuke.args4j.CmdLineException}.
+     */
+    public String getParameter(int idx) throws CmdLineException;
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/Setter.java b/alter-lib/src/org/kohsuke/args4j/spi/Setter.java
new file mode 100755
index 0000000..ac256d4
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/Setter.java
@@ -0,0 +1,29 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineException;
+
+/**
+ * Abstraction of the value setter.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public interface Setter<T> {
+    /**
+     * Adds/sets a value to the property of the option bean.
+     *
+     * <p>
+     * A {@link Setter} object has an implicit knowledge about the property it's setting,
+     * and the instance of the option bean.
+     */
+    void addValue(T value) throws CmdLineException;
+
+    /**
+     * Gets the type of the underlying method/field.
+     */
+    Class<T> getType();
+    
+    /**
+     * Whether this setter is instrinsically multi-valued.
+     */
+    boolean isMultiValued();
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/ShortOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/ShortOptionHandler.java
new file mode 100755
index 0000000..e459732
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/ShortOptionHandler.java
@@ -0,0 +1,24 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link Short}
+ * {@link OptionHandler}
+ * {@link OneArgumentOptionHandler}
+ * @author Jan Materne
+ * @since 2.0.9
+ */
+public class ShortOptionHandler extends OneArgumentOptionHandler<Short> {
+
+	public ShortOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super Short> setter) {
+		super(parser, option, setter);
+	}
+
+	@Override
+	protected Short parse(String argument) throws NumberFormatException {
+		return Short.parseShort(argument);
+	}
+
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/StopOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/StopOptionHandler.java
new file mode 100755
index 0000000..16be42f
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/StopOptionHandler.java
@@ -0,0 +1,49 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+import org.kohsuke.args4j.OptionDef;
+
+/**
+ * {@link OptionHandler} for the option terminator "--".
+ *
+ * <p>
+ * This {@link OptionHandler} can be used to implement the special token
+ * "--" that indicates that the rest of tokens are not options, but arguments.
+ *
+ * <p>
+ * For example, if you have the following class:
+ *
+ * <pre>
+ * class Foo {
+ *   @Argument
+ *   @Option(name="--",handler={@link StopOptionHandler}.class)
+ *   List<String> args;
+ *
+ *   @Option(name="-n")
+ *   int n;
+ * }
+ * </pre>
+ *
+ * <p>
+ * The command line {@code -n 5 abc def} would parse into n=5, args={"abc",def"},
+ * but {@code -- -n 5 abc def} would parse into n=0, args={"-n","5","abc","def"}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class StopOptionHandler extends OptionHandler<String> {
+    public StopOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super String> setter) {
+        super(parser, option, setter);
+    }
+
+    @Override
+    public int parseArguments(Parameters params) throws CmdLineException {
+    	owner.stopOptionParsing();
+    	return 0;
+    }
+
+    @Override
+    public String getDefaultMetaVariable() {
+        return "ARGUMENTS";
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/StringOptionHandler.java b/alter-lib/src/org/kohsuke/args4j/spi/StringOptionHandler.java
new file mode 100755
index 0000000..49490e3
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/StringOptionHandler.java
@@ -0,0 +1,27 @@
+package org.kohsuke.args4j.spi;
+
+import org.kohsuke.args4j.OptionDef;
+import org.kohsuke.args4j.CmdLineException;
+import org.kohsuke.args4j.CmdLineParser;
+
+/**
+ * String {@link OptionValueHandler}.
+ *
+ * @author Kohsuke Kawaguchi
+ */
+public class StringOptionHandler extends OptionHandler<String> {
+    public StringOptionHandler(CmdLineParser parser, OptionDef option, Setter<? super String> setter) {
+        super(parser, option, setter);
+    }
+
+    @Override
+    public int parseArguments(Parameters params) throws CmdLineException {
+        setter.addValue(params.getParameter(0));
+        return 1;
+    }
+
+    @Override
+    public String getDefaultMetaVariable() {
+        return "VAL";
+    }
+}
diff --git a/alter-lib/src/org/kohsuke/args4j/spi/package.html b/alter-lib/src/org/kohsuke/args4j/spi/package.html
new file mode 100755
index 0000000..5401537
--- /dev/null
+++ b/alter-lib/src/org/kohsuke/args4j/spi/package.html
@@ -0,0 +1,14 @@
+<!--
+To change this template, choose Tools | Templates
+and open the template in the editor.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    Clases que extienden el coportamiento de args4j.
+  </body>
+</html>
diff --git a/alter-lib/src/parser/AlnParser.jj b/alter-lib/src/parser/AlnParser.jj
new file mode 100755
index 0000000..2764c41
--- /dev/null
+++ b/alter-lib/src/parser/AlnParser.jj
@@ -0,0 +1,265 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+options
+{
+  STATIC = false;
+}
+
+PARSER_BEGIN(AlnParser)
+
+package parser;
+
+import types.Aln;
+import types.AlnSequence;
+import java.io.StringReader;
+import java.util.Vector;
+
+/**
+* ALN format parser.
+* @author Daniel Gomez Blanco
+* @version 1.2
+*/
+
+public class AlnParser
+{
+  /**
+  * Static method that parses an input string and returns a MSA in ALN format.
+  * @param in Input string.
+  * @return MSA in ALN format.
+  */
+  public static Aln parseMSA (String in) throws ParseException
+    {
+        //Parse string and return MSA
+        AlnParser parser = new AlnParser(new StringReader(in));
+        return parser.Aln();
+    }
+}
+
+PARSER_END(AlnParser)
+
+TOKEN :
+{
+    <EOL: "\n" | "\r" | "\r\n" > |
+    <BLANK: " " | "\t" > |
+    <UPPER_CASE: ["A"-"Z"] > |
+    <LOWER_CASE: ["a"-"z"] > |
+    <NUMBER: ["0"-"9"] > |
+    <ANY: ~["\r","\n"," ","\t","A"-"Z","a"-"z","0"-"9","*",":",".","-","?","\"","'","%"] >
+}
+
+//When a "%" is found in DEFAULT state ignore it and change state to IN_COMMENT
+MORE :
+{
+    "%": IN_COMMENT
+}
+
+//When any character is found within a comment, ignore it
+<IN_COMMENT> MORE :
+{
+    <  ~[] >
+}
+
+//When a EOL is found in IN_COMMENT state change to DEFAULT state
+<IN_COMMENT> SKIP :
+{
+    <"\n" | "\r" | "\r\n">: DEFAULT
+}
+
+/**
+* Grammar's root production. Structure:<br>
+*   1. Any combination of spaces, tabs and new lines
+* until the word "CLUSTAL", "MUSCLE" or "PROBCONS".<br>
+*   2. Any character after the word "CLUSTAL", "MUSCLE" or "PROBCONS"
+* until the end of that line.<br>
+*   3. Any combination of spaces, tabs and new lines
+* until first sequence identifier.<br>
+*   4. Sequence blocks with the following structure:<br>
+*     4a. Sequence line:<br>
+*       4a1. Identifier.<br>
+*       4a2. Data line.<br>
+*       4a3. Number of residues (optional).<br>
+*     4b. Consensus line made up of spaces, tabs, "*", ":" or ".".
+* @return MSA in ALN format.
+*/
+Aln Aln():
+{
+    Vector<AlnSequence> seqs = new Vector<AlnSequence>();
+    String id, data;
+    int cont = 0;
+}
+{
+    (<EOL> | <BLANK>)*
+    ("CLUSTAL" | "MUSCLE" | "PROBCONS")
+    (<BLANK> | <UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | "*" | ":" | "."
+        | "-" | "?" | "CLUSTAL" | "MUSCLE" | "PROBCONS" | "\"" | "'")* <EOL>
+    (<EOL> | <BLANK>)*
+    (
+        id = Id() <BLANK> data = DataLine() (<NUMBER> (<BLANK>)*)* <EOL>
+        {
+            seqs.add(new AlnSequence(id,data));
+        }
+    )+
+    ((<BLANK> | "*" | ":" | ".")* (<EOL>))+
+    (
+        (
+            IdSeq(seqs.elementAt(cont).getId()) <BLANK> data = DataLine() (<NUMBER> (<BLANK>)*)* (<EOL> | <EOF>)
+            {
+                seqs.elementAt(cont).concat(data);
+                cont++;
+            }
+        )+
+        (((<BLANK> | "*" | ":" | ".")* (<EOL>))+ | <EOF>)
+        {
+            cont = 0;
+        }
+    )*
+    <EOF>
+    {
+        return new Aln(seqs);
+    }
+}
+
+/**
+* Parses a sequence identifier. The identifier cannot contain spaces
+* and it cannot start with the characters "*",":","." to avoid
+* confusion with consensus lines.
+* @return String with the sequence identifier.
+*/
+String Id():
+{
+    StringBuffer s =  new StringBuffer();
+    Token t;
+}
+{
+    (
+        (
+        ("\"" | "'")
+
+        (
+            (t = <BLANK> | t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY>
+            | t = "*" | t = ":" | t= "." | t = "-" | t = "?"
+            | t = "CLUSTAL" | t = "MUSCLE" | t = "PROBCONS")
+            {
+                s.append(t.image);
+            }
+        )+
+
+        ("\"" | "'")
+        )
+    |
+        (
+        (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER>
+            | t = <ANY> | t = "-" | t="?"
+            | t = "CLUSTAL" | t = "MUSCLE" | t = "PROBCONS")
+        {
+            s.append(t.image);
+        }
+
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY>
+            | t = "*" | t = ":" | t= "." | t = "-" | t = "?" | t = "\"" | t = "'"
+            | t = "CLUSTAL" | t = "MUSCLE" | t = "PROBCONS")
+            {
+                s.append(t.image);
+            }
+        )*
+        )
+    )
+    {
+        return s.toString();
+    }
+}
+
+/**
+* Same behaviour as Id(), but in this case equality between the already read
+* identifier and the current one is checked.
+* @param id Identifier to parse.
+*/
+void IdSeq(String id):
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (
+        ("\"" | "'")
+        (
+            (t = <BLANK> | t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY>
+            | t = "*" | t = ":" | t= "." | t = "-" | t = "?"
+            | t = "CLUSTAL" | t = "MUSCLE" | t = "PROBCONS")
+            {
+                s.append(t.image);
+            }
+        )+
+        ("\"" | "'")
+        )
+
+    |
+
+        (
+        (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER>
+            | t = <ANY> | t = "-" | t="?"
+            | t = "CLUSTAL" | t = "MUSCLE" | t = "PROBCONS")
+        {
+            s.append(t.image);
+        }
+
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY>
+            | t = "*" | t = ":" | t= "." | t = "-" | t = "?" | t = "\"" | t = "'"
+            | t = "CLUSTAL" | t = "MUSCLE" | t = "PROBCONS")
+            {
+                s.append(t.image);
+            }
+        )*
+        )
+    )
+    {
+        if (!id.equals(s.toString()))
+        throw new ParseException("ID for sequence \"" + id
+                            + "\"does not match with ID in line " + t.beginLine);
+    }
+}
+
+/**
+* Parses a data line. A data line can be made up of characters from "A" to "Z"
+* (lowercase and uppercase), "-", "." or "?". Spaces and tabs are omitted.
+* @return String with the data line (always uppercase).
+*/
+String DataLine():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        t = <BLANK>
+        |
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = "-" | t = "." | t = "?"
+                | t = "CLUSTAL" | t = "MUSCLE" | t = "PROBCONS")
+            {
+                s.append(t.image);
+            }
+        )
+    )+
+    {
+        return s.toString().toUpperCase();
+    }
+}
\ No newline at end of file
diff --git a/alter-lib/src/parser/AutodetectionParser.jj b/alter-lib/src/parser/AutodetectionParser.jj
new file mode 100755
index 0000000..a2e922e
--- /dev/null
+++ b/alter-lib/src/parser/AutodetectionParser.jj
@@ -0,0 +1,184 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+options
+{
+  STATIC = false;
+}
+
+PARSER_BEGIN(AutodetectionParser)
+
+package parser;
+
+import java.io.StringReader;
+
+/**
+* Autodetection parser.
+* @author Daniel Gomez Blanco
+* @version 1.2
+*/
+public class AutodetectionParser
+{
+
+  /**
+  * Static method that parses an input string and returns the format of the input MSA.
+  * @param in Input string.
+  * @return String with the detected format.
+  */
+  public static String detectFormat (String in) throws ParseException
+    {
+        //Parse string and return MSA format
+        AutodetectionParser parser = new AutodetectionParser(new StringReader(in));
+        return parser.Autodetection();
+    }
+}
+
+PARSER_END(AutodetectionParser)
+
+TOKEN :
+{
+    <EOL: "\n" | "\r" | "\r\n" > |
+    <BLANK: " " | "\t" > |
+    <UPPER_CASE: ["A"-"Z"] > |
+    <NUMBER: ["0"-"9"] > |
+    <ANY: ~["\r","\n"," ","\t","A"-"Z","0"-"9",";",">","#","%"] >
+}
+
+/**
+* Grammar's root production. After omitting spaces, tabs and new lines,
+* format is detected using the first words:<br>
+*   - If it starts with "#" or "%" it's GDE.<br>
+*   - If it starts with "#NEXUS" it's NEXUS.<br>
+*   - If it starts with "CLUSTAL", "MUSCLE" or "PROBCONS" it's ALN.<br>
+*   - If it starts with "PileUp", "!!AA_MULTIPLE_ALIGNMENT" or
+* "!!NA_MULTIPLE_ALIGNMENT" it's MSF.<br>
+*   - If it starts with a number, followed by a sequence of spaces
+* or tabs, and then another number, it's PHYLIP.<br>
+*   - If it starts with ">" followed by two characters and ";" it's PIR.<br>
+*   - If it starts with ">" and it doesn't meet the latter point it's FASTA.
+*/
+String Autodetection():
+{
+    String toret;
+}
+{
+    (<BLANK> | <EOL>)*
+    (
+        ( "#" | "%" )
+        {
+            return "gde";
+        }
+    |
+        "#NEXUS"
+        {
+            return "nexus";
+        }
+    |
+        ("CLUSTAL" | "MUSCLE" | "PROBCONS")
+        {
+            return "aln";
+        }
+    |
+        (Number() (<BLANK>)+ Number())
+        {
+            return "phylip";
+        }
+    |
+        (">"
+        (LOOKAHEAD(Type() ";" )
+            (
+                Type() ";"
+                { return "pir"; }
+            )
+            |
+            (
+                Line()
+                { return "fasta"; }
+            )
+        )
+        )
+    |
+        (
+            "PileUp"
+        |
+            "!!AA_MULTIPLE_ALIGNMENT"
+        |
+            "!!NA_MULTIPLE_ALIGNMENT"
+        )
+        {
+        return "msf";
+        }
+    )
+}
+
+/**
+* Parses a number.
+* @return Parsed number.
+*/
+int Number():
+{
+    String s = "";
+    Token t;
+}
+{
+    (t = <NUMBER>
+        {
+            s = s.concat(t.image);
+        }
+    )+
+    {
+        return Integer.parseInt(s);
+    }
+}
+
+/**
+* Parses a PIR style type.
+* @return String with the type of MSA.
+*/
+String Type():
+{
+    Token t1, t2;
+}
+{
+    (t1 = <UPPER_CASE> (t2 = <UPPER_CASE> | t2 = <NUMBER>))
+    {
+        return t1.image + t2.image;
+    }
+}
+
+/**
+* Parses a line made up with any sequence of characters.
+* @return Parsed line.
+*/
+String Line():
+{
+    String s = "";
+    Token t;
+}
+{
+    (
+        (t = <BLANK> | t = <UPPER_CASE> | t = <NUMBER> | t = <ANY>
+        | t = ">" | t = ";" | t = "#" | t = "%" | t = "#NEXUS" | t = "CLUSTAL"
+        | t = "MUSCLE" | t = "PROBCONS"| t = "PileUp")
+        {
+            s = s.concat(t.image);
+        }
+    )+
+    {
+        return s.trim();
+    }
+}
\ No newline at end of file
diff --git a/alter-lib/src/parser/FastaParser.jj b/alter-lib/src/parser/FastaParser.jj
new file mode 100755
index 0000000..df0dbcd
--- /dev/null
+++ b/alter-lib/src/parser/FastaParser.jj
@@ -0,0 +1,186 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+options
+{
+  STATIC = false;
+}
+
+PARSER_BEGIN(FastaParser)
+
+package parser;
+
+import types.Fasta;
+import types.FastaSequence;
+import java.io.StringReader;
+import java.util.Vector;
+
+/**
+* FASTA format parser.
+* @author Daniel Gomez Blanco
+* @version 1.2
+*/
+public class FastaParser
+{
+  /**
+  * Static method that parses an input string and returns a MSA in FASTA format.
+  * @param in Input string.
+  * @return MSA in FASTA format.
+  */
+  public static Fasta parseMSA (String in) throws ParseException
+    {
+        //Parse string and return MSA
+        FastaParser parser = new FastaParser(new StringReader(in));
+        return parser.Fasta();
+    }
+}
+
+PARSER_END(FastaParser)
+
+TOKEN :
+{
+    <EOL: "\n" | "\r" | "\r\n" > |
+    <BLANK: " " | "\t" > |
+    <UPPER_CASE: ["A"-"Z"] > |
+    <LOWER_CASE: ["a"-"z"] > |
+    <NUMBER: ["0"-"9"] > |
+    <ANY: ~["\r","\n"," ","\t","A"-"Z","a"-"z","0"-"9",">","-",".","?","\"","'"] >
+
+}
+
+/**
+* Grammar's root production. Structure:<br>
+*   1. Any combination of spaces, tabs and new lines until ">".<br>
+*   2. Sequences with the following format:<br>
+*     2a. ">".<br>
+*     2b. Sequence identifier.<br>
+*     2c. New line.<br>
+*     2d. Sequence data.<br>
+* @return MSA in FASTA format.
+*/
+Fasta Fasta():
+{
+    Vector<FastaSequence> seqs = new Vector<FastaSequence>();
+    String id, data;
+    String desc = "";
+}
+{
+    (<EOL> | <BLANK>)*
+    (
+        ">" (<BLANK>)* id = Word() (( <BLANK> ((desc = Line() <EOL>) | <EOL>)) | <EOL>)
+        data = Data()
+        {
+            seqs.add(new FastaSequence(id, desc, data));
+        }
+    )+
+    <EOF>
+    {
+        return new Fasta(seqs);
+    }
+}
+
+/**
+* Parses a word made up of any character sequence.
+* @return Parsed word.
+*/
+String Word():
+{
+    String s = "";
+    Token t;
+}
+{
+    (
+        (
+            ("\"" | "'")
+            (
+                (t = <BLANK> | t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> |
+                t = <ANY> | t = ">" | t = "-" | t = "." | t = "?" )
+                {
+                    s = s.concat(t.image);
+                }
+            )+
+            ("\"" | "'")
+        )
+    |
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> |
+            t = <ANY> | t = ">" | t = "-" | t = "." | t = "?")
+            {
+                s = s.concat(t.image);
+            }
+        )
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> |
+            t = <ANY> | t = ">" | t = "-" | t = "." | t = "?" | t = "\"" | t = "'")
+            {
+                s = s.concat(t.image);
+            }
+        )*
+    )
+    {
+        return s.trim();
+    }
+}
+
+/**
+* Parses a line made up of any character sequence.
+* @return Parsed line.
+*/
+String Line():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (t = <BLANK> | t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> |
+        t = <ANY> | t = ">" | t = "-" | t = "." | t = "?" | t = "\"" | t = "'")
+        {
+            s.append(t.image);
+        }
+    )+
+    {
+        return s.toString().trim();
+    }
+}
+
+/**
+* Parses sequence data. These data can be made up of any characters
+* from "A" to "Z" (lowercase and uppercase), "-", "." or "?".
+* Spaces, tabs and new lines are omitted.
+* @return String with the sequence data (uppercase always).
+*/
+String Data():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (t = <BLANK> | t = <EOL>)
+        |
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = "-" | t = "." | t = "?" )
+            {
+                s.append(t.image);
+            }
+        )
+    )+
+    {
+        return s.toString().toUpperCase();
+    }
+}
\ No newline at end of file
diff --git a/alter-lib/src/parser/GdeParser.jj b/alter-lib/src/parser/GdeParser.jj
new file mode 100755
index 0000000..776fb1a
--- /dev/null
+++ b/alter-lib/src/parser/GdeParser.jj
@@ -0,0 +1,141 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+options
+{
+  STATIC = false;
+}
+
+PARSER_BEGIN(GdeParser)
+
+package parser;
+
+import types.Gde;
+import types.GdeSequence;
+import java.io.StringReader;
+import java.util.Vector;
+
+/**
+* GDE format parser.
+* @author Daniel Gomez Blanco
+* @version 1.2
+*/
+public class GdeParser
+{
+  /**
+  * Static method that parses an input string and returns a MSA in GDE format.
+  * @param in Input string.
+  * @return MSA in GDE format.
+  */
+  public static Gde parseMSA (String in) throws ParseException
+    {
+        //Parse string and return MSA
+        GdeParser parser = new GdeParser(new StringReader(in));
+        return parser.Gde();
+    }
+}
+
+PARSER_END(GdeParser)
+
+TOKEN :
+{
+    <EOL: "\n" | "\r" | "\r\n" > |
+    <BLANK: " " | "\t" > |
+    <UPPER_CASE: ["A"-"Z"] > |
+    <LOWER_CASE: ["a"-"z"] > |
+    <NUMBER: ["0"-"9"] > |
+    <ANY: ~["\r","\n"," ","\t","A"-"Z","a"-"z","0"-"9","#","%","-",".","?"] >
+
+}
+
+/**
+* Grammar's root production. Structure:<br>
+*   1. Any combinations of spaces, tabs and new lines until "#" or "%".<br>
+*   2. Sequences with the following format:<br>
+*     2a. "#" ó "%".<br>
+*     2b. Sequence identifier.<br>
+*     2c. New line.<br>
+*     2d. Sequence data.<br>
+* @return MSA in GDE format.
+*/
+Gde Gde():
+{
+    Vector<GdeSequence> seqs = new Vector<GdeSequence>();
+    String id, data;
+}
+{
+    (<EOL> | <BLANK>)*
+    (
+        ("#" | "%") id = Line() <EOL> data = Data()
+        {
+            seqs.add(new GdeSequence(id,data));
+        }
+    )+
+    <EOF>
+    {
+        return new Gde(seqs);
+    }
+}
+
+/**
+* Parses a line made up of any character sequence.
+* @return Parsed line.
+*/
+String Line():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (t = <BLANK> | t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> |
+        t = <ANY> | t = "-" | t = "#" | t = "%" | t = "." | t = "?" )
+        {
+            s.append(t.image);
+        }
+    )+
+    {
+        return s.toString().trim();
+    }
+}
+
+/**
+* Parses sequence data. These data can be made up of any characters
+* from "A" to "Z" (lowercase and uppercase), "-", "." or "?".
+* Spaces, tabs and new lines are omitted.
+* @return String with the sequence data (uppercase always).
+*/
+String Data():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (t = <BLANK> | t = <EOL>)
+        |
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = "-" | t = "." | t = "?" )
+            {
+                s.append(t.image);
+            }
+        )
+    )+
+    {
+        return s.toString().toUpperCase();
+    }
+}
\ No newline at end of file
diff --git a/alter-lib/src/parser/MsfParser.jj b/alter-lib/src/parser/MsfParser.jj
new file mode 100755
index 0000000..63a0a07
--- /dev/null
+++ b/alter-lib/src/parser/MsfParser.jj
@@ -0,0 +1,284 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+options
+{
+  STATIC = false;
+}
+
+PARSER_BEGIN(MsfParser)
+
+package parser;
+
+import types.Msf;
+import types.MsfSequence;
+import java.io.StringReader;
+import java.util.Vector;
+
+/**
+* MSF format parser.
+* @author Daniel Gomez Blanco
+* @version 1.2
+*/
+public class MsfParser
+{
+  /**
+  * Static method that parses an input string and returns a MSA in MSF format.
+  * @param in Input string.
+  * @return MSA in MSF format.
+  */
+  public static Msf parseMSA (String in) throws ParseException
+    {
+        //Parse string and return MSA
+        MsfParser parser = new MsfParser(new StringReader(in));
+        return parser.Msf();
+    }
+}
+
+PARSER_END(MsfParser)
+
+TOKEN :
+{
+    <EOL: "\n" | "\r" | "\r\n" > |
+    <BLANK: " " | "\t" > |
+    <UPPER_CASE: ["B"-"M"] | "O" | ["Q"-"Z"] > |
+    <LOWER_CASE: ["a"-"z"] > |
+    <NUMBER: ["0"-"9"] > |
+    <ANY: ~["\r","\n"," ","\t","A"-"Z","a"-"z","0"-"9",".","N","P","A","?","-"] >
+
+}
+
+/**
+* Grammar's root production. Structure:<br>
+*   1. Any combination of spaces, tabs and new lines until
+* "PileUp", "!!AA_MULTIPLE_ALIGNMENT" or "!!NA_MULTIPLE_ALIGNMENT".<br>
+*   2. "PileUp", "!!AA_MULTIPLE_ALIGNMENT" or
+* "!!NA_MULTIPLE_ALIGNMENT".<br>
+*   3. Any combination of characters until "MSF:".<br>
+*   4. "MSF:" followed by the MSA's length, "Type:"
+* followed by the MSA's type and "Check:" followed by the MSA's total checksum.
+* This lines ends with ".."<br>
+*   5. Sequence information block made up by lines starting with
+* "Name:" followed by the sequence identifier and " oo"
+* as a sequence identifier end delimiter, "Len:" followed by the sequence length
+* (all must be equal), "Check:" followed by the sequence checksum and
+* "Weight" followed by the sequence weight.<br>
+*   6. "//" as an information block delimiter.<br>
+*   7. Aligned sequences.
+* @return MSA in MSF format.
+*/
+Msf Msf():
+{
+    Vector<MsfSequence> seqs = new Vector<MsfSequence>();
+    String id,data;
+    Token type;
+    int total_length, length, total_check, check;
+    float weight;
+    int cont = 0;
+}
+{
+    (<BLANK> | <EOL>)*
+    (
+        "PileUp"
+    |
+        "!!AA_MULTIPLE_ALIGNMENT"
+    |
+        "!!NA_MULTIPLE_ALIGNMENT"
+    )
+    (<EOL> | <BLANK> | <UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | "-"
+        | "//" | "." | ".." | " oo" | "A" | "N" | "P" | "?" | "PileUp" | "!!AA_MULTIPLE_ALIGNMENT"
+        | "!!NA_MULTIPLE_ALIGNMENT")*
+
+    "MSF:" (<BLANK>)* total_length = Number() (<BLANK>)*
+    "Type:" (<BLANK>)* (type = "N" | type = "P" | type = "A" )
+    (<EOL> | <BLANK> | <UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | "-"
+        | "//" | "." | ".." | " oo" | "A" | "N" | "P" | "?" | "PileUp" | "!!AA_MULTIPLE_ALIGNMENT"
+        | "!!NA_MULTIPLE_ALIGNMENT")*
+    "Check:" (<BLANK>)* total_check = Number() (<BLANK>)* ".." (<BLANK>)* (<EOL>)+
+
+    ( 
+        (<BLANK>)* "Name:" (<BLANK>)* id = Id() (" oo" (<BLANK>)+)*
+        "Len:" (<BLANK>)* length = Number()
+        (<BLANK>)* "Check:" (<BLANK>)* check = Number()
+        (<BLANK>)* "Weight:" (<BLANK>)* weight = Float() (<BLANK>)* (<EOL>)+
+        {
+            seqs.add(new MsfSequence(id,length,check,weight,""));
+        }
+    )+
+    "//" (<BLANK>)*
+    (<EOL> (<BLANK>)*)+
+
+    (
+        IdSeq(seqs.elementAt(cont).getId()) <BLANK> data = DataLine() ((<EOL> (<BLANK>)*)+ | <EOF>)
+        {
+            seqs.elementAt(cont).concat(data);
+            cont++;
+            if (cont == seqs.size())
+                cont = 0;
+        }
+    )+
+
+    <EOF>
+
+    {
+        return new Msf(seqs, total_length, type.image, total_check);
+    }
+
+}
+
+
+/**
+* Parses a number.
+* @return Parsed number.
+*/
+int Number():
+{
+    String s = "";
+    Token t;
+}
+{
+    (t = <NUMBER>
+        {
+            s = s.concat(t.image);
+        }
+    )+
+    {
+        return Integer.parseInt(s);
+    }
+}
+
+/**
+* Parses a floating point number.
+* @return Parsed float.
+*/
+Float Float():
+{
+    int n1, n2;
+}
+{
+    n1 = Number()
+    "."
+    n2 = Number()
+    {
+        return Float.parseFloat(String.valueOf(n1) + "." + String.valueOf(n2));
+    }
+}
+
+/**
+* Parses a sequence identifier. An identifier can be made up of any sequence
+* of characters, including spaces and tabs, but it must not start with any of those.
+* The string " oo" indicates the end of the identifier.
+* @return Sequence identifier.
+*/
+String Id():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY> | t = "-"
+        | t = "." | t = "//" | t= ".." | t = "N" | t = "P" | t = "A" | t = "?"
+        | t = "PileUp" | t = "!!AA_MULTIPLE_ALIGNMENT" | t = "!!NA_MULTIPLE_ALIGNMENT")
+        {
+            s.append(t.image);
+        }
+    )
+    (
+        (t = <BLANK> | t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY> | t = "-"
+        | t = "." | t = "//" | t= ".." | t = "N" | t = "P" | t= "A" | t = "?"
+        | t = "PileUp" | t = "!!AA_MULTIPLE_ALIGNMENT" | t = "!!NA_MULTIPLE_ALIGNMENT")
+        {
+            s.append(t.image);
+        }
+    )*
+    {
+        return s.toString().trim();
+    }
+}
+
+/**
+* Same behaviour as Id(), but in this case equality between the already read
+* identifier and the current one is checked.
+* @param id Identifier to parse.
+*/
+void IdSeq(String id):
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY> | t = "-"
+        | t = "." | t = "//" | t= ".." | t = "N" | t = "P" | t = "A" | t = "?"
+        | t = "PileUp" | t = "!!AA_MULTIPLE_ALIGNMENT" | t = "!!NA_MULTIPLE_ALIGNMENT")
+        {
+            s.append(t.image);
+            if (id.length() == s.length())
+                if (id.equals(s.toString()))
+                    return;
+                else
+                    throw new ParseException("ID for sequence \"" + id 
+                            + "\"does not match with ID in line " + t.beginLine);
+
+        }
+    )
+    (
+        (t = <BLANK> | t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY> | t = "-"
+        | t = "." | t = "//" | t= ".." | t = "N" | t = "P" | t = "A" | t = "?"
+        | t = "PileUp" | t = "!!AA_MULTIPLE_ALIGNMENT" | t = "!!NA_MULTIPLE_ALIGNMENT")
+        {
+            s.append(t.image);
+            if (id.length() == s.length())
+                if (id.equals(s.toString()))
+                    return;
+                else
+                    throw new ParseException("ID for sequence \"" + id 
+                            + "\"does not match with ID in line " + t.beginLine);
+        }
+    )*
+    {
+        throw new ParseException("ID for sequence \"" + id
+                            + "\"does not match with ID in line " + t.beginLine);
+    }
+}
+
+/**
+* Parses a data line. A data line can be made up of characters from "A" to "Z"
+* (lowercase and uppercase), "." or "?". Spaces and tabs are omitted.
+* @return String with the data line (always uppercase).
+*/
+String DataLine():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        t = <BLANK>
+        |
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = "." | t = ".." | t = "N" | t = "P" | t = "A" | t = "?" | t = "-" )
+            {
+                s.append(t.image);
+            }
+        )
+    )+
+    {
+        return (s.toString().toUpperCase()).replace('.','-');
+    }
+}
\ No newline at end of file
diff --git a/alter-lib/src/parser/NexusParser.jj b/alter-lib/src/parser/NexusParser.jj
new file mode 100755
index 0000000..7a186bd
--- /dev/null
+++ b/alter-lib/src/parser/NexusParser.jj
@@ -0,0 +1,382 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+options
+{
+  STATIC = false;
+  IGNORE_CASE = true;
+}
+
+PARSER_BEGIN(NexusParser)
+
+package parser;
+
+import types.Nexus;
+import types.NexusSequence;
+import java.io.StringReader;
+import java.util.Vector;
+
+/**
+* NEXUS format parser.
+* @author Daniel Gomez Blanco
+* @version 1.3
+*/
+public class NexusParser
+{
+  /**
+  * Static method that parses an input string and returns a MSA in NEXUS format.
+  * @param in Input string.
+  * @return MSA in NEXUS format.
+  */
+  public static Nexus parseMSA (String in) throws ParseException
+    {
+        //Parse string and return MSA
+        NexusParser parser = new NexusParser(new StringReader(in));
+        return parser.Nexus();
+    }
+}
+
+PARSER_END(NexusParser)
+
+TOKEN :
+{
+    <EOL: "\n" | "\r" | "\r\n" > |
+    <BLANK: " " | "\t" > |
+    <UPPER_CASE: ["A"-"Z"] > |
+    <LOWER_CASE: ["a"-"z"] > |
+    <NUMBER: ["0"-"9"] > |
+    <ANY: ~["\r","\n"," ","\t","A"-"Z","a"-"z","0"-"9",";","-",".","?","=","[","\"","'"] >
+
+}
+
+//When a "[" is found in DEFAULT state ignore it and change state to IN_COMMENT
+MORE :
+{
+    "[": IN_COMMENT
+}
+
+//When any character is found within a comment, ignore it
+<IN_COMMENT> MORE :
+{
+    <  ~["]"] >
+}
+
+//When a "]" is found in IN_COMMENT state change to DEFAULT state
+<IN_COMMENT> SKIP :
+{
+    "]": DEFAULT
+}
+
+/**
+* Grammar's root production. Structure:<br>
+*   1. Any combination of spaces, tabs and new lines until "#NEXUS".<br>
+*   2. "#NEXUS".<br>
+*   3. Any combination of characters until "BEGIN DATA;".<br>
+*   4. "BEGIN DATA;"<br>
+*   5. Any combination of characters until "ntax=".<br>
+*   6. "ntax=" followed by the taxa number (number of sequences in the MSA),
+* "nchar=" followed by the sequences length and ";".<br>
+*   7. Any character until "datatype=".<br>
+*   8. "datatype=" followed by the MSA type.<br>
+*   9. Any character until "matrix".<br>
+*   10. Sequences in NEXUS format:<br>
+*     10a. Sequence identifier.<br>
+*     10a. Data line.<br>
+*   11. ";".<br>
+*   12. "end;".<br>
+*   13. Any combination of characters until the end of file.<br>
+* @return MSA in NEXUS format.
+*/
+Nexus Nexus():
+{
+    Vector<NexusSequence> seqs = new Vector<NexusSequence>();
+    int taxa = 0,length = 0;
+    String id, data;
+    String type = "";
+    int cont = 0;
+}
+{
+    (<EOL> | <BLANK>)*
+
+    "#NEXUS"
+    (<UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | ";" | "-" | "." | "?" | <BLANK> | <EOL>
+        | "#NEXUS" | "ntax" | "nchar" | "datatype" | "matrix" | "end;" | "="  | "\"" | "'")*
+
+    (
+        (
+            "BEGIN DATA" ";"
+
+            (<UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | ";" | "-" | "." | "?" | <BLANK> | <EOL> | "="  | "\"" | "'")*
+
+            (
+                (
+                      ("ntax" (<BLANK>)* "=" (<BLANK>)* taxa = Number() (<EOL> | <BLANK> | ";"))
+                    | ("nchar" (<BLANK>)* "=" (<BLANK>)* length = Number() (<EOL> | <BLANK> | ";"))
+                    | ("datatype" (<BLANK>)* "=" (<BLANK>)* type = Type() (<EOL> | <BLANK> | ";"))
+                )
+                (<UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | ";" | "-" | "." | "?" | <BLANK> | <EOL> | "="  | "\"" | "'")*
+            )+
+
+            {
+                if (taxa == 0)
+                    throw new ParseException("Number of sequences (ntax) missing in NEXUS header.");
+                if (length == 0)
+                    throw new ParseException("Sequences length (nchar) missing in NEXUS header.");
+                if (type.isEmpty())
+                    throw new ParseException("MSA type (datatype) missing in NEXUS header.");
+            }
+        )
+    |
+        (
+            "BEGIN TAXA" ";"
+
+            (<UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | ";" | "-" | "." | "?" | <BLANK> | <EOL> | "="  | "\"" | "'")*
+
+            "ntax" (<BLANK>)* "=" (<BLANK>)* taxa = Number() (<EOL> | <BLANK> | ";")
+
+            (<UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | ";" | "-" | "." | "?" | <BLANK> | <EOL> | "="  | "\"" | "'")*
+
+            "end;"
+
+            {
+                if (taxa == 0)
+                    throw new ParseException("Number of sequences (ntax) missing in NEXUS header.");
+            }
+
+            (<UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | ";" | "-" | "." | "?" | <BLANK> | <EOL> | "="  | "\"" | "'")*
+
+            "BEGIN CHARACTERS" ";"
+
+            (<UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | ";" | "-" | "." | "?" | <BLANK> | <EOL> | "="  | "\"" | "'")*
+
+            (
+                (
+                    ("nchar" (<BLANK>)* "=" (<BLANK>)* length = Number() (<EOL> | <BLANK> | ";"))
+                    | ("datatype" (<BLANK>)* "=" (<BLANK>)* type = Type() (<EOL> | <BLANK> | ";"))
+                )
+                (<UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | ";" | "-" | "." | "?" | <BLANK> | <EOL> | "="  | "\"" | "'")*
+            )+
+
+            {
+                if (length == 0)
+                    throw new ParseException("Sequences length (nchar) missing in NEXUS header.");
+                if (type.isEmpty())
+                    throw new ParseException("MSA type (datatype) missing in NEXUS header.");
+            }
+        )
+    )
+
+    "matrix" (<BLANK>)* (<EOL> (<BLANK>)*)+
+
+    (
+        id = Id() <BLANK> data = DataLine() (";"(<BLANK>)*)? (<EOL> (<BLANK>)*)+ (";"(<BLANK>)* (<EOL> (<BLANK>)*)+)?
+        {
+            seqs.add(new NexusSequence(id, data));
+            cont++;
+            if (cont == taxa)
+            {
+                cont = 0;
+                break;
+            }
+        }
+    )+
+    (
+        IdSeq(seqs.elementAt(cont).getId()) <BLANK> data = DataLine() (";"(<BLANK>)*)? (<EOL> (<BLANK>)*)+ (";"(<BLANK>)* (<EOL> (<BLANK>)*)+)?
+        {
+            seqs.elementAt(cont).concat(data);
+            cont++;
+            if (cont == seqs.size())
+                cont = 0;
+        }
+    )*
+
+    "end;"
+    (<UPPER_CASE> | <LOWER_CASE> | <NUMBER> | <ANY> | ";" | "-" | "." | "?" | <BLANK> | <EOL>
+        | "#NEXUS" | "ntax" | "nchar" | "datatype" | "matrix" | "end;" | "BEGIN DATA" | "BEGIN TAXA" | "BEGIN CHARACTERS" | "=" | "\"" | "'")*
+    <EOF>
+
+    {
+        return new Nexus(taxa, length, type, seqs);
+    }
+}
+
+
+/**
+* Parses a number.
+* @return Parsed number.
+*/
+int Number():
+{
+    String s = "";
+    Token t;
+}
+{
+    (t = <NUMBER>
+        {
+            s = s.concat(t.image);
+        }
+    )+
+    {
+        return Integer.parseInt(s);
+    }
+}
+
+/**
+* Parses a NEXUS style type.
+* @return String with the type.
+*/
+String Type():
+{
+    String s = "";
+    Token t;
+}
+{
+    (
+        (t = <UPPER_CASE> | t = <LOWER_CASE>)
+        {
+            s = s.concat(t.image);
+        }
+    )+
+    {
+        return s.toUpperCase();
+    }
+}
+
+/**
+* Parses a sequence identifier. An identifier cannot contain spaces or start with ";".
+* @return Sequence identifier.
+*/
+String Id():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (
+            ("\"" | "'")
+            (
+                (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY>
+                | t = "-" | t = "." | t = "?" | t= "matrix" | t = "nchar" | t = "ntax"
+                | t = "datatype" | t = "#NEXUS" | t = "BEGIN DATA" | t = "end;" | t = "=")
+                {
+                    s.append(t.image);
+                }
+            )+
+            ("\"" | "'")
+        )
+    |
+        (
+            (
+                (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY>
+                | t = "-" | t = "." | t = "?" | t= "matrix" | t = "nchar" | t = "ntax"
+                | t = "datatype" | t = "#NEXUS" | t = "BEGIN DATA" | t = "=")
+                {
+                    s.append(t.image);
+                }
+            )
+            (
+                (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY>
+                | t = ";" | t = "-" | t = "." | t = "?" | t= "matrix" | t = "nchar" | t = "ntax"
+                | t = "datatype" | t = "#NEXUS" | t = "BEGIN DATA" | t = "end;" | t = "=" | t = "\"" | t = "'")
+                {
+                    s.append(t.image);
+                }
+            )*
+        )
+    )
+    {
+        return s.toString();
+    }
+}
+
+/**
+* Same behaviour as Id(), but in this case equality between the already read
+* identifier and the current one is checked.
+* @param id Identifier to parse.
+*/
+void IdSeq(String id):
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (
+            ("\"" | "'")
+            (
+                (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY>
+                | t = "-" | t = "." | t = "?" | t= "matrix" | t = "nchar" | t = "ntax"
+                | t = "datatype" | t = "#NEXUS" | t = "BEGIN DATA" | t = "end;" | t = "=")
+                {
+                    s.append(t.image);
+                }
+            )+
+            ("\"" | "'")
+        )
+    |
+        (
+            (
+                (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY>
+                | t = "-" | t = "." | t = "?" | t= "matrix" | t = "nchar" | t = "ntax"
+                | t = "datatype" | t = "#NEXUS" | t = "BEGIN DATA" | t = "=")
+                {
+                    s.append(t.image);
+                }
+            )
+            (
+                (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> | t = <ANY>
+                | t = ";" | t = "-" | t = "." | t = "?" | t= "matrix" | t = "nchar" | t = "ntax"
+                | t = "datatype" | t = "#NEXUS" | t = "BEGIN DATA" | t = "end;" | t = "=" | t = "\"" | t = "'")
+                {
+                    s.append(t.image);
+                }
+            )*
+        )
+    )
+    {
+        if (!id.equals(s.toString()))
+            throw new ParseException("ID for sequence \"" + id
+                            + "\"does not match with ID in line " + t.beginLine);
+    }
+}
+
+/**
+* Parses a data line. A data line can be made up of characters from "A" to "Z"
+* (lowercase and uppercase), "-", "." or "?". Spaces and tabs are omitted.
+* @return String with the data line (always uppercase).
+*/
+String DataLine():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        t = <BLANK>
+        |
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = "-" | t = "." | t = "?")
+            {
+                s.append(t.image);
+            }
+        )
+    )+
+    {
+        return s.toString().toUpperCase();
+    }
+}
\ No newline at end of file
diff --git a/alter-lib/src/parser/PhylipParser.jj b/alter-lib/src/parser/PhylipParser.jj
new file mode 100755
index 0000000..074b766
--- /dev/null
+++ b/alter-lib/src/parser/PhylipParser.jj
@@ -0,0 +1,348 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+options
+{
+  STATIC = false;
+}
+
+PARSER_BEGIN(PhylipParser)
+
+package parser;
+
+import types.Phylip;
+import types.PhylipSequence;
+import java.io.StringReader;
+import java.util.Vector;
+import java.util.StringTokenizer;
+
+/**
+* PHYLIP format parser.
+* @author Daniel Gomez Blanco
+* @version 1.2
+*/
+public class PhylipParser
+{
+    /**
+    * Static method that parses an input string and returns a MSA in PHYLIP format.
+    * @param in Input string.
+    * @return MSA in PHYLIP format.
+    */
+    public static Phylip parseMSA (String in) throws ParseException
+    {
+        //Parse string and return MSA
+        PhylipParser parser = new PhylipParser(new StringReader(in));
+        return parser.Phylip();
+    }
+}
+
+PARSER_END(PhylipParser)
+
+TOKEN :
+{
+    <EOL: "\n" | "\r" | "\r\n" > |
+    <BLANK: " " | "\t" > |
+    <UPPER_CASE: ["A"-"Z"] > |
+    <LOWER_CASE: ["a"-"z"] > |
+    <NUMBER: ["0"-"9"] > |
+    <ANY: ~["\r","\n"," ","\t","A"-"Z","a"-"z","0"-"9","-",".","?","\"","'"] >
+
+}
+
+/**
+* Grammar's root production. Structure:<br>
+*   1. Any combination of spaces, tabs and new lines
+* until a number is found.<br>
+*   2. Taxa number (number of sequences) followed by one or more
+* spaces or tabs and the sequences length. Any character can follow until
+* the end of the line, these characters will be omitted.<br>
+*   3. Any combination of spaces, tabs and new lines
+* until the first sequence identifier.<br>
+*   4. If the MSA is in sequential format sequences with the following structure follow:<br>
+*     4a. Sequence identifier.<br>
+*     4b. Sequence data.<br>
+*   5. If the MSA is in interleaved format lines with the following structure follow:<br>
+*     5a. Sequence identifier.<br>
+*     5b. Sequence data line.<br>
+* @return MSA in PHYLIP format.
+*/
+Phylip Phylip():
+{
+    Vector<PhylipSequence> seqs = new Vector<PhylipSequence>();
+    int taxa, length;
+    String id1, id2, data1, data2;
+}
+{
+    (<EOL> | <BLANK>)*
+    taxa = Number() (<BLANK>)+ length = Number() (<EOL> | ((<BLANK>)+ ((Line() <EOL>) | <EOL>)))
+    (<EOL> | <BLANK>)*
+
+    id1 = Id() (<EOL> | ((<BLANK>)+ (<EOL>)?)) data1 = DataLine() <EOL> (<EOL> | <BLANK>)*
+    id2 = Id() (<EOL> | ((<BLANK>)+ (<EOL>)?)) data2 = DataLine() <EOL> (<EOL> | <BLANK>)*
+    {
+        if(data1.length() > data2.length())
+        {
+            StringBuffer data = new StringBuffer();
+            data.append(data1);
+            data.append(id2);
+            data.append(data2);
+            seqs.add(new PhylipSequence(id1, data.toString()));
+
+            int read = seqs.firstElement().getData().length();
+
+            seqs.firstElement().concat(Data(length - read));
+            //It's sequential
+            PhylipSeq(length, seqs);
+        }
+        else
+        {
+            seqs.add(new PhylipSequence(id1,data1));
+            seqs.add(new PhylipSequence(id2,data2));
+            //It's interleaved
+            PhylipIntIds(taxa - 2, seqs);
+            PhylipIntSeqs(taxa, seqs);
+        }
+    }
+    <EOF>
+    {
+        return new Phylip(taxa, length, seqs);
+    }
+}
+
+/**
+* Parses the first sequences of an interleaved PHYLIP, adding a new sequence
+* to the vector for every parsed line.
+* @param taxa Number of sequences to be parsed.
+* @param seqs Sequences vector.
+*/
+void PhylipIntIds(int taxa, Vector<PhylipSequence> seqs):
+{
+    if (taxa == 0)
+        return;
+    int cont = 0;
+    String id, data;
+}
+{
+    (
+        id = Id() (<EOL> | ((<BLANK>)+ (<EOL>)?)) data = DataLine() (<EOF> | (<EOL> (<EOL> | <BLANK>)*))
+        {
+            seqs.add(new PhylipSequence(id, data));
+            cont++;
+            if (cont == taxa)
+                return;
+        }
+    )+
+}
+
+/**
+* Parses de rest of the sequences of an interleaved PHYLIP, concating them to the
+* already read ones.
+* @param taxa Number of sequences to be parsed.
+* @param seqs Sequences vector.
+*/
+void PhylipIntSeqs(int taxa, Vector<PhylipSequence> seqs):
+{
+    int cont = 0;
+    String data;
+}
+{
+    (
+        data = DataLine() (<EOF> | (<EOL> (<EOL> | <BLANK>)*))
+        {
+            seqs.elementAt(cont).concat(data);
+            cont++;
+            if (cont == taxa)
+                cont = 0;
+        }
+    )*
+}
+
+/**
+* Parses the sequences of a sequential PHYLIP, adding a new sequence to the sequences vector
+* for every parsed line.
+* @param length Length of the sequences to be parsed.
+* @seqs Sequences vector.
+*/
+void PhylipSeq(int length, Vector<PhylipSequence> seqs):
+{
+    String id, data;
+}
+{
+    (<BLANK> | <EOL>)*
+    (
+        id = Id() (<BLANK>|<EOL>) data = Data(length) (<BLANK> | <EOL>)*
+        {
+            seqs.add(new PhylipSequence(id,data));
+        }
+    )*
+}
+
+/**
+* Parses a number.
+* @return Parsed number.
+*/
+int Number():
+{
+    String s = "";
+    Token t;
+}
+{
+    (t = <NUMBER>
+        {
+            s = s.concat(t.image);
+        }
+    )+
+    {
+        return Integer.parseInt(s);
+    }
+}
+
+/**
+* Parses a sequence identifier.
+* @return Sequence identifier.
+*/
+String Id():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (
+            ("\"" | "'")
+            (
+                (t = <BLANK> | t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER>
+                    |t = <ANY> | t = "-" | t = "." | t = "?" )
+                {
+                    s.append(t.image);
+                }
+            )+
+            ("\"" | "'")
+        )
+    |
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER>
+                    |t = <ANY> | t = "-" | t = "." | t = "?" )
+            {
+                s.append(t.image);
+            }
+            (
+                (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER>
+                    |t = <ANY> | t = "-" | t = "." | t = "?" | t = "\"" | t ="'")
+                {
+                    s.append(t.image);
+                }
+            )*
+        )
+    )
+    {
+        return s.toString().trim();
+    }
+
+}
+
+/**
+* Parses a line made up of any character sequence.
+* @return Parsed line.
+*/
+String Line():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER>
+        | t = <ANY> | t = "-" | t = "." | t = "?"  | t = "\"" | t = "'")
+    {
+        s.append(t.image);
+    }
+    (
+        (t = <BLANK> | t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER>
+            | t = <ANY> | t = "-" | t = "." | t = "?"  | t = "\"" | t = "'")
+        {
+            s.append(t.image);
+        }
+    )*
+    {
+        return s.toString().trim();
+    }
+}
+
+/**
+* Parses a data line. A data line can be made up of characters from "A" to "Z"
+* (lowercase and uppercase), "-", "." or "?". Spaces and tabs are omitted.
+* @return String with the data line (always uppercase).
+*/
+String DataLine():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (t = <UPPER_CASE> | t = <LOWER_CASE> | t = "-" | t = "." | t = "?")
+        {
+            s.append(t.image);
+        }
+    )
+    (
+        t = <BLANK>
+        |
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = "-" | t = "." | t = "?")
+            {
+                s.append(t.image);
+            }
+        )
+    )*
+    {
+        return s.toString().toUpperCase();
+    }
+}
+
+/**
+* Parses the data of a sequence with the given length. These data can be made up
+* of any characters from "A" to "Z" (lowercase and uppercase), "-", "." or "?".
+* Spaces, tabs and new lines are omitted.
+* @param length Length of the sequence to be parsed.
+* @return String with the sequence data (uppercase always).
+*/
+String Data(int length):
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+    int chars = 0;
+    if (length==0) return ""; //lipido's patch needed for sequential Phylip with 2 lines per sequence
+}
+{
+    (
+        (t = <BLANK> | t = <EOL>)
+        |
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = "-" | t = "." | t = "?" )
+            {
+                s.append(t.image);
+                chars++;
+                if(chars == length)
+                    return s.toString().toUpperCase();
+            }
+        )
+    )+
+    {
+        return s.toString().toUpperCase();
+    }
+}
diff --git a/alter-lib/src/parser/PirParser.jj b/alter-lib/src/parser/PirParser.jj
new file mode 100755
index 0000000..f2642ce
--- /dev/null
+++ b/alter-lib/src/parser/PirParser.jj
@@ -0,0 +1,163 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+options
+{
+  STATIC = false;
+}
+
+PARSER_BEGIN(PirParser)
+
+package parser;
+
+import types.Pir;
+import types.PirSequence;
+import java.io.StringReader;
+import java.util.Vector;
+
+/**
+* PIR format parser.
+* @author Daniel Gomez Blanco
+* @version 1.2
+*/
+public class PirParser
+{
+    /**
+    * Static method that parses an input string and returns a MSA in PIR format.
+    * @param in Input string.
+    * @return MSA in PIR format.
+    */
+    public static Pir parseMSA (String in) throws ParseException
+    {
+        //Parse string and return MSA
+        PirParser parser = new PirParser(new StringReader(in));
+        return parser.Pir();
+    }
+}
+
+PARSER_END(PirParser)
+
+TOKEN :
+{
+    <EOL: "\n" | "\r" | "\r\n" > |
+    <BLANK: " " | "\t" > |
+    <UPPER_CASE: ["A"-"Z"] > |
+    <LOWER_CASE: ["a"-"z"] > |
+    <NUMBER: ["0"-"9"] > |
+    <ANY: ~["\r","\n"," ","\t","A"-"Z","a"-"z","0"-"9",";",">","*","-",".","?"] >
+
+}
+
+/**
+* Grammar's root production. Structure:<br>
+*   1. Any combination of spaces, tabs and new lines until ">".<br>
+*   2. Sequences with the following format:<br>
+*     2a. ">".<br>
+*     2b. Sequence type.<br>
+*     2c. ";".<br>
+*     2d. Sequence identifier.<br>
+*     2e. New line.<br>
+*     2f. Description.<br>
+*     2g. New line.<br>
+*     2h. Sequence data.<br>
+* @return MSA in PIR format.
+*/
+Pir Pir():
+{
+    Vector<PirSequence> seqs =  new Vector<PirSequence>();
+    String type, id, desc, data;
+    desc = "";
+}
+{
+    (<EOL> | <BLANK>)*
+    (
+        ">" (<BLANK>)* type = Type() (<BLANK>)* ";" id = Line() <EOL>
+        (desc = Line() <EOL> | <EOL>)
+        data = Data() "*" (<EOL> | <BLANK>)*
+        {
+            seqs.add(new PirSequence(id,type,desc,data));
+        }
+    )+
+    <EOF>
+    {
+        return new Pir(seqs);
+    }
+}
+
+/**
+* Parses a PIR style type.
+* @return Type.
+*/
+String Type():
+{
+    Token t1, t2;
+}
+{
+    t1 = <UPPER_CASE> (t2 = <UPPER_CASE> | t2 = <NUMBER>)
+    {
+        return t1.image + t2.image;
+    }
+}
+
+/**
+* Parses a line made up of any character sequence.
+* @return Parsed line.
+*/
+String Line():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (t = <BLANK> | t = <UPPER_CASE> | t = <LOWER_CASE> | t = <NUMBER> |
+        t = <ANY> | t = ">" | t = ";" | t = "*" | t = "-" | t = "." | t = "?" )
+        {
+            s.append(t.image);
+        }
+    )+
+    {
+        return s.toString().trim();
+    }
+}
+
+/**
+* Parses sequence data. These data can be made up of any characters
+* from "A" to "Z" (lowercase and uppercase), "-", "." or "?".
+* Spaces, tabs and new lines are omitted.
+* @return String with the sequence data (uppercase always).
+*/
+String Data():
+{
+    StringBuffer s = new StringBuffer();
+    Token t;
+}
+{
+    (
+        (t = <BLANK> | t = <EOL>)
+        |
+        (
+            (t = <UPPER_CASE> | t = <LOWER_CASE> | t = "-" | t = "." | t = "?" )
+            {
+                s.append(t.image);
+            }
+        )
+    )+
+    {
+        return s.toString().toUpperCase();
+    }
+}
\ No newline at end of file
diff --git a/alter-lib/src/parser/package.html b/alter-lib/src/parser/package.html
new file mode 100755
index 0000000..c0a8efa
--- /dev/null
+++ b/alter-lib/src/parser/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    Parsers generated with JavaCC.
+    @author Daniel Gomez Blanco
+    @version 1.2
+  </body>
+</html>
diff --git a/alter-lib/src/reader/AlnReader.java b/alter-lib/src/reader/AlnReader.java
new file mode 100755
index 0000000..ea754af
--- /dev/null
+++ b/alter-lib/src/reader/AlnReader.java
@@ -0,0 +1,79 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package reader;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import parser.AlnParser;
+import parser.ParseException;
+import types.MSA;
+import types.Sequence;
+
+/**
+ * ALN format reader.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class AlnReader implements Reader
+{
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+     /**
+     * Class contructor, it initializes the logger.
+     * @param logger Name of the logger to be instatiated.
+     */
+    public AlnReader(String logger)
+    {
+        this.logger = Logger.getLogger(logger);
+    }
+    
+    /**
+     * Parses an input string and returns an MSA object.
+     * @param in Input string.
+     * @return MSA object parsed from the input string.
+     * @throws ParseException If an error occurs while parsing.
+     */
+    public MSA read(String in) throws ParseException
+    {
+        //Parse input
+        MSA msa = AlnParser.parseMSA(in);
+
+        //Check if MSA is correctly constructed
+        Sequence first = (Sequence)msa.getSeqs().elementAt(0);
+        for(int i=0;i<msa.getSeqs().size();i++)
+        {
+            Sequence seq = (Sequence)msa.getSeqs().elementAt(i);
+            //Check if the sequences lengths are equal
+            if (seq.getData().length() != first.getData().length())
+                throw new ParseException("Sequence lengths are not equal.");
+            //Replace match characters
+            ReaderUtils.replaceMatch(seq, first);
+        }
+
+        logger.log(Level.INFO, "MSA read in ALN format (" +
+                "Taxa = " + msa.getSeqs().size() + ", " +
+                "Length =  " + ((Sequence)msa.getSeqs().elementAt(0)).getData().length() +
+                ").");
+        
+        return msa;
+    }
+}
diff --git a/alter-lib/src/reader/AutodetectionReader.java b/alter-lib/src/reader/AutodetectionReader.java
new file mode 100755
index 0000000..9e79f16
--- /dev/null
+++ b/alter-lib/src/reader/AutodetectionReader.java
@@ -0,0 +1,80 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package reader;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import parser.*;
+import types.MSA;
+
+/**
+ * Autodetection reader
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class AutodetectionReader implements Reader
+{
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+     /**
+     * Class contructor, it initializes the logger.
+     * @param logger Name of the logger to be instatiated.
+     */
+    public AutodetectionReader(String logger)
+    {
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Parses an input string and returns an MSA object.
+     * @param in Input string.
+     * @return MSA object parsed from the input string.
+     * @throws ParseException If an error occurs while parsing.
+     */
+    public MSA read(String in) throws ParseException
+    {
+        //Detect format
+        String inF = AutodetectionParser.detectFormat(in);
+
+        logger.log(Level.INFO, inF.toUpperCase() + " format detected.");
+
+        //Parse input in the detected format
+        Reader reader;
+        if (inF.equals("aln"))
+            reader = new AlnReader(logger.getName());
+        else if (inF.equals("fasta"))
+            reader = new FastaReader(logger.getName());
+        else if (inF.equals("gde"))
+            reader = new GdeReader(logger.getName());
+        else if (inF.equals("msf"))
+            reader = new MsfReader(logger.getName());
+        else if (inF.equals("nexus"))
+            reader = new NexusReader(logger.getName());
+        else if (inF.equals("phylip"))
+            reader = new PhylipReader(logger.getName());
+        else if (inF.equals("pir"))
+            reader = new PirReader(logger.getName());
+        else
+            throw new UnsupportedOperationException("Input format not supported.");
+        return reader.read(in);
+    }
+}
diff --git a/alter-lib/src/reader/FastaReader.java b/alter-lib/src/reader/FastaReader.java
new file mode 100755
index 0000000..8ef7a7e
--- /dev/null
+++ b/alter-lib/src/reader/FastaReader.java
@@ -0,0 +1,78 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package reader;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import parser.FastaParser;
+import parser.ParseException;
+import types.MSA;
+import types.Sequence;
+
+/**
+ * FASTA format reader.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class FastaReader implements Reader
+{
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+     /**
+     * Class contructor, it initializes the logger.
+     * @param logger Name of the logger to be instatiated.
+     */
+    public FastaReader(String logger)
+    {
+        this.logger = Logger.getLogger(logger);
+    }
+    
+    /**
+     * Parses an input string and returns an MSA object.
+     * @param in Input string.
+     * @return MSA object parsed from the input string.
+     * @throws ParseException If an error occurs while parsing.
+     */
+    public MSA read(String in) throws ParseException
+    {
+        //Parse input
+        MSA msa = FastaParser.parseMSA(in);
+
+        //Check if MSA is correctly constructed
+        Sequence first = (Sequence)msa.getSeqs().elementAt(0);
+        for(int i=0;i<msa.getSeqs().size();i++)
+        {
+            Sequence seq = (Sequence)msa.getSeqs().elementAt(i);
+            //Check if the sequences lengths are equal
+            if (seq.getData().length() != first.getData().length())
+                throw new ParseException("Sequence lengths are not equal.");
+            //Replace match characters
+            ReaderUtils.replaceMatch(seq, first);
+        }
+
+        logger.log(Level.INFO, "MSA read in FASTA format (" +
+                "Taxa = " + msa.getSeqs().size() + ", " +
+                "Length =  " + ((Sequence)msa.getSeqs().elementAt(0)).getData().length() +
+                ").");
+
+        return msa;
+    }
+}
diff --git a/alter-lib/src/reader/GdeReader.java b/alter-lib/src/reader/GdeReader.java
new file mode 100755
index 0000000..fe943b9
--- /dev/null
+++ b/alter-lib/src/reader/GdeReader.java
@@ -0,0 +1,79 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package reader;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import parser.GdeParser;
+import parser.ParseException;
+import types.MSA;
+import types.Sequence;
+
+/**
+ * GDE format reader.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class GdeReader implements Reader
+{
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+     /**
+     * Class contructor, it initializes the logger.
+     * @param logger Name of the logger to be instatiated.
+     */
+    public GdeReader(String logger)
+    {
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Parses an input string and returns an MSA object.
+     * @param in Input string.
+     * @return MSA object parsed from the input string.
+     * @throws ParseException If an error occurs while parsing.
+     */
+    public MSA read(String in) throws ParseException
+    {
+        //Parse input
+        MSA msa = GdeParser.parseMSA(in);
+
+        //Check if MSA is correctly constructed
+        Sequence first = (Sequence)msa.getSeqs().elementAt(0);
+        for(int i=0;i<msa.getSeqs().size();i++)
+        {
+            Sequence seq = (Sequence)msa.getSeqs().elementAt(i);
+            //Check if the sequences lengths are equal
+            if (seq.getData().length() != first.getData().length())
+                throw new ParseException("Sequence lengths are not equal.");
+            //Replace match characters
+            ReaderUtils.replaceMatch(seq, first);
+        }
+
+        logger.log(Level.INFO, "MSA read in GDE format (" +
+                "Taxa = " + msa.getSeqs().size() + ", " +
+                "Length =  " + ((Sequence)msa.getSeqs().elementAt(0)).getData().length() +
+                ").");
+        
+        return msa;
+    }
+}
diff --git a/alter-lib/src/reader/MsfReader.java b/alter-lib/src/reader/MsfReader.java
new file mode 100755
index 0000000..a49f1f7
--- /dev/null
+++ b/alter-lib/src/reader/MsfReader.java
@@ -0,0 +1,79 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package reader;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import parser.MsfParser;
+import parser.ParseException;
+import types.MSA;
+import types.Msf;
+import types.MsfSequence;
+import types.Sequence;
+
+/**
+ * MSF format reader.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class MsfReader implements Reader
+{
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+     /**
+     * Class contructor, it initializes the logger.
+     * @param logger Name of the logger to be instatiated.
+     */
+    public MsfReader(String logger)
+    {
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Parses an input string and returns an MSA object.
+     * @param in Input string.
+     * @return MSA object parsed from the input string.
+     * @throws ParseException If an error occurs while parsing.
+     */
+    public MSA read(String in) throws ParseException
+    {
+        //Parse input
+        Msf msa = MsfParser.parseMSA(in);
+
+        //Check if MSA is correctly constructed
+        for(int i=0;i<msa.getSeqs().size();i++)
+        {
+            Sequence seq = (Sequence)msa.getSeqs().elementAt(i);
+            //Check if the sequences lengths are equal
+            if (seq.getData().length() != msa.getLength()
+                    || seq.getData().length() != ((MsfSequence)seq).getLength())
+                throw new ParseException("Sequence lengths are not equal to the given length.");
+        }
+
+        logger.log(Level.INFO, "MSA read in MSF format (" +
+                "Taxa = " + msa.getSeqs().size() + ", " +
+                "Length =  " + ((Sequence)msa.getSeqs().elementAt(0)).getData().length() +
+                ").");
+        
+        return msa;
+    }
+}
\ No newline at end of file
diff --git a/alter-lib/src/reader/NexusReader.java b/alter-lib/src/reader/NexusReader.java
new file mode 100755
index 0000000..8ea9c06
--- /dev/null
+++ b/alter-lib/src/reader/NexusReader.java
@@ -0,0 +1,84 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package reader;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import parser.NexusParser;
+import parser.ParseException;
+import types.MSA;
+import types.Nexus;
+import types.Sequence;
+
+/**
+ * NEXUS format reader.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class NexusReader implements Reader
+{
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+     /**
+     * Class contructor, it initializes the logger.
+     * @param logger Name of the logger to be instatiated.
+     */
+    public NexusReader(String logger)
+    {
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Parses an input string and returns an MSA object.
+     * @param in Input string.
+     * @return MSA object parsed from the input string.
+     * @throws ParseException If an error occurs while parsing.
+     */
+    public MSA read(String in) throws ParseException
+    {
+        //Parse input
+        Nexus msa = NexusParser.parseMSA(in);
+
+        //Check if the number of sequences is equal to the given one
+        if (msa.getSeqs().size() != msa.getTaxa())
+            throw new ParseException("Number of sequences is not equal to the given number.");
+
+        //Check if MSA is correctly constructed
+        Sequence first = (Sequence)msa.getSeqs().elementAt(0);
+        for(int i=0;i<msa.getSeqs().size();i++)
+        {
+            Sequence seq = (Sequence)msa.getSeqs().elementAt(i);
+            //Check if the sequences lengths are equal
+            if (seq.getData().length() != msa.getLength())
+                throw new ParseException("Sequence lengths are not equal to the given length.");
+            //Replace match characters
+            ReaderUtils.replaceMatch(seq, first);
+        }
+
+        logger.log(Level.INFO, "MSA read in NEXUS format (" +
+                "Taxa = " + msa.getSeqs().size() + ", " +
+                "Length =  " + ((Sequence)msa.getSeqs().elementAt(0)).getData().length() +
+                ").");
+
+        return msa;
+    }
+}
diff --git a/alter-lib/src/reader/PhylipReader.java b/alter-lib/src/reader/PhylipReader.java
new file mode 100755
index 0000000..3971b7c
--- /dev/null
+++ b/alter-lib/src/reader/PhylipReader.java
@@ -0,0 +1,85 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package reader;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import parser.ParseException;
+import parser.PhylipParser;
+import types.MSA;
+import types.Phylip;
+import types.Sequence;
+
+/**
+ * PHYLIP format reader.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class PhylipReader implements Reader
+{
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+     /**
+     * Class contructor, it initializes the logger.
+     * @param logger Name of the logger to be instatiated.
+     */
+    public PhylipReader(String logger)
+    {
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Parses an input string and returns an MSA object.
+     * @param in Input string.
+     * @return MSA object parsed from the input string.
+     * @throws ParseException If an error occurs while parsing.
+     */
+    public MSA read(String in) throws ParseException
+    {
+        //Parse input
+        Phylip msa = PhylipParser.parseMSA(in);
+
+        //Check if the number of sequences is equal to the given one
+        if (msa.getSeqs().size() != msa.getTaxa())
+            throw new ParseException("Number of sequences is not equal to the given number.");
+
+        //Check if MSA is correctly constructed
+        Sequence first = (Sequence)msa.getSeqs().elementAt(0);
+        for(int i=0;i<msa.getSeqs().size();i++)
+        {
+            Sequence seq = (Sequence)msa.getSeqs().elementAt(i);
+            //Check if the sequences lengths are equal
+            if (seq.getData().length() != msa.getLength())
+                throw new ParseException("Sequence lengths are not equal to the given length.");
+            //Replace match characters
+            ReaderUtils.replaceMatch(seq, first);
+        }
+
+
+        logger.log(Level.INFO, "MSA read in PHYLIP format (" +
+                "Taxa = " + msa.getSeqs().size() + ", " +
+                "Length =  " + ((Sequence)msa.getSeqs().elementAt(0)).getData().length() +
+                ").");
+
+        return msa;
+    }
+}
diff --git a/alter-lib/src/reader/PirReader.java b/alter-lib/src/reader/PirReader.java
new file mode 100755
index 0000000..c669793
--- /dev/null
+++ b/alter-lib/src/reader/PirReader.java
@@ -0,0 +1,81 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package reader;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import parser.ParseException;
+import parser.PirParser;
+import types.MSA;
+import types.PirSequence;
+
+/**
+ * PIR format reader.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+public class PirReader implements Reader
+{
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+     /**
+     * Class contructor, it initializes the logger.
+     * @param logger Name of the logger to be instatiated.
+     */
+    public PirReader(String logger)
+    {
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Parses an input string and returns an MSA object.
+     * @param in Input string.
+     * @return MSA object parsed from the input string.
+     * @throws ParseException If an error occurs while parsing.
+     */
+    public MSA read(String in) throws ParseException
+    {
+        //Parse input
+        MSA msa = PirParser.parseMSA(in);
+
+        //Check if MSA is correctly constructed
+        PirSequence first = (PirSequence)msa.getSeqs().elementAt(0);
+        for(int i=0;i<msa.getSeqs().size();i++)
+        {
+            PirSequence seq = (PirSequence)msa.getSeqs().elementAt(i);
+            //Check if the sequences lengths are equal
+            if (seq.getData().length() != first.getData().length())
+                throw new ParseException("Sequence lengths are not equal.");
+            //Check if the types are equal
+            if (seq.getType().getClass() != first.getType().getClass())
+                throw new ParseException("Sequence types are not equal.");
+            //Replace match characters
+            ReaderUtils.replaceMatch(seq, first);
+        }
+
+        logger.log(Level.INFO, "MSA read in PIR format (" +
+                "Taxa = " + msa.getSeqs().size() + ", " +
+                "Length =  " + ((PirSequence)msa.getSeqs().elementAt(0)).getData().length() +
+                ").");
+
+        return msa;
+    }
+}
diff --git a/alter-lib/src/reader/Reader.java b/alter-lib/src/reader/Reader.java
new file mode 100755
index 0000000..ed1850d
--- /dev/null
+++ b/alter-lib/src/reader/Reader.java
@@ -0,0 +1,37 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package reader;
+
+import parser.ParseException;
+import types.MSA;
+
+/**
+ * Defines the method that readers must implement.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public interface Reader
+{
+    /**
+     * Parses an input string and returns an MSA object.
+     * @param in Input string.
+     * @return MSA object parsed from the input string.
+     * @throws ParseException If an error occurs while parsing.
+     */
+    public MSA read(String in) throws ParseException;
+}
diff --git a/alter-lib/src/reader/ReaderUtils.java b/alter-lib/src/reader/ReaderUtils.java
new file mode 100755
index 0000000..8d9ba79
--- /dev/null
+++ b/alter-lib/src/reader/ReaderUtils.java
@@ -0,0 +1,53 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package reader;
+
+import parser.ParseException;
+import types.Sequence;
+
+/**
+ * Provides static methods common to every reader.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class ReaderUtils
+{
+    /**
+     * Replaces match characters with the character in the same position of the
+     * first sequence of the MSA.
+     * @param seq Current sequence.
+     * @param first First sequence of the MSA.
+     * @throws ParseException If a match character is trying to be replaced by a "?", "." or "-" character.
+     */
+    public static void replaceMatch(Sequence seq, Sequence first) throws ParseException
+    {
+        if (seq.getData().contains("."))
+            //Lanzar excepción si el caracter está en la primera secuencia
+            if (seq == first)
+                throw new ParseException("Match character \".\" in first sequence of MSA.");
+            else
+                for(int j=0;j<seq.getData().length();j++)
+                    if (seq.getData().charAt(j) == '.')
+                        if (first.getData().charAt(j) == '?'
+                            || first.getData().charAt(j) == '-')
+                            throw new ParseException("Match character \".\" cannot be replaced by \"?\" or \"-\".");
+                        else
+                            seq.replaceChar(j, first.getData().charAt(j));
+    }
+}
diff --git a/alter-lib/src/reader/package.html b/alter-lib/src/reader/package.html
new file mode 100755
index 0000000..0ba894e
--- /dev/null
+++ b/alter-lib/src/reader/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    Reader to parse input MSAs.
+    @author Daniel Gomez Blanco
+    @version 1.0
+  </body>
+</html>
diff --git a/alter-lib/src/types/Aln.java b/alter-lib/src/types/Aln.java
new file mode 100755
index 0000000..d1096f5
--- /dev/null
+++ b/alter-lib/src/types/Aln.java
@@ -0,0 +1,71 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+package types;
+
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * MSA in ALN format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class Aln extends MSA
+{
+    /**
+     * Class constructor.
+     * @param seqs Vector containing aligned sequences.
+     */
+    public Aln(Vector<AlnSequence> seqs)
+    {
+        super(seqs);
+    }
+
+    /**
+     * Collapse sequences to haplotypes. It creates a new MSA object with the
+     * result sequences and then returns it.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @param log Name of the logger to be instantiated.
+     * @return New MSA containing the result sequences.
+     */
+    @Override
+    public MSA collapse(boolean gapsAsMissing, boolean countMissing, int limit, String log)
+    {
+        Logger logger = Logger.getLogger(log);
+        Vector<AlnSequence> newSeqs = new Vector<AlnSequence>();
+        newSeqs.add((AlnSequence) seqs.firstElement());
+
+        for(int i=1;i<seqs.size();i++)
+        {
+            AlnSequence seq = (AlnSequence) seqs.elementAt(i);
+            Sequence unique = isUnique(seq, newSeqs, gapsAsMissing, countMissing, limit);
+            if (unique != null)
+                logger.log(Level.INFO, "Sequence \"" + seq.getId() + "\" is equal" +
+                        " to sequence \"" + unique.getId() + "\". Sequence removed.");
+            else
+                newSeqs.add(seq);
+        }
+
+        return new Aln(newSeqs);
+    }
+}
diff --git a/alter-lib/src/types/AlnSequence.java b/alter-lib/src/types/AlnSequence.java
new file mode 100755
index 0000000..052d209
--- /dev/null
+++ b/alter-lib/src/types/AlnSequence.java
@@ -0,0 +1,37 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Sequence in ALN format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class AlnSequence extends Sequence
+{
+    /**
+     * Class constructor.
+     * @param id Sequence identifier.
+     * @param data Sequence data.
+     */
+    public AlnSequence(String id, String data)
+    {
+        super(id,data);
+    }
+}
diff --git a/alter-lib/src/types/Checksumable.java b/alter-lib/src/types/Checksumable.java
new file mode 100755
index 0000000..a2846b9
--- /dev/null
+++ b/alter-lib/src/types/Checksumable.java
@@ -0,0 +1,34 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Defines method getChecksum() that all sequence or MSA classes containing
+ * a checksum must implement.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public interface Checksumable
+{
+    /**
+     * Returns the sequence or MSA checksum.
+     * @return Sequence or MSA checksum.
+     */
+    public int getChecksum();
+}
diff --git a/alter-lib/src/types/DNA.java b/alter-lib/src/types/DNA.java
new file mode 100755
index 0000000..96d3ffa
--- /dev/null
+++ b/alter-lib/src/types/DNA.java
@@ -0,0 +1,26 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * DNA type.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class DNA extends Nucleotide{}
diff --git a/alter-lib/src/types/DNACircular.java b/alter-lib/src/types/DNACircular.java
new file mode 100755
index 0000000..689e0f3
--- /dev/null
+++ b/alter-lib/src/types/DNACircular.java
@@ -0,0 +1,26 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Circular DNA type.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class DNACircular extends DNA{}
diff --git a/alter-lib/src/types/DNALinear.java b/alter-lib/src/types/DNALinear.java
new file mode 100755
index 0000000..9cd17c2
--- /dev/null
+++ b/alter-lib/src/types/DNALinear.java
@@ -0,0 +1,26 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Liner DNA type.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class DNALinear extends DNA{}
diff --git a/alter-lib/src/types/Describable.java b/alter-lib/src/types/Describable.java
new file mode 100755
index 0000000..de7efb8
--- /dev/null
+++ b/alter-lib/src/types/Describable.java
@@ -0,0 +1,33 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Defines method getDesc() that all sequence classes containing a description
+ * must implement.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public interface Describable
+{
+    /**
+     * Returns the sequence description.
+     * @return Sequence description.
+     */
+    public String getDesc();
+}
diff --git a/alter-lib/src/types/Fasta.java b/alter-lib/src/types/Fasta.java
new file mode 100755
index 0000000..d6735ba
--- /dev/null
+++ b/alter-lib/src/types/Fasta.java
@@ -0,0 +1,70 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * MSA in FASTA format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class Fasta extends MSA
+{
+    /**
+     * Class constructor.
+     * @param seqs Vector containing aligned sequences.
+     */
+    public Fasta(Vector<FastaSequence> seqs)
+    {
+        super(seqs);
+    }
+
+    /**
+     * Collapse sequences to haplotypes. It creates a new MSA object with the
+     * result sequences and then returns it.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @param log Name of the logger to be instantiated.
+     * @return New MSA containing the result sequences.
+     */
+    @Override
+    public MSA collapse(boolean gapsAsMissing, boolean countMissing, int limit, String log)
+    {
+        Logger logger = Logger.getLogger(log);
+        Vector<FastaSequence> newSeqs = new Vector<FastaSequence>();
+        newSeqs.add((FastaSequence) seqs.firstElement());
+
+        for(int i=1;i<seqs.size();i++)
+        {
+            FastaSequence seq = (FastaSequence) seqs.elementAt(i);
+            Sequence unique = isUnique(seq, newSeqs, gapsAsMissing, countMissing, limit);
+            if (unique != null)
+                logger.log(Level.INFO, "Sequence \"" + seq.getId() + "\" is equal" +
+                        " to sequence \"" + unique.getId() + "\". Sequence removed.");
+            else
+                newSeqs.add(seq);
+        }
+
+        return new Fasta(newSeqs);
+    }
+}
diff --git a/alter-lib/src/types/FastaSequence.java b/alter-lib/src/types/FastaSequence.java
new file mode 100755
index 0000000..e70cb9a
--- /dev/null
+++ b/alter-lib/src/types/FastaSequence.java
@@ -0,0 +1,53 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Sequence in FASTA format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class FastaSequence extends Sequence implements Describable
+{
+    /**
+     * Sequence description.
+     */
+    private String desc;
+
+    /**
+     * Class constructor.
+     * @param id Sequence identifier.
+     * @param desc Sequence description.
+     * @param data Sequence data.
+     */
+    public FastaSequence(String id, String desc, String data)
+    {
+        super(id, data);
+        this.desc = desc;
+    }
+
+    /**
+     * Returns the sequence data.
+     * @return Sequence data.
+     */
+    public String getDesc()
+    {
+        return desc;
+    }
+}
diff --git a/alter-lib/src/types/Gde.java b/alter-lib/src/types/Gde.java
new file mode 100755
index 0000000..e68bde9
--- /dev/null
+++ b/alter-lib/src/types/Gde.java
@@ -0,0 +1,70 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * MSA in GDE format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class Gde extends MSA
+{
+    /**
+     * Class constructor.
+     * @param seqs Vector containing aligned sequences.
+     */
+    public Gde(Vector<GdeSequence> seqs)
+    {
+        super(seqs);
+    }
+
+    /**
+     * Collapse sequences to haplotypes. It creates a new MSA object with the
+     * result sequences and then returns it.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @param log Name of the logger to be instantiated.
+     * @return New MSA containing the result sequences.
+     */
+    @Override
+    public MSA collapse(boolean gapsAsMissing, boolean countMissing, int limit, String log)
+    {
+        Logger logger = Logger.getLogger(log);
+        Vector<GdeSequence> newSeqs = new Vector<GdeSequence>();
+        newSeqs.add((GdeSequence) seqs.firstElement());
+
+        for(int i=1;i<seqs.size();i++)
+        {
+            GdeSequence seq = (GdeSequence) seqs.elementAt(i);
+            Sequence unique = isUnique(seq, newSeqs, gapsAsMissing, countMissing, limit);
+            if (unique != null)
+                logger.log(Level.INFO, "Sequence \"" + seq.getId() + "\" is equal" +
+                        " to sequence \"" + unique.getId() + "\". Sequence removed.");
+            else
+                newSeqs.add(seq);
+        }
+
+        return new Gde(newSeqs);
+    }
+}
diff --git a/alter-lib/src/types/GdeSequence.java b/alter-lib/src/types/GdeSequence.java
new file mode 100755
index 0000000..bae1006
--- /dev/null
+++ b/alter-lib/src/types/GdeSequence.java
@@ -0,0 +1,37 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Sequence in GDE format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class GdeSequence extends Sequence
+{
+    /**
+     * Class constructor.
+     * @param id Sequence identifier.
+     * @param data Sequence data.
+     */
+    public GdeSequence(String id, String data)
+    {
+        super(id, data);
+    }
+}
diff --git a/alter-lib/src/types/Lengthable.java b/alter-lib/src/types/Lengthable.java
new file mode 100755
index 0000000..d0ca6a0
--- /dev/null
+++ b/alter-lib/src/types/Lengthable.java
@@ -0,0 +1,34 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Defines method getLength() that all sequence or MSA classes containing the
+ * length attibute must implement.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public interface Lengthable
+{
+    /**
+     * Returns the MSA or sequence length.
+     * @return MSA or sequence length.
+     */
+    public int getLength();
+}
diff --git a/alter-lib/src/types/MSA.java b/alter-lib/src/types/MSA.java
new file mode 100755
index 0000000..bd2d8d9
--- /dev/null
+++ b/alter-lib/src/types/MSA.java
@@ -0,0 +1,133 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+import java.util.Vector;
+
+/**
+ * Abstract class representing a MSA.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public abstract class MSA
+{
+    /**
+     * Aligned sequences vector.
+     */
+    protected Vector seqs;
+
+    /**
+     * Class constructor.
+     * @param seqs Aligned sequences vector.
+     */
+    public MSA(Vector seqs)
+    {
+        this.seqs = seqs;
+    }
+
+    /**
+     * Returns the aligned sequences.
+     * @return Aligned sequences vector.
+     */
+    public Vector getSeqs()
+    {
+        return seqs;
+    }
+
+    /**
+     * Adds a sequence to the sequences vector.
+     * @param seq Sequence to be added to the vector.
+     */
+    public void addSeq(Sequence seq)
+    {
+        seqs.add(seq);
+    }
+
+    /**
+     * Collapse sequences to haplotypes. It creates a new MSA object with the
+     * result sequences and then returns it.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @param log Name of the logger to be instantiated.
+     * @return New MSA containing the result sequences.
+     */
+    public abstract MSA collapse(boolean gapsAsMissing, boolean countMissing, int limit, String logger);
+
+    /**
+     * Checks if a sequence is unique in the vector till his position in it,
+     * according to the given parameters. It compares all previous positions
+     * in the vector to the given one, checking for equivalent sequences.
+     * @param seq Sequence be checked.
+     * @param seqs Sequences vector.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @return La secuencia a la que es equivalente la secuencia actual. Null en caso de que no exista ninguna secuencia equivalente.
+     */
+    protected Sequence isUnique(Sequence seq, Vector seqs, boolean gapsAsMissing, boolean countMissing, int limit)
+    {
+        //Sequence data
+        String data = seq.getData();
+
+        //Sequence to compare to (start with the first)
+        Sequence uniqueSeq = (Sequence) seqs.firstElement();
+        //Counter
+        int cont = 0;
+        while(cont < seqs.size() && seq != uniqueSeq)
+        {
+            //Data to compare to
+            String unique = uniqueSeq.getData();
+            //Number of differences
+            int diff = 0;
+            int miss = 0;
+            int gaps = 0;
+            //For each site
+            for (int i=0; i<data.length();i++)
+            {
+                char c1 = data.charAt(i);
+                char c2 = unique.charAt(i);
+                if(c1 == c2)
+                    continue;
+                else if (c1 == '?' || c2 == '?')
+                    miss++;
+                else if (c1 == '-' || c2 == '-')
+                    gaps++;
+                else
+                    diff++;
+            }
+
+            if (gapsAsMissing)
+                miss += gaps;
+            else
+                diff += gaps;
+
+            if (countMissing)
+                diff += miss;
+
+            if (diff <= limit)
+                return uniqueSeq;
+            cont++;
+            if (cont < seqs.size())
+                uniqueSeq = (Sequence) seqs.elementAt(cont);
+        }
+
+        return null;
+    }
+}
diff --git a/alter-lib/src/types/Msf.java b/alter-lib/src/types/Msf.java
new file mode 100755
index 0000000..d6cdd14
--- /dev/null
+++ b/alter-lib/src/types/Msf.java
@@ -0,0 +1,137 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * MSA in MSF format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class Msf extends MSA implements Lengthable, Typeable, Checksumable
+{
+    /**
+     * Length of the sequences in the MSA.
+     */
+    private int length;
+    /**
+     * MSA type.
+     */
+    private Type type;
+    /**
+     * MSA checksum.
+     */
+    private int check;
+
+    /**
+     * Class constructor.
+     * @param seqs Sequences vector.
+     * @param length Sequences length.
+     * @param type MSA type.
+     * @param check MSA checksum.
+     */
+    public Msf(Vector<MsfSequence> seqs, int length, String type, int check)
+    {
+        super(seqs);
+        this.length = length;
+        this.check = check;
+
+        if (type.equals("N"))
+            this.type = new Nucleotide();
+        else if (type.equals("P") || type.equals("A"))
+            this.type = new Protein();
+        else
+            this.type = null;
+    }
+
+    /**
+     * Class constructor. Gets as type an object of class Type.
+     * @param seqs Sequences vector.
+     * @param length Sequences length.
+     * @param type MSA type.
+     * @param check MSA checksum.
+     */
+    public Msf(Vector<MsfSequence> seqs, int length, Type type, int check)
+    {
+        super(seqs);
+        this.length = length;
+        this.check = check;
+        this.type = type;
+    }
+
+    /**
+     * Returs MSA checksum.
+     * @return MSA checksum.
+     */
+    public int getChecksum()
+    {
+        return check;
+    }
+
+    /**
+     * Returns the MSA length.
+     * @return MSA length.
+     */
+    public int getLength()
+    {
+        return length;
+    }
+
+    /**
+     * Returns the MSA type.
+     * @return MSA type.
+     */
+    public Type getType()
+    {
+        return type;
+    }
+
+    /**
+     * Collapse sequences to haplotypes. It creates a new MSA object with the
+     * result sequences and then returns it.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @param log Name of the logger to be instantiated.
+     * @return New MSA containing the result sequences.
+     */
+    @Override
+    public MSA collapse(boolean gapsAsMissing, boolean countMissing, int limit, String log)
+    {
+        Logger logger = Logger.getLogger(log);
+        Vector<MsfSequence> newSeqs = new Vector<MsfSequence>();
+        newSeqs.add((MsfSequence) seqs.firstElement());
+
+        for(int i=1;i<seqs.size();i++)
+        {
+            MsfSequence seq = (MsfSequence) seqs.elementAt(i);
+            Sequence unique = isUnique(seq, newSeqs, gapsAsMissing, countMissing, limit);
+            if (unique != null)
+                logger.log(Level.INFO, "Sequence \"" + seq.getId() + "\" is equal" +
+                        " to sequence \"" + unique.getId() + "\". Sequence removed.");
+            else
+                newSeqs.add(seq);
+        }
+
+        return new Msf(newSeqs, length, type, check);
+    }
+}
diff --git a/alter-lib/src/types/MsfSequence.java b/alter-lib/src/types/MsfSequence.java
new file mode 100755
index 0000000..dfa8728
--- /dev/null
+++ b/alter-lib/src/types/MsfSequence.java
@@ -0,0 +1,83 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Sequence in MSF format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class MsfSequence extends Sequence implements Checksumable, Lengthable, Weightable
+{
+    /**
+     * Sequence length.
+     */
+    private int length;
+    /**
+     * Sequence checksum.
+     */
+    private int check;
+    /**
+     * Sequence weight.
+     */
+    private float weight;
+
+    /**
+     * Class constructor.
+     * @param id Sequence identifier.
+     * @param length Sequence length.
+     * @param check Sequence checksum.
+     * @param weight Sequence weight.
+     * @param data Sequence data.
+     */
+    public MsfSequence (String id, int length, int check, float weight, String data)
+    {
+        super(id, data);
+        this.length = length;
+        this.check = check;
+        this.weight = weight;
+    }
+
+    /**
+     * Returns the sequence checksum.
+     * @return Sequence checksum.
+     */
+    public int getChecksum()
+    {
+        return check;
+    }
+
+    /**
+     * Returns sequence length.
+     * @return Sequence length.
+     */
+    public int getLength()
+    {
+        return length;
+    }
+
+    /**
+     * Returns sequence weight.
+     * @return Sequence weight.
+     */
+    public float getWeight()
+    {
+        return weight;
+    }
+}
diff --git a/alter-lib/src/types/Nexus.java b/alter-lib/src/types/Nexus.java
new file mode 100755
index 0000000..0f731dc
--- /dev/null
+++ b/alter-lib/src/types/Nexus.java
@@ -0,0 +1,141 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * MSA in NEXUS format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class Nexus extends MSA implements Lengthable, Typeable, Taxable
+{
+    /**
+     * Number of sequences in the MSA.
+     */
+    private int taxa;
+    /**
+     * Length of the sequences in the MSA.
+     */
+    private int length;
+    /**
+     * MSA type.
+     */
+    private Type type;
+
+    /**
+     * Class constructor.
+     * @param taxa Number of sequences in the MSA.
+     * @param length Length of the sequences in the MSA.
+     * @param type Type of MSA.
+     * @param seqs Sequences vector.
+     */
+    public Nexus(int taxa, int length, String type, Vector<NexusSequence> seqs)
+    {
+        super(seqs);
+        this.taxa = taxa;
+        this.length = length;
+
+        if (type.equals("PROTEIN"))
+            this.type = new Protein();
+        else if (type.equals("NUCLEOTIDE"))
+            this.type = new Nucleotide();
+        else if (type.equals("DNA"))
+            this.type = new DNA();
+        else if (type.equals("RNA"))
+            this.type = new RNA();
+        else
+            this.type = null;
+    }
+
+    /**
+     * Class constructor. Gets as the type an object of class Type.
+     * @param taxa Number of sequences in the MSA.
+     * @param length Length of the sequences in the MSA.
+     * @param type Type of MSA.
+     * @param seqs Sequences vector.
+     */
+    public Nexus(int taxa, int length, Type type, Vector<NexusSequence> seqs)
+    {
+        super(seqs);
+        this.taxa = taxa;
+        this.length = length;
+        this.type = type;
+    }
+
+    /**
+     * Returns the number of sequences in the MSA.
+     * @return Number of sequences.
+     */
+    public int getTaxa()
+    {
+        return taxa;
+    }
+
+    /**
+     * Returns the MSA type.
+     * @return MSA type.
+     */
+    public Type getType()
+    {
+        return type;
+    }
+
+    /**
+     * Returns the length of the sequences in the MSA.
+     * @return Length of the sequences in the MSA.
+     */
+    public int getLength()
+    {
+        return length;
+    }
+
+    /**
+     * Collapse sequences to haplotypes. It creates a new MSA object with the
+     * result sequences and then returns it.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @param log Name of the logger to be instantiated.
+     * @return New MSA containing the result sequences.
+     */
+    @Override
+    public MSA collapse(boolean gapsAsMissing, boolean countMissing, int limit, String log)
+    {
+        Logger logger = Logger.getLogger(log);
+        Vector<NexusSequence> newSeqs = new Vector<NexusSequence>();
+        newSeqs.add((NexusSequence) seqs.firstElement());
+
+        for(int i=1;i<seqs.size();i++)
+        {
+            NexusSequence seq = (NexusSequence) seqs.elementAt(i);
+            Sequence unique = isUnique(seq, newSeqs, gapsAsMissing, countMissing, limit);
+            if (unique != null)
+                logger.log(Level.INFO, "Sequence \"" + seq.getId() + "\" is equal" +
+                        " to sequence \"" + unique.getId() + "\". Sequence removed.");
+            else
+                newSeqs.add(seq);
+        }
+
+        return new Nexus(newSeqs.size(), length, type, newSeqs);
+    }
+}
diff --git a/alter-lib/src/types/NexusSequence.java b/alter-lib/src/types/NexusSequence.java
new file mode 100755
index 0000000..9d69352
--- /dev/null
+++ b/alter-lib/src/types/NexusSequence.java
@@ -0,0 +1,37 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Sequence in NEXUS format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class NexusSequence extends Sequence
+{
+    /**
+     * Class constructor.
+     * @param id Sequence identifier.
+     * @param data Sequence data.
+     */
+    public NexusSequence(String id, String data)
+    {
+        super(id,data);
+    }
+}
diff --git a/alter-lib/src/types/Nucleotide.java b/alter-lib/src/types/Nucleotide.java
new file mode 100755
index 0000000..dd1b60f
--- /dev/null
+++ b/alter-lib/src/types/Nucleotide.java
@@ -0,0 +1,26 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Nucleotide type.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class Nucleotide extends Type{}
diff --git a/alter-lib/src/types/Phylip.java b/alter-lib/src/types/Phylip.java
new file mode 100755
index 0000000..5bbf1d3
--- /dev/null
+++ b/alter-lib/src/types/Phylip.java
@@ -0,0 +1,101 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * MSA in PHYLIP format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class Phylip extends MSA implements Lengthable, Taxable
+{
+    /**
+     * Number of sequences in the MSA.
+     */
+    private int taxa;
+    /**
+     * Length of the sequences in the MSA.
+     */
+    private int length;
+
+    /**
+     * Class constructor.
+     * @param taxa Number of sequences in the MSA.
+     * @param length Sequences length.
+     * @param seqs Sequences vector.
+     */
+    public Phylip(int taxa, int length, Vector<PhylipSequence> seqs)
+    {
+        super(seqs);
+        this.taxa = taxa;
+        this.length = length;
+    }
+
+    /**
+     * Returns the length of the sequences in the MSA.
+     * @return Length of the sequences in the MSA.
+     */
+    public int getLength()
+    {
+        return length;
+    }
+
+    /**
+     * Returns the number of sequenes in the MSA
+     * @return Number of sequences in the MSA.
+     */
+    public int getTaxa()
+    {
+        return taxa;
+    }
+
+    /**
+     * Collapse sequences to haplotypes. It creates a new MSA object with the
+     * result sequences and then returns it.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @param log Name of the logger to be instantiated.
+     * @return New MSA containing the result sequences.
+     */
+    @Override
+    public MSA collapse(boolean gapsAsMissing, boolean countMissing, int limit, String log)
+    {
+        Logger logger = Logger.getLogger(log);
+        Vector<PhylipSequence> newSeqs = new Vector<PhylipSequence>();
+        newSeqs.add((PhylipSequence) seqs.firstElement());
+
+        for(int i=1;i<seqs.size();i++)
+        {
+            PhylipSequence seq = (PhylipSequence) seqs.elementAt(i);
+            Sequence unique = isUnique(seq, newSeqs, gapsAsMissing, countMissing, limit);
+            if (unique != null)
+                logger.log(Level.INFO, "Sequence \"" + seq.getId() + "\" is equal" +
+                        " to sequence \"" + unique.getId() + "\". Sequence removed.");
+            else
+                newSeqs.add(seq);
+        }
+
+        return new Phylip(newSeqs.size(), length, newSeqs);
+    }
+}
diff --git a/alter-lib/src/types/PhylipSequence.java b/alter-lib/src/types/PhylipSequence.java
new file mode 100755
index 0000000..e7bdecf
--- /dev/null
+++ b/alter-lib/src/types/PhylipSequence.java
@@ -0,0 +1,37 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Sequence in PHYLIP format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipSequence extends Sequence
+{
+    /**
+     * Class constructor.
+     * @param id Sequence identifier.
+     * @param data Sequence data.
+     */
+    public PhylipSequence(String id, String data)
+    {
+        super(id, data);
+    }
+}
diff --git a/alter-lib/src/types/Pir.java b/alter-lib/src/types/Pir.java
new file mode 100755
index 0000000..952c69e
--- /dev/null
+++ b/alter-lib/src/types/Pir.java
@@ -0,0 +1,79 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * MSA in PIR format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public class Pir extends MSA implements Typeable
+{
+    /**
+     * Class constructor.
+     * @param seqs Sequences vector.
+     */
+    public Pir(Vector<PirSequence> seqs)
+    {
+        super(seqs);
+    }
+
+    /**
+     * Returns the MSA type. Returns the type of the first sequence in the MSA.
+     * It is assumed that all sequences are of the same type in a MSA.
+     * @return Tipo del MSA.
+     */
+    public Type getType()
+    {
+        return ((PirSequence) this.getSeqs().firstElement()).getType();
+    }
+
+    /**
+     * Collapse sequences to haplotypes. It creates a new MSA object with the
+     * result sequences and then returns it.
+     * @param gapsAsMissing Treat gaps as missing data when collapsing.
+     * @param countMissing Count missing data as differences when collapsing.
+     * @param limit Connection limit (sequences differing at <= l sites will be collapsed).
+     * @param log Name of the logger to be instantiated.
+     * @return New MSA containing the result sequences.
+     */
+    @Override
+    public MSA collapse(boolean gapsAsMissing, boolean countMissing, int limit, String log)
+    {
+        Logger logger = Logger.getLogger(log);
+        Vector<PirSequence> newSeqs = new Vector<PirSequence>();
+        newSeqs.add((PirSequence) seqs.firstElement());
+
+        for(int i=1;i<seqs.size();i++)
+        {
+            PirSequence seq = (PirSequence) seqs.elementAt(i);
+            Sequence unique = isUnique(seq, newSeqs, gapsAsMissing, countMissing, limit);
+            if (unique != null)
+                logger.log(Level.INFO, "Sequence \"" + seq.getId() + "\" is equal" +
+                        " to sequence \"" + unique.getId() + "\". Sequence removed.");
+            else
+                newSeqs.add(seq);
+        }
+
+        return new Pir(newSeqs);
+    }
+}
diff --git a/alter-lib/src/types/PirSequence.java b/alter-lib/src/types/PirSequence.java
new file mode 100755
index 0000000..ad28682
--- /dev/null
+++ b/alter-lib/src/types/PirSequence.java
@@ -0,0 +1,88 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Sequence in PIR format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PirSequence extends Sequence implements Describable, Typeable
+{
+    /**
+     * Sequence type. In PIR format, every sequence has an individual type
+     * but it must be equal in all of them.
+     */
+    private Type type;
+    /**
+     * Sequence description.
+     */
+    private String desc;
+
+    /**
+     * Class constructor.
+     * @param id Sequence identifier.
+     * @param type Sequence type.
+     * @param desc Sequence description.
+     * @param data Sequence data.
+     */
+    public PirSequence(String id, String type, String desc, String data)
+    {
+        super(id,data);
+
+        this.desc = desc;
+
+        if (type.equals("P1"))
+            this.type =  new ProteinComplete();
+        else if (type.equals("F1"))
+            this.type = new ProteinFragment();
+        else if (type.equals("DL"))
+            this.type = new DNALinear();
+        else if (type.equals("DC"))
+            this.type = new DNACircular();
+        else if (type.equals("RL"))
+            this.type = new RNALinear();
+        else if (type.equals("RC"))
+            this.type = new RNACircular();
+        else if (type.equals("N3"))
+            this.type = new RNAt();
+        else if (type.equals("N1"))
+            this.type = new RNAOther();
+        else
+            this.type = null;
+    }
+
+    /**
+     * Returns the sequence type.
+     * @return Sequence type.
+     */
+    public Type getType()
+    {
+        return type;
+    }
+
+    /**
+     * Returns the sequence description.
+     * @return Sequence description.
+     */
+    public String getDesc()
+    {
+        return desc;
+    }
+}
diff --git a/alter-lib/src/types/Protein.java b/alter-lib/src/types/Protein.java
new file mode 100755
index 0000000..0877151
--- /dev/null
+++ b/alter-lib/src/types/Protein.java
@@ -0,0 +1,26 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Protein type.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class Protein extends Type{}
diff --git a/alter-lib/src/types/ProteinComplete.java b/alter-lib/src/types/ProteinComplete.java
new file mode 100755
index 0000000..155e3ae
--- /dev/null
+++ b/alter-lib/src/types/ProteinComplete.java
@@ -0,0 +1,27 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Complete protein type.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class ProteinComplete extends Protein
+{}
diff --git a/alter-lib/src/types/ProteinFragment.java b/alter-lib/src/types/ProteinFragment.java
new file mode 100755
index 0000000..1469c93
--- /dev/null
+++ b/alter-lib/src/types/ProteinFragment.java
@@ -0,0 +1,27 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Fragment protein type.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class ProteinFragment extends Protein
+{}
diff --git a/alter-lib/src/types/RNA.java b/alter-lib/src/types/RNA.java
new file mode 100755
index 0000000..c65a34a
--- /dev/null
+++ b/alter-lib/src/types/RNA.java
@@ -0,0 +1,27 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * RNA tye.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class RNA extends Nucleotide
+{}
diff --git a/alter-lib/src/types/RNACircular.java b/alter-lib/src/types/RNACircular.java
new file mode 100755
index 0000000..eac4d46
--- /dev/null
+++ b/alter-lib/src/types/RNACircular.java
@@ -0,0 +1,26 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Circular ARN type
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class RNACircular extends RNA{}
diff --git a/alter-lib/src/types/RNALinear.java b/alter-lib/src/types/RNALinear.java
new file mode 100755
index 0000000..56e9e35
--- /dev/null
+++ b/alter-lib/src/types/RNALinear.java
@@ -0,0 +1,26 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Linear RNA type
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class RNALinear extends RNA{}
diff --git a/alter-lib/src/types/RNAOther.java b/alter-lib/src/types/RNAOther.java
new file mode 100755
index 0000000..33ce678
--- /dev/null
+++ b/alter-lib/src/types/RNAOther.java
@@ -0,0 +1,26 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Other functional RNA type.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class RNAOther extends RNA{}
diff --git a/alter-lib/src/types/RNAt.java b/alter-lib/src/types/RNAt.java
new file mode 100755
index 0000000..db6275c
--- /dev/null
+++ b/alter-lib/src/types/RNAt.java
@@ -0,0 +1,26 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * tRNA type
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class RNAt extends RNA{}
diff --git a/alter-lib/src/types/Sequence.java b/alter-lib/src/types/Sequence.java
new file mode 100755
index 0000000..be024ea
--- /dev/null
+++ b/alter-lib/src/types/Sequence.java
@@ -0,0 +1,85 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Sequence in a MSA.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public abstract class Sequence
+{
+    /**
+     * Sequence identifier.
+     */
+    private String id;
+    /**
+     * Sequence data.
+     */
+    private StringBuffer data;
+
+    /**
+     * Class constructor.
+     * @param id Sequence identifier.
+     * @param data Sequence data.
+     */
+    public Sequence(String id, String data)
+    {
+        this.id = id;
+        this.data = new StringBuffer(2000);
+        this.data.append(data);
+    }
+
+    /**
+     * Returns the sequence identifier.
+     * @return Sequence identifier.
+     */
+    public String getId()
+    {
+        return id;
+    }
+
+    /**
+     * Returns the sequence data.
+     * @return Sequence data.
+     */
+    public String getData()
+    {
+        return data.toString();
+    }
+
+    /**
+     * Concats given data to the current data.
+     * @param data Data to concat.
+     */
+    public void concat(String data)
+    {
+        this.data.append(data);
+    }
+
+    /**
+     * Replaces the character in the given position for the given character.
+     * @param index Index of the character to be replaced.
+     * @param character Character to be inserted.
+     */
+    public void replaceChar(int index, char character)
+    {
+        this.data.setCharAt(index, character);
+    }
+}
diff --git a/alter-lib/src/types/Taxable.java b/alter-lib/src/types/Taxable.java
new file mode 100755
index 0000000..b7c7340
--- /dev/null
+++ b/alter-lib/src/types/Taxable.java
@@ -0,0 +1,34 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Defines method getTaxa() that all MSA classes containing the number of
+ * sequences must implement.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public interface Taxable
+{
+    /**
+     * Returns the number of sequences in the MSA.
+     * @return Number of sequences in the MSA.
+     */
+    public int getTaxa();
+}
diff --git a/alter-lib/src/types/Type.java b/alter-lib/src/types/Type.java
new file mode 100755
index 0000000..f984b43
--- /dev/null
+++ b/alter-lib/src/types/Type.java
@@ -0,0 +1,27 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Abstract class that acts as the root of the class hierarchy to define the MSA type.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public abstract class Type
+{}
diff --git a/alter-lib/src/types/Typeable.java b/alter-lib/src/types/Typeable.java
new file mode 100755
index 0000000..1e82ba5
--- /dev/null
+++ b/alter-lib/src/types/Typeable.java
@@ -0,0 +1,33 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Defines method getType() that all MSA or sequence classes containing the type
+ * must implement.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public interface Typeable
+{
+    /**
+     * Returns the MSA type.
+     * @return MSA type.
+     */
+    public Type getType();
+}
diff --git a/alter-lib/src/types/Weightable.java b/alter-lib/src/types/Weightable.java
new file mode 100755
index 0000000..9a27447
--- /dev/null
+++ b/alter-lib/src/types/Weightable.java
@@ -0,0 +1,33 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package types;
+
+/**
+ * Defines method getWeight() that all MSA or sequence classes containing a weight
+ * must implement.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public interface Weightable
+{
+    /**
+     * Returns the sequence or MSA weight.
+     * @return Sequence weight.
+     */
+    public float getWeight();
+}
diff --git a/alter-lib/src/types/package.html b/alter-lib/src/types/package.html
new file mode 100755
index 0000000..009ac5b
--- /dev/null
+++ b/alter-lib/src/types/package.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    Contains the classes needed to instantiate MSA objects.
+    @author Daniel Gomez Blanco
+    @version 1.1
+  </body>
+</html>
diff --git a/alter-lib/src/writer/AlnJModelTestWriter.java b/alter-lib/src/writer/AlnJModelTestWriter.java
new file mode 100755
index 0000000..4161e1d
--- /dev/null
+++ b/alter-lib/src/writer/AlnJModelTestWriter.java
@@ -0,0 +1,69 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class AlnWriter to adapt the output to jModelTest.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+public class AlnJModelTestWriter extends AlnWriter
+{
+    /**
+     * Class constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param resNumbers Output residue numbers.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public AlnJModelTestWriter(String os, boolean lowerCase, boolean resNumbers, boolean match, String logger)
+    {
+        super(os, lowerCase, resNumbers, match, logger);
+    }
+
+    /**
+     * Writes a MSA in ALN format, adapted for jModelTest. It checks
+     * that the MSA is not a protein MSA and that it contains 4 or more sequences.
+     * It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return String with the MSA in ALN format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        if (msa.getSeqs().size() < 4)
+            logger.log(Level.WARNING, "MSA contains less than 4 sequences. " +
+                    "It will not be processed by jModelTest.");
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+            type = WriterUtils.inferType(msa);
+        if (type instanceof Protein)
+            logger.log(Level.WARNING, "MSA is an amino acids MSA. " +
+                    "It will not be processed by jModelTest (only DNA is processed).");
+        return super.write(msa);
+    }
+}
diff --git a/alter-lib/src/writer/AlnWriter.java b/alter-lib/src/writer/AlnWriter.java
new file mode 100755
index 0000000..ab4fc9f
--- /dev/null
+++ b/alter-lib/src/writer/AlnWriter.java
@@ -0,0 +1,333 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import types.MSA;
+import types.Sequence;
+
+/** Implements interface Writer for the ALN format.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+public class AlnWriter implements Writer
+{
+    /**
+     * New line characters according to the given output OS.
+     */
+    String nl;
+    /**
+     * Lowercase output.
+     */
+    boolean lowerCase;
+    /**
+     * Output residue numbers.
+     */
+    boolean resNumbers;
+    /**
+     * Output match characters.
+     */
+    boolean match;
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+    /**
+     * Class constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param resNumbers Output residue numbers.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public AlnWriter(String os, boolean lowerCase, boolean resNumbers, boolean match, String logger)
+    {
+        if (os.equals("macos"))
+            nl = "\r";
+        else if (os.equals("linux"))
+            nl = "\n";
+        else
+            nl = "\r\n";
+        this.lowerCase = lowerCase;
+        this.resNumbers = resNumbers;
+        this.match = match;
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Writes a MSA in ALN format.
+     * @param msa Input MSA.
+     * @return MSA in ALN format.
+     */
+    public String write(MSA msa)
+    {
+        //Output
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+
+        //Copy sequences and calculate longest ID in order to align
+        String[] data = new String[msa.getSeqs().size()];
+        LinkedHashSet<String> id = new LinkedHashSet<String>(msa.getSeqs().size());
+        int[] residues = new int[msa.getSeqs().size()];
+        int longestId = 0;
+        for (int i = 0; i < msa.getSeqs().size(); i++)
+        {
+            //Copy data
+            Sequence seq = (Sequence) msa.getSeqs().elementAt(i);
+            data[i] = getData(seq, (Sequence) msa.getSeqs().firstElement());
+            String uid = getId(seq, id);
+            id.add(uid);
+            //Update longest ID
+            if (uid.length() > longestId)
+                longestId = uid.length();
+            residues[i] = 0;
+        }
+
+        //Write header
+        outb.append(writeHeader());
+
+        //Write sequences
+        while (!data[0].isEmpty())
+        {
+            String[] forConsensus = new String[data.length];
+
+            int i = 0;
+            for (String uid:id)
+            {
+                outb.append(writeLine(uid, longestId, data, forConsensus, residues, i));
+                i++;
+            }
+            //Write consensus line
+            outb.append(consensusLine(forConsensus, longestId));
+            outb.append(nl);
+        }
+        logger.log(Level.INFO, "MSA successfully converted to ALN format!");
+        return outb.toString();
+    }
+
+    /**
+     * Returns the sequence identifier. In case the current identifier is
+     * repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+        if (id.contains(" ") || id.contains("\t"))
+        {
+            logger.log(Level.WARNING, "ID for sequence \"" + id + "\" contains blanks. Blanks replaced by \"_\".");
+            id = id.replaceAll("[\t ]", "_");
+        }
+
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+
+    /**
+     * Returns the sequence data, using lowercase or match characters if
+     * necessary.
+     * @param seq Sequence containing the data.
+     * @param first First sequence in the MSA.
+     * @return Sequence data.
+     */
+    protected String getData(Sequence seq, Sequence first)
+    {
+        String data;
+        if (match)
+            data = WriterUtils.writeMatch(seq, first);
+        else
+            data = seq.getData();
+        if (lowerCase)
+            return data.toLowerCase();
+        else
+            return data;
+    }
+
+    /**
+     * Write the ALN header.
+     * @return ALN header.
+     */
+    protected String writeHeader()
+    {
+        return "CLUSTAL W (1.8) multiple sequence alignment (ALTER 1.3.3)" + nl + nl + nl;
+    }
+
+    /**
+     * Writes a line corresponding to a sequence of the MSA.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length (needed to align).
+     * @param data Sequences data.
+     * @param forConsensus Data to calculate consensus line.
+     * @param Residues written so far for every sequence.
+     * @param index Index of the current sequence in the array (needed to
+     * update data).
+     * @return Line in ALN format.
+     */
+    protected String writeLine(String id, int longestId, String data[],
+                            String forConsensus[], int residues[], int index)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(), longestId)
+                        + WriterUtils.align(longestId, 10) + "      ");
+
+        //Write a line if possible
+        if (data[index].length() > 60)
+        {
+            forConsensus[index] = data[index].substring(0, 60);
+            outb.append(forConsensus[index]);
+            if (resNumbers)
+            {
+                int res = countResidues(forConsensus[index]);
+                if (res != 0)
+                {
+                    residues[index] += res;
+                    outb.append(" " + residues[index]);
+                }
+            }
+            data[index] = data[index].substring(60);
+        }
+        else
+        {
+            forConsensus[index] = data[index];
+            outb.append(forConsensus[index]);
+            if (resNumbers)
+            {
+                int res = countResidues(forConsensus[index]);
+                if (res != 0)
+                {
+                    residues[index] += res;
+                    outb.append(" " + residues[index]);
+                }
+            }
+            data[index] = "";
+        }
+        outb.append(nl);
+        return outb.toString();
+    }
+
+    /**
+     * Counts residues (characters that are not "?" or "-") in the input string.
+     * @param s Input string.
+     * @return Number of residues in the string.
+     */
+    protected int countResidues(String s)
+    {
+        int toret = 0;
+        for(int i=0;i<s.length();i++)
+            if ( s.charAt(i) != '-' && s.charAt(i) != '?')
+                toret++;
+        return toret;
+    }
+
+     /**
+     * Calculates the consesus line of a block of sequences.
+     * @param data Block of sequences.
+     * @return Consensus line for the given sequences.
+     */
+    protected String consensusLine(String[] data, int longestId)
+    {
+        //String to return
+        String out = "";
+
+        out += WriterUtils.align(0, longestId) + WriterUtils.align(longestId, 10) + "      ";
+
+        //For each character
+        for (int i = 0; i < data[0].length(); i++)
+        {
+            boolean fully = true;
+            boolean nores = false;
+            char residue = data[0].charAt(i);
+            //Build string with the characters in a column
+            String col = "";
+            for (int j = 0; j < data.length; j++)
+            {
+                char c = data[j].charAt(i);
+                if (c == '.')
+                    c = residue;
+                //If there is no residue break the loop
+                if (c == '-' || c == '?')
+                {
+                    nores = true;
+                    break;
+                }
+                //If the current residue is different from the first one flag it
+                if (c != residue)
+                    fully = false;
+                col += c;
+            }
+
+            //If there is no residue
+            if (nores)
+                out += ' ';
+            //If the residue is fully preserved
+            else if (fully)
+                out += '*';
+            //Check strong groups
+            else if (col.replaceAll("[STA]", "").isEmpty())
+                out += ':';
+            else if (col.replaceAll("[NEQK]", "").isEmpty())
+                out += ':';
+            else if (col.replaceAll("[NHQK]", "").isEmpty())
+                out += ':';
+            else if (col.replaceAll("[NDEQ]", "").isEmpty())
+                out += ':';
+            else if (col.replaceAll("[QHRK]", "").isEmpty())
+                out += ':';
+            else if (col.replaceAll("[MILV]", "").isEmpty())
+                out += ':';
+            else if (col.replaceAll("[MILF]", "").isEmpty())
+                out += ':';
+            else if (col.replaceAll("[HY]", "").isEmpty())
+                out += ':';
+            else if (col.replaceAll("[FYW]", "").isEmpty())
+                out += ':';
+            //Check weak groups
+            else if (col.replaceAll("[CSA]", "").isEmpty())
+                out += '.';
+            else if (col.replaceAll("[ATV]", "").isEmpty())
+                out += '.';
+            else if (col.replaceAll("[SAG]", "").isEmpty())
+                out += '.';
+            else if (col.replaceAll("[STNK]", "").isEmpty())
+                out += '.';
+            else if (col.replaceAll("[STPA]", "").isEmpty())
+                out += '.';
+            else if (col.replaceAll("[SGND]", "").isEmpty())
+                out += '.';
+            else if (col.replaceAll("[SNDEQK]", "").isEmpty())
+                out += '.';
+            else if (col.replaceAll("[NDEQHK]", "").isEmpty())
+                out += '.';
+            else if (col.replaceAll("[NEQHRK]", "").isEmpty())
+                out += '.';
+            else if (col.replaceAll("[FVLIM]", "").isEmpty())
+                out += '.';
+            else if (col.replaceAll("[HFY]", "").isEmpty())
+                out += '.';
+            //If none is preserved
+            else
+                out += ' ';
+        }
+        out += nl;
+
+        return out;
+    }
+}
diff --git a/alter-lib/src/writer/FastaDnaSPWriter.java b/alter-lib/src/writer/FastaDnaSPWriter.java
new file mode 100644
index 0000000..a4eb3fc
--- /dev/null
+++ b/alter-lib/src/writer/FastaDnaSPWriter.java
@@ -0,0 +1,69 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class FastaWriter to adapt the output to dnaSP.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class FastaDnaSPWriter extends FastaWriter
+{
+    /**
+     * Class constructor. Calls the superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public FastaDnaSPWriter(String os, boolean lowerCase, boolean match, String logger)
+    {
+        super(os,lowerCase,match,logger);
+    }
+
+    /**
+     * Writes a MSA in FASTA format, adapted to dnaSP. It checks that the MSA is
+     * not a protein MSA. It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return MSA in FASTA format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is an amino acids MSA. " +
+                    "It will not be processed by dnaSP (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+}
diff --git a/alter-lib/src/writer/FastaJModelTestWriter.java b/alter-lib/src/writer/FastaJModelTestWriter.java
new file mode 100755
index 0000000..9ad0e0d
--- /dev/null
+++ b/alter-lib/src/writer/FastaJModelTestWriter.java
@@ -0,0 +1,73 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class FastaWriter to adapt the output to jModelTest.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class FastaJModelTestWriter extends FastaWriter
+{
+    /**
+     * Class constructor. Calls the superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public FastaJModelTestWriter(String os, boolean lowerCase, boolean match, String logger)
+    {
+        super(os,lowerCase,match,logger);
+    }
+
+    /**
+     * Writes a MSA in FASTA format, adapted for jModelTest. It checks
+     * that the MSA is not a protein MSA and that it contains 4 or more sequences.
+     * It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return String with the MSA in FASTA format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        if (msa.getSeqs().size() < 4)
+            logger.log(Level.WARNING, "MSA contains less than 4 sequences. " +
+                    "It will not be processed by jModelTest.");
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is an amino acids MSA. " +
+                    "It will not be processed by jModelTest (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+}
diff --git a/alter-lib/src/writer/FastaWriter.java b/alter-lib/src/writer/FastaWriter.java
new file mode 100755
index 0000000..dbe6bd4
--- /dev/null
+++ b/alter-lib/src/writer/FastaWriter.java
@@ -0,0 +1,163 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import types.Describable;
+import types.MSA;
+import types.Sequence;
+
+/**
+ * Implements interface Writer for the FASTA format.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class FastaWriter implements Writer
+{
+    /**
+     * New line characters according to the given output OS.
+     */
+    String nl;
+    /**
+     * Lowercase output.
+     */
+    boolean lowerCase;
+    /**
+     * Output match characters.
+     */
+    boolean match;
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+    /**
+     * Class constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public FastaWriter(String os, boolean lowerCase, boolean match, String logger)
+    {
+        if (os.equals("macos"))
+            nl = "\r";
+        else if (os.equals("linux"))
+            nl = "\n";
+        else
+            nl = "\r\n";
+        this.lowerCase = lowerCase;
+        this.match = match;
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Writes a MSA in FASTA format.
+     * @param msa Input MSA.
+     * @return MSA in FASTA format.
+     */
+    public String write(MSA msa)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+
+        LinkedHashSet<String> ids = new LinkedHashSet<String>(msa.getSeqs().size());
+        //Write sequences
+        for(int i=0;i<msa.getSeqs().size();i++)
+        {
+            Sequence seq = (Sequence)msa.getSeqs().elementAt(i);
+            String id = getId(seq, ids);
+            ids.add(id);
+            String data = getData(seq, (Sequence) msa.getSeqs().firstElement());
+            outb.append(writeSequence(id, data));
+        }
+
+        logger.log(Level.INFO, "MSA successfully converted to FASTA format!");
+        return outb.toString();
+    }
+
+    /**
+     * Returns the sequence identifier. In case the current identifier is
+     * repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+        if (seq instanceof Describable)
+            id += " " + ((Describable) seq).getDesc();
+
+        return WriterUtils.getUniqueId(ids,id,logger.getName());
+    }
+
+    /**
+     * Returns the sequence data, using lowercase or match characters if
+     * necessary.
+     * @param seq Sequence containing the data.
+     * @param first First sequence in the MSA.
+     * @return Sequence data.
+     */
+    protected String getData(Sequence seq, Sequence first)
+    {
+        String data;
+        if (match)
+            data = WriterUtils.writeMatch(seq, first);
+        else
+            data = seq.getData();
+        if (lowerCase)
+            return data.toLowerCase();
+        else
+            return data;
+    }
+
+    /**
+     * Writes a complete sequence.
+     * @param id Sequence identifier.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    protected String writeSequence(String id, String data)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        //Escribir ID y descripcion
+        outb.append(">" + id);
+        outb.append(nl);
+
+        //Mientras queden caracteres por escribir
+        while(!data.isEmpty())
+        {
+            //Si hay caracteres para hacer una línea
+            if (data.length() > 60)
+            {            
+                outb.append(data.substring(0, 60));
+                data = data.substring(60);
+            }
+            else
+            {           
+                outb.append(data);
+                data = "";
+            }
+            outb.append(nl);
+        }
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/GdeSeAlWriter.java b/alter-lib/src/writer/GdeSeAlWriter.java
new file mode 100644
index 0000000..8998f7a
--- /dev/null
+++ b/alter-lib/src/writer/GdeSeAlWriter.java
@@ -0,0 +1,52 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import types.MSA;
+
+/**
+ * Extends class GdeWriter to adapt the output to SeAl.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class GdeSeAlWriter extends GdeWriter
+{
+    /**
+     * Class constructor. Calls the superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public GdeSeAlWriter(String os, boolean lowerCase, boolean match, String logger)
+    {
+        super(os,lowerCase,match,logger);
+    }
+
+    /**
+     * Returns the character that must precede the sequence identifier.
+     * @param msa Input MSA.
+     * @return '#'.
+     */
+    @Override
+    protected char getStart(MSA msa)
+    {
+        return '#';
+    }
+}
diff --git a/alter-lib/src/writer/GdeWriter.java b/alter-lib/src/writer/GdeWriter.java
new file mode 100755
index 0000000..748eb7a
--- /dev/null
+++ b/alter-lib/src/writer/GdeWriter.java
@@ -0,0 +1,193 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import types.Describable;
+import types.MSA;
+import types.Nucleotide;
+import types.Sequence;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Implements interface Writer for the GDE format.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class GdeWriter implements Writer
+{
+    /**
+     * New line characters according to the given output OS.
+     */
+    String nl;
+    /**
+     * Lowercase output.
+     */
+    boolean lowerCase;
+    /**
+     * Output match characters.
+     */
+    boolean match;
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+    /**
+     * Class constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public GdeWriter(String os, boolean lowerCase, boolean match, String logger)
+    {
+        if (os.equals("macos"))
+            nl = "\r";
+        else if (os.equals("linux"))
+            nl = "\n";
+        else
+            nl = "\r\n";
+        this.lowerCase = lowerCase;
+        this.match = match;
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Writes a MSA in GDE format.
+     * @param msa Input MSA.
+     * @return MSA in GDE format.
+     */
+    public String write(MSA msa)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+
+        //Start character
+        char start = getStart(msa);
+        LinkedHashSet<String> ids = new LinkedHashSet<String>(msa.getSeqs().size());
+        //Write sequences
+        for(int i=0;i<msa.getSeqs().size();i++)
+        {
+            Sequence seq = (Sequence)msa.getSeqs().elementAt(i);
+            String id = getId(seq,ids);
+            ids.add(id);
+            String data = getData(seq, (Sequence)msa.getSeqs().firstElement());
+            outb.append(writeSequence(id, data, start));
+        }
+        logger.log(Level.INFO, "MSA successfully converted to GDE format!");
+        return outb.toString();
+    }
+
+    /**
+     * Returns the sequence identifier. In case the current identifier is
+     * repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+        if (seq instanceof Describable)
+            id += " " + ((Describable) seq).getDesc();
+
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+
+    /**
+     * Returns the sequence data, using lowercase or match characters if
+     * necessary.
+     * @param seq Sequence containing the data.
+     * @param first First sequence in the MSA.
+     * @return Sequence data.
+     */
+    protected String getData(Sequence seq, Sequence first)
+    {
+        String data;
+        if (match)
+            data = WriterUtils.writeMatch(seq, first);
+        else
+            data = seq.getData();
+        if (lowerCase)
+            return data.toLowerCase();
+        else
+            return data;
+    }
+
+    /**
+     * Returns the character that must precede the sequence identifier.
+     * @param msa Input MSA.
+     * @return '#' for nucleotides and '%' in othe case.
+     */
+    protected char getStart(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+            if (type instanceof Nucleotide)
+                logger.log(Level.INFO,"Nucleotide MSA type inferred.");
+            else
+                logger.log(Level.INFO, "Protein MSA type inferred.");
+        }
+
+        if (type instanceof Nucleotide)
+            return '#';
+        else
+            return '%';
+    }
+
+    /**
+     * Writes a complete sequence.
+     * @param id Sequence identifier.
+     * @param data Sequence data.
+     * @param start Start character.
+     * @return Formatted sequence.
+     */
+    protected String writeSequence(String id, String data, char start)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        //Write ID
+        outb.append(start + id + nl);
+
+        //While there are characters to be written
+        while(!data.isEmpty())
+        {
+            //If there are enough characters to make a line
+            if (data.length() > 60)
+            {
+                outb.append(data.substring(0,60));
+                data = data.substring(60);
+            }
+            else
+            {
+                outb.append(data);
+                data = "";
+            }
+            outb.append(nl);
+        }
+
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/MegaDnaSPWriter.java b/alter-lib/src/writer/MegaDnaSPWriter.java
new file mode 100644
index 0000000..bc79c3f
--- /dev/null
+++ b/alter-lib/src/writer/MegaDnaSPWriter.java
@@ -0,0 +1,69 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class MegaWriter to adapt the output to dnaSP.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class MegaDnaSPWriter extends MegaWriter
+{
+    /**
+     * Class constructor. Calls the superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public MegaDnaSPWriter(String os, boolean lowerCase, boolean match, String logger)
+    {
+        super(os,lowerCase,match,logger);
+    }
+
+    /**
+     * Writes a MSA in MEGA format, adapted to dnaSP. It checks that the MSA is
+     * not a protein MSA. It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return MSA in MEGA format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is an amino acids MSA. " +
+                    "It will not be processed by dnaSP (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+}
diff --git a/alter-lib/src/writer/MegaWriter.java b/alter-lib/src/writer/MegaWriter.java
new file mode 100755
index 0000000..3f27be1
--- /dev/null
+++ b/alter-lib/src/writer/MegaWriter.java
@@ -0,0 +1,196 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import types.MSA;
+import types.Sequence;
+
+/**
+ * Implements interface Writer for the MEGA format.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class MegaWriter implements Writer
+{
+    /**
+     * New line characters according to the given output OS.
+     */
+    String nl;
+    /**
+     * Lowercase output.
+     */
+    boolean lowerCase;
+    /**
+     * Output match characters.
+     */
+    boolean match;
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+    /**
+     * Class constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public MegaWriter(String os, boolean lowerCase, boolean match, String logger)
+    {
+        if (os.equals("macos"))
+            nl = "\r";
+        else if (os.equals("linux"))
+            nl = "\n";
+        else
+            nl = "\r\n";
+        this.lowerCase = lowerCase;
+        this.match = match;
+        this.logger = Logger.getLogger(logger);
+        this.logger.setLevel(Level.ALL);
+    }
+
+    /**
+     * Writes a MSA in MEGA format.
+     * @param msa Input MSA.
+     * @return MSA in MEGA format.
+     */
+    public String write(MSA msa)
+    {
+        //Output
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+
+        outb.append(writeHeader());
+
+        //Copy sequences
+        String[] data = new String[msa.getSeqs().size()];
+        LinkedHashSet<String> id = new LinkedHashSet<String>(msa.getSeqs().size());
+        int longestId = 0;
+        for (int i = 0; i < msa.getSeqs().size(); i++)
+        {
+            Sequence seq = (Sequence) msa.getSeqs().elementAt(i);
+            //Copy data
+            data[i] = getData(seq, (Sequence) msa.getSeqs().firstElement());
+            String uid = getId(seq,id);
+            id.add(uid);
+            //Update longest ID
+            if(uid.length() > longestId)
+                longestId = uid.length();
+        }
+        //Write sequences
+        while(!data[0].isEmpty())
+        {
+            int i=0;
+            for (String uid:id)
+            {
+                outb.append(writeLine(uid, longestId, data, i));
+                i++;
+            }
+            outb.append(nl);
+        }
+
+        logger.log(Level.INFO, "MSA successfully converted to MEGA format!");
+        return outb.toString();
+    }
+
+    /**
+     * Returns the sequence identifier. In case the current identifier is
+     * repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+        
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+
+    /**
+     * Returns the sequence data, using lowercase or match characters if
+     * necessary.
+     * @param seq Sequence containing the data.
+     * @param first First sequence in the MSA.
+     * @return Sequence data.
+     */
+    protected String getData(Sequence seq, Sequence first)
+    {
+        String data;
+        if (match)
+            data = WriterUtils.writeMatch(seq, first);
+        else
+            data = seq.getData();
+        if (lowerCase)
+            return data.toLowerCase();
+        else
+            return data;
+    }
+
+    /**
+     * Writes the MEGA format header.
+     * @return MEGA format header.
+     */
+    protected String writeHeader()
+    {
+        return "#mega" + nl + "TITLE: MSA converted with ALTER 1.3.3" + nl + nl;
+    }
+
+    /**
+     * Writes a line corresponding to a sequence of the MSA.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length (needed to align).
+     * @param data Sequences data.
+     * @param index Index of the current sequence in the array (needed to
+     * update data).
+     * @return Line in MEGA format.
+     */
+    protected String writeLine(String id, int longestId, String[] data, int index)
+    {
+        //Write ID
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append("#" + id + WriterUtils.align(id.length(), longestId) +
+                WriterUtils.align(longestId, 10) + "  ");
+
+        //Write a line of 10 characters blocks
+        for (int j = 0; j < 5; j++)
+        {
+            //If there are enough characters to make a 10 characters block
+            if (data[index].length() > 10)
+            {
+                outb.append(data[index].substring(0, 10) + " ");
+                data[index] = data[index].substring(10);
+            }
+            else
+            {
+                outb.append(data[index]);
+                data[index] = "";
+            }
+            //If there are no more data exit the loop
+            if (data[index].isEmpty())
+                break;
+        }
+        outb.append(nl);
+        return outb.toString();
+    }
+
+}
diff --git a/alter-lib/src/writer/MsfJModelTestWriter.java b/alter-lib/src/writer/MsfJModelTestWriter.java
new file mode 100755
index 0000000..d5335f5
--- /dev/null
+++ b/alter-lib/src/writer/MsfJModelTestWriter.java
@@ -0,0 +1,72 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class MsfWriter to adapt the output to jModelTest.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class MsfJModelTestWriter extends MsfWriter
+{
+    /**
+     * Class constructor. Calls the superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param logger Logger name.
+     */
+    public MsfJModelTestWriter(String os, boolean lowerCase, String logger)
+    {
+        super(os,lowerCase,logger);
+    }
+
+    /**
+     * Writes a MSA in MSF format, adapted for jModelTest. It checks
+     * that the MSA is not a protein MSA and that it contains 4 or more sequences.
+     * It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return String with the MSA in MSF format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        if (msa.getSeqs().size() < 4)
+            logger.log(Level.WARNING, "MSA contains less than 4 sequences. " +
+                    "It will not be processed by jModelTest.");
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is an amino acids MSA. " +
+                    "It will not be processed by jModelTest (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+}
diff --git a/alter-lib/src/writer/MsfMegaWriter.java b/alter-lib/src/writer/MsfMegaWriter.java
new file mode 100644
index 0000000..f51d574
--- /dev/null
+++ b/alter-lib/src/writer/MsfMegaWriter.java
@@ -0,0 +1,55 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import types.Sequence;
+
+/**
+ * Extends class MsfWriter to adapt to the output to MEGA.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class MsfMegaWriter extends MsfWriter
+{
+    /**
+     * Class constructor. Calls the superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param logger Logger name.
+     */
+    public MsfMegaWriter(String os, boolean lowerCase, String logger)
+    {
+        super(os,lowerCase,logger);
+    }
+
+    /**
+     * Returns the sequence data, using lowercase characters if necessary.
+     * @param seq Sequence containing the data.
+     * @param first First sequence in the MSA.
+     * @return Sequence data.
+     */
+    @Override
+    protected String getData(Sequence seq)
+    {
+        if (lowerCase)
+            return seq.getData().toLowerCase();
+        else
+            return seq.getData();
+    }
+}
diff --git a/alter-lib/src/writer/MsfSeaViewWriter.java b/alter-lib/src/writer/MsfSeaViewWriter.java
new file mode 100644
index 0000000..bafd26b
--- /dev/null
+++ b/alter-lib/src/writer/MsfSeaViewWriter.java
@@ -0,0 +1,62 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+/**
+ * Extends class MsfWriter to adapt to the output to SeaView.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class MsfSeaViewWriter extends MsfWriter
+{
+    /**
+     * Class constructor. Calls the superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param logger Logger name.
+     */
+    public MsfSeaViewWriter(String os, boolean lowerCase, String logger)
+    {
+        super(os,lowerCase,logger);
+    }
+
+    /**
+     * Writes information of a sequence, to be placed in the information block
+     * after the MSF header.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param length Sequence length.
+     * @param longestLength Longest length number length.
+     * @param check Sequence checksum.
+     * @param longestCheck Longest checksum length.
+     * @param weight Sequence weight.
+     * @param longestWeight Longest weight length.
+     * @return Sequence information.
+     */
+    @Override
+    protected String writeInfo(String id, int longestId, int length, int longestLength,
+                                int check, int longestCheck, float weight, int longestWeight)
+    {
+        return " Name: " + id + WriterUtils.align(id.length(),longestId)
+            + "  Len:  " + WriterUtils.align(String.valueOf(length).length(),longestLength) + length
+            + "  Check:  " + WriterUtils.align((String.valueOf(check)).length(),longestCheck) + check
+            + "  Weight:  " + WriterUtils.align(String.valueOf(weight).length(),longestWeight) + weight
+            + nl;
+    }
+}
diff --git a/alter-lib/src/writer/MsfWriter.java b/alter-lib/src/writer/MsfWriter.java
new file mode 100755
index 0000000..f526fd2
--- /dev/null
+++ b/alter-lib/src/writer/MsfWriter.java
@@ -0,0 +1,353 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import types.Lengthable;
+import types.MSA;
+import types.Nucleotide;
+import types.Protein;
+import types.Sequence;
+import types.Type;
+import types.Typeable;
+import types.Weightable;
+
+/**
+ * Implements interface Writer for the MSF format.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class MsfWriter implements Writer
+{
+    /**
+     * New line characters according to the given output OS.
+     */
+    String nl;
+    /**
+     * Lowercase output.
+     */
+    boolean lowerCase;
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+    /**
+     * Class constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param logger Logger name.
+     */
+    public MsfWriter(String os, boolean lowerCase, String logger)
+    {
+        if (os.equals("macos"))
+            nl = "\r";
+        else if (os.equals("linux"))
+            nl = "\n";
+        else
+            nl = "\r\n";
+        this.lowerCase = lowerCase;
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Writes a MSA in MSF format.
+     * @param msa Input MSA.
+     * @return MSA in MSF format.
+     */
+    public String write(MSA msa)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+
+        //Copy sequence data and find longest strings
+        String[] data = new String[msa.getSeqs().size()];
+        LinkedHashSet<String> id = new LinkedHashSet<String>(msa.getSeqs().size());
+        int[] length = new int[msa.getSeqs().size()];
+        int[] check = new int[msa.getSeqs().size()];
+        float[] weight = new float[msa.getSeqs().size()];
+        int longestId = 0;
+        int longestLength = 0;
+        int longestCheck = 0;
+        int longestWeight = 0;
+        for (int i = 0; i < msa.getSeqs().size(); i++)
+        {
+            Sequence seq = (Sequence)msa.getSeqs().elementAt(i);
+            data[i] = getData(seq);
+            String uid = getId(seq,id);
+            id.add(uid);
+            length[i] = getLength(seq);
+            check[i] = getChecksum(data[i]);
+            weight[i] = getWeight(seq);
+
+            if (uid.length() > longestId)
+                longestId = uid.length();
+            if (String.valueOf(length[i]).length() > longestLength)
+                longestLength = String.valueOf(length[i]).length();
+            if ((String.valueOf(check[i])).length() > longestCheck)
+                longestCheck = (String.valueOf(check[i])).length();
+            if (String.valueOf(weight[i]).length() > longestWeight)
+                longestWeight = String.valueOf(weight[i]).length();
+        }
+
+        //Write header
+        int msaLength = getLength(msa);
+        int msaCheck = getChecksum(check);
+        char msaType = getType(msa);
+        outb.append(writeHeader(msaLength, msaType, msaCheck));
+
+        //Write sequences information
+        int i=0;
+        for (String uid:id)
+        {
+            outb.append(writeInfo(uid, longestId, length[i], longestLength,
+                    check[i], longestCheck, weight[i], longestWeight));
+            i++;
+        }
+
+        outb.append(nl + "//" + nl + nl + nl + nl);
+
+        while (!data[0].isEmpty())
+        {
+            i = 0;
+            for (String uid:id)
+            {
+                outb.append(writeLine(uid, longestId, data, i));
+                i++;
+            }
+                
+            outb.append(nl);
+        }
+        logger.log(Level.INFO, "MSA successfully converted to MSF format!");
+        return outb.toString();
+    }
+
+    /**
+     * Returns the sequence identifier. In case the current identifier is
+     * repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+        //If ID contains spaces
+        if (id.length() > 10 && (id.contains(" ") || id.contains("\t")))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" is longer than 10 characters and contains blanks. Blanks replaced by \"_\".");
+            id = id.replaceAll("[\t ]","_");
+        }
+        
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+
+    /**
+     * Returns the sequence data, using lowercase characters if necessary.
+     * @param seq Sequence containing the data.
+     * @param first First sequence in the MSA.
+     * @return Sequence data.
+     */
+    protected String getData(Sequence seq)
+    {
+        if (lowerCase)
+            return seq.getData().replace('-','.').toLowerCase();
+        else
+            return seq.getData().replace('-', '.');
+    }
+
+    /**
+     * Returns the length of the sequence.
+     * @param seq Sequence to get the length of.
+     * @return Sequence length.
+     */
+    protected int getLength(Sequence seq)
+    {
+        if (seq instanceof Lengthable)
+            return ((Lengthable) seq).getLength();
+        else
+            return seq.getData().length();
+    }
+
+    /**
+     * Returns the length of the sequences in the MSA.
+     * @param msa MSA to get the length of.
+     * @return Length of the sequences in the MSA.
+     */
+    protected int getLength(MSA msa)
+    {
+        if (msa instanceof Lengthable)
+            return ((Lengthable) msa).getLength();
+        else
+            return ((Sequence) msa.getSeqs().firstElement()).getData().length();
+    }
+
+    /**
+     * Returns the sequence weight.
+     * @param seq Sequence to get the weight of.
+     * @return Sequence weight.
+     */
+    protected float getWeight(Sequence seq)
+    {
+        if (seq instanceof Weightable)
+            return ((Weightable) seq).getWeight();
+        else
+            return 1.0f;
+    }
+
+    /**
+     * Calculates the MSA checksum using the checksums of the sequences in the MSA.
+     * @param check Checksums of the sequences in the MSA.
+     * @return MSA checksum.
+     */
+    protected int getChecksum (int[] check)
+    {
+        int checksum = 0;
+        for (int i=0;i<check.length;i++)
+        {
+            checksum += check[i];
+            checksum %= 10000;
+        }
+        return checksum;
+    }
+
+    /**
+     * Calculates the checksum of a sequence.
+     * @param s Sequence to calculate the checksum of.
+     * @return Sequence checksum.
+     */
+    protected int getChecksum (String s)
+    {
+        int index = 0;
+        int checksum = 0;
+        for (int i=0;i<s.length();i++)
+        {
+            char c = s.charAt(i);
+            index++;
+            checksum += index * (int)c;
+            if (index == 57)
+                index = 0;
+
+        }
+        return checksum % 10000;
+    }
+
+    /**
+     * Returns a string with the MSA type.
+     * @param msa MSA to get the type of.
+     * @return MSA type.
+     */
+    protected char getType(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+            if (type instanceof Nucleotide)
+                logger.log(Level.INFO,"Nucleotide MSA type inferred.");
+            else
+                logger.log(Level.INFO, "Protein MSA type inferred.");
+        }
+
+        if (type instanceof Protein)
+            return 'P';
+        else if (type instanceof Nucleotide)
+            return 'N';
+        else
+            return 'X';
+    }
+
+    /**
+     * Writes the MSF header.
+     * @param checksum MSA checksum.
+     * @param length Sequences length.
+     * @param type MSA type.
+     * @return MSF header.
+     */
+    protected String writeHeader(int length, char type, int checksum)
+    {
+        String out = "";
+        out += "PileUp" + nl + nl + nl + nl;
+        out += "   MSF:  " + length + "  Type: " + type + "    Check:  "
+                + checksum + "   .. " + nl + nl;
+        return out;
+    }
+
+    /**
+     * Writes information of a sequence, to be placed in the information block
+     * after the MSF header.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param length Sequence length.
+     * @param longestLength Longest length number length.
+     * @param check Sequence checksum.
+     * @param longestCheck Longest checksum length.
+     * @param weight Sequence weight.
+     * @param longestWeight Longest weight length.
+     * @return Sequence information.
+     */
+    protected String writeInfo(String id, int longestId, int length, int longestLength,
+                                int check, int longestCheck, float weight, int longestWeight)
+    {
+        return " Name: " + id + " oo" + WriterUtils.align(id.length(),longestId)
+            + "  Len:  " + WriterUtils.align(String.valueOf(length).length(),longestLength) + length
+            + "  Check:  " + WriterUtils.align((String.valueOf(check)).length(),longestCheck) + check
+            + "  Weight:  " + WriterUtils.align(String.valueOf(weight).length(),longestWeight) + weight
+            + nl;
+    }
+
+    /**
+     * Writes a line corresponding to a sequence of the MSA.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length (needed to align).
+     * @param data Sequences data.
+     * @param index Index of the current sequence in the array (needed to
+     * update data).
+     * @return Line in MSF format.
+     */
+    protected String writeLine(String id, int longestId, String[] data, int index)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(),longestId));
+        outb.append(WriterUtils.align(longestId, 10) + "      ");
+
+        //Write a row
+        for (int j = 0; j < 6; j++)
+        {
+            //If there are enough characters to make a 10 characters block
+            if (data[index].length() > 10)
+            {
+                outb.append(data[index].substring(0, 10) + " ");
+                data[index] = data[index].substring(10);
+            }
+            else
+            {
+                outb.append(data[index]);
+                data[index] = "";
+                break;
+            }
+        }
+        outb.append(nl);
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/NexusDnaSPWriter.java b/alter-lib/src/writer/NexusDnaSPWriter.java
new file mode 100644
index 0000000..bb57bca
--- /dev/null
+++ b/alter-lib/src/writer/NexusDnaSPWriter.java
@@ -0,0 +1,70 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class NexusWriter to adapt the output to dnaSP.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class NexusDnaSPWriter extends NexusWriter
+{
+    /**
+     * Class constructor. Calls the constructor in the superclass.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public NexusDnaSPWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os, lowerCase, sequential, match, logger);
+    }
+
+    /**
+     * Writes a MSA in NEXUS format, adapted to dnaSP. It checks that the MSA is
+     * not a protein MSA. It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return MSA in NEXUS format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is an amino acids MSA. " +
+                    "It will not be processed by dnaSP (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+}
diff --git a/alter-lib/src/writer/NexusJModelTestWriter.java b/alter-lib/src/writer/NexusJModelTestWriter.java
new file mode 100755
index 0000000..1a65c5d
--- /dev/null
+++ b/alter-lib/src/writer/NexusJModelTestWriter.java
@@ -0,0 +1,75 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class NexusWriter to adapt the output to jModelTest.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class NexusJModelTestWriter extends NexusWriter
+{
+    /**
+     * Class constructor. Calls the constructor in the superclass.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public NexusJModelTestWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match,logger);
+    }
+
+    /**
+     * Writes a MSA in NEXUS format, adapted for jModelTest. It checks
+     * that the MSA is not a protein MSA and that it contains 4 or more sequences.
+     * It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return String with the MSA in NEXUS format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        if (msa.getSeqs().size() < 4)
+            logger.log(Level.WARNING, "MSA contains less than 4 sequences. " +
+                    "It will not be processed by jModelTest.");
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is an amino acids MSA. " +
+                    "It will not be processed by jModelTest (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+}
+
diff --git a/alter-lib/src/writer/NexusMesquiteWriter.java b/alter-lib/src/writer/NexusMesquiteWriter.java
new file mode 100644
index 0000000..f2a53fa
--- /dev/null
+++ b/alter-lib/src/writer/NexusMesquiteWriter.java
@@ -0,0 +1,62 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+/**
+ * Extends class NexusWriter to adapt the output to Mesquite.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class NexusMesquiteWriter extends NexusWriter
+{
+    /**
+     * Class constructor. Calls the constructor in the superclass.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public NexusMesquiteWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os, lowerCase, sequential, match, logger);
+    }
+
+    /**
+     * Writes the NEXUS header adapted to Mesquite.
+     * @param taxa Number of sequences.
+     * @param length Sequences length.
+     * @param type MSA type.
+     * @return NEXUS header.
+     */
+    @Override
+    protected String writeHeader(int taxa, int length, String type)
+    {
+        String out = "#NEXUS" + nl;
+        out += "BEGIN DATA;" + nl;
+        out += "dimensions ntax=" + taxa + " nchar=" + length + ";" + nl;
+        out += "format missing=?" + nl;
+        out += "symbols=\"ABCDEFGHIKLMNOPQRSTUVWXYZ\"" + nl;
+        if (!sequential)
+            out += "interleave ";
+        out += "datatype=" + type + " gap=-;" + nl + nl;
+        out += "matrix" + nl;
+        return out;
+    }
+}
diff --git a/alter-lib/src/writer/NexusMrBayesWriter.java b/alter-lib/src/writer/NexusMrBayesWriter.java
new file mode 100755
index 0000000..c2aaee8
--- /dev/null
+++ b/alter-lib/src/writer/NexusMrBayesWriter.java
@@ -0,0 +1,145 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import types.DNA;
+import types.MSA;
+import types.Nucleotide;
+import types.Protein;
+import types.RNA;
+import types.Sequence;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class NexusWriter to adapt the output to MrBayes.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class NexusMrBayesWriter extends NexusWriter
+{
+    /**
+     * Class constructor. Calls the constructor in the superclass.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public NexusMrBayesWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os, lowerCase, sequential, match, logger);
+    }
+
+    /**
+     * Returns the sequence identifier, considering MrBayes limitations. In case
+     * the current identifier is repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    @Override
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+         //Copy ID
+        String id = seq.getId();
+        //If it contains spaces
+        if (id.contains(" ") || id.contains("\t"))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" contains blanks. Blanks replaced by \"_\"");
+            id = id.replaceAll("[\t ]","_");
+        }
+        //If it contains characters used indicate comments
+        if (id.contains("[") || id.contains("]"))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" contains \"[\" or \"]\". Characters replaced by \"_\"");
+            id = id.replaceAll("\\[\\]","_");
+        }
+
+        if (id.replaceAll("[_.0-9a-zA-Z]", "").length() != 0)
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" contains invalid characters. Characters replaced by \"_\"");
+            id = id.replaceAll("[^_.0-9a-zA-Z]","_");
+        }
+
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+
+    /**
+     * Writes the NEXUS header adapted to MrBayes.
+     * @param taxa Number of sequences.
+     * @param length Sequences length.
+     * @param type MSA type.
+     * @return NEXUS header.
+     */
+    @Override
+    protected String writeHeader(int taxa, int length, String type)
+    {
+        String out = "#NEXUS" + nl;
+        out += "BEGIN DATA;" + nl;
+        out += "dimensions ntax=" + taxa + " nchar=" + length + ";" + nl;
+        out += "format missing=?" + nl;
+        if (sequential)
+            out += "interleave=no ";
+        else
+            out += "interleave=yes ";
+        out += "datatype=" + type + " gap=- match=.;" + nl + nl;
+        out += "matrix" + nl;
+        return out;
+    }
+
+    /**
+     * Returns a string with the MSA type. MrBayes does not accept NUCLEOTIDE
+     * type so it is changed to DNA.
+     * @param msa MSA to get the type of.
+     * @return MSA type.
+     */
+    @Override
+    protected String getType(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+            if (type instanceof Nucleotide)
+                logger.log(Level.INFO,"Nucleotide MSA type inferred.");
+            else
+                logger.log(Level.INFO, "Protein MSA type inferred.");
+        }
+
+        if (type instanceof Protein)
+            return "PROTEIN";
+        else if (type instanceof Nucleotide)
+            if (type instanceof DNA)
+                return "DNA";
+            else if (type instanceof RNA)
+                return "RNA";
+            else
+                return "DNA";
+        else
+            return "UNKNOWN";
+    }
+}
diff --git a/alter-lib/src/writer/NexusProtTestWriter.java b/alter-lib/src/writer/NexusProtTestWriter.java
new file mode 100755
index 0000000..d52177e
--- /dev/null
+++ b/alter-lib/src/writer/NexusProtTestWriter.java
@@ -0,0 +1,70 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Nucleotide;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class NexusWriter to adapt the output to ProtTest.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class NexusProtTestWriter extends NexusWriter
+{
+    /**
+     * Class constructor. Calls the constructor in the superclass.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public NexusProtTestWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match,logger);
+    }
+
+    /**
+     * Writes a MSA in NEXUS format adapted to ProtTest. It checks that it is
+     * a proteins MSA and calls the superclass method.
+     * @param msa Input MSA.
+     * @return MSA in NEXUS format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Nucleotide)
+        {
+            logger.log(Level.WARNING,"MSA is a nucleotides MSA. " +
+                    "It will not be processed by ProtTest (only protein is processed).");
+        }
+        return super.write(msa);
+    }
+}
\ No newline at end of file
diff --git a/alter-lib/src/writer/NexusSplitsTreeWriter.java b/alter-lib/src/writer/NexusSplitsTreeWriter.java
new file mode 100644
index 0000000..96ee4c0
--- /dev/null
+++ b/alter-lib/src/writer/NexusSplitsTreeWriter.java
@@ -0,0 +1,65 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+/**
+ * Extends class NexusWriter to adapt the output to SplitsTree.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class NexusSplitsTreeWriter extends NexusWriter
+{
+    /**
+     * Class constructor. Calls the constructor in the superclass.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public NexusSplitsTreeWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os, lowerCase, sequential, match, logger);
+    }
+
+    /**
+     * Writes the NEXUS header adapted to SplitsTree.
+     * @param taxa Number of sequences.
+     * @param length Sequences length.
+     * @param type MSA type.
+     * @return NEXUS header.
+     */
+    @Override
+    protected String writeHeader(int taxa, int length, String type)
+    {
+        String out = "#nexus" + nl;
+        out += "begin taxa;" + nl;
+        out += "dimensions ntax=" + taxa + ";" + nl;
+        out += "taxlabels _detect_;" + nl;
+        out += "end;" + nl + nl;
+        out += "begin characters;" + nl;
+        out += "dimensions nchar=" + length + ";" + nl;
+        out += "format missing=?" + nl;
+        if (!sequential)
+            out += "interleave ";
+        out += "datatype=" + type.toLowerCase() + " labels gap=-;" + nl + nl;
+        out += "matrix" + nl;
+        return out;
+    }
+}
diff --git a/alter-lib/src/writer/NexusTCSWriter.java b/alter-lib/src/writer/NexusTCSWriter.java
new file mode 100755
index 0000000..ff8dae8
--- /dev/null
+++ b/alter-lib/src/writer/NexusTCSWriter.java
@@ -0,0 +1,76 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class NexusWriter to adapt the output to TCS.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class NexusTCSWriter extends NexusWriter
+{
+    /**
+     * Class constructor. Calls the constructor in the superclass.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public NexusTCSWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os, lowerCase, sequential, match, logger);
+    }
+
+    /**
+     * Writes a MSA in NEXUS format, adapted to TCS. It checks that the MSA is
+     * not a proteins MSA and that it not contains ambiguous caracters. It then
+     * calls the superclass method.
+     * @param msa Input MSA.
+     * @return MSA in NEXUS format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is a protein MSA. " +
+                    "It will not be processed by TCS (only DNA is processed).");
+        }
+        if (WriterUtils.isIUPAC(msa,type))
+        {
+            logger.log(Level.WARNING,"MSA contains IUPAC ambiguous characters. " +
+                    "They will be treated as missing data by TCS.");
+        }
+        return super.write(msa);
+    }
+}
diff --git a/alter-lib/src/writer/NexusWriter.java b/alter-lib/src/writer/NexusWriter.java
new file mode 100755
index 0000000..71e58d2
--- /dev/null
+++ b/alter-lib/src/writer/NexusWriter.java
@@ -0,0 +1,360 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import types.DNA;
+import types.Lengthable;
+import types.MSA;
+import types.Nucleotide;
+import types.Protein;
+import types.RNA;
+import types.Sequence;
+import types.Taxable;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Implements interface Writer for the NEXUS format.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class NexusWriter implements Writer
+{
+    /**
+     * New line characters according to the given output OS.
+     */
+    String nl;
+    /**
+     * Lowercase output.
+     */
+    boolean lowerCase;
+    /**
+     * Sequential output.
+     */
+    boolean sequential;
+    /**
+     * Output match characters.
+     */
+    boolean match;
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+    /**
+     * Class constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public NexusWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        if (os.equals("macos"))
+            nl = "\r";
+        else if (os.equals("linux"))
+            nl = "\n";
+        else
+            nl = "\r\n";
+        this.lowerCase = lowerCase;
+        this.sequential = sequential;
+        this.match = match;
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Writes a MSA in NEXUS format.
+     * @param msa Input MSA.
+     * @return MSA in NEXUS format.
+     */
+    public String write(MSA msa)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+       
+        //Copy sequences and find longest ID
+        String[] data = new String[msa.getSeqs().size()];
+        LinkedHashSet<String> id = new LinkedHashSet<String>(msa.getSeqs().size());
+        int longestId = 0;
+
+        for (int i = 0; i < msa.getSeqs().size(); i++)
+        {
+            Sequence seq = (Sequence)msa.getSeqs().elementAt(i);
+            //Copy data
+            data[i] = getData(seq, (Sequence) msa.getSeqs().firstElement());
+            //Copy ID
+            String uid = getId(seq,id);
+            id.add(uid);
+            //Update longest ID
+            if (uid.length() > longestId)
+                longestId = uid.length();
+        }
+
+        //Intantiate number of sequences, length and type
+        int taxa = getTaxa(msa);
+        int length = getLength(msa);
+        String type = getType(msa);
+
+        //Write header
+        outb.append(writeHeader(taxa, length, type));
+
+        if (sequential)
+            outb.append(sequential(id, longestId, data));
+        else
+            outb.append(interleaved(id, longestId, data));
+
+        outb.append(writeFooter());
+        
+        logger.log(Level.INFO, "MSA successfully converted to NEXUS format!");
+        return outb.toString();
+    }
+
+    /**
+     * Writes sequences of a MSA in sequential NEXUS.
+     * @param id Sequences identifiers.
+     * @param longestId Longest identifier length (needed to align).
+     * @param data Sequences data.
+     * @return Sequences in sequential NEXUS.
+     */
+    private String sequential (LinkedHashSet<String> id, int longestId, String[] data)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+        //Write sequences
+        int i= 0;
+        for(String uid:id)
+        {
+            outb.append(writeSequence(uid, longestId, data[i]));
+            i++;
+        }
+        return outb.toString();
+    }
+
+    /**
+     * Writes sequences of a MSA in interleaved NEXUS.
+     * @param id Sequences identifiers.
+     * @param longestId Longest identifier length (needed to align).
+     * @param data Sequences data.
+     * @return Sequences in interleaved NEXUS.
+     */
+    private String interleaved (LinkedHashSet<String> id, int longestId, String[] data)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+        //Write sequences
+        while (!data[0].isEmpty())
+        {
+            int i=0;
+            for(String uid:id)
+            {
+                outb.append(writeLine(uid, longestId, data, i));
+                i++;
+            }
+                
+            outb.append(nl);
+        }
+        
+        return outb.toString();
+    }
+
+    /**
+     * Returns the sequence identifier. In case the current identifier is
+     * repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        //Copiar identificador
+        String id = seq.getId();
+        //Si contiene espacios
+        if (id.contains(" ") || id.contains("\t"))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" contains blanks. Blanks replaced by \"_\"");
+            id = id.replaceAll("[\t ]","_");
+        }
+        //Si contiene caracteres destinados a comentarios
+        if (id.contains("[") || id.contains("]"))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" contains \"[\" or \"]\". Characters replaced by \"_\"");
+            id = id.replaceAll("\\[\\]","_");
+        }
+
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+
+    /**
+     * Returns the sequence data, using lowercase or match characters if
+     * necessary.
+     * @param seq Sequence containing the data.
+     * @param first First sequence in the MSA.
+     * @return Sequence data.
+     */
+    protected String getData(Sequence seq, Sequence first)
+    {
+        String data;
+        if (match)
+            data = WriterUtils.writeMatch(seq, first);
+        else
+            data = seq.getData();
+        if (lowerCase)
+            return data.toLowerCase();
+        else
+            return data;
+    }
+
+    /**
+     * Returns the number of sequences in the MSA.
+     * @param msa MSA to get the number of sequences of.
+     * @return Number of sequences.
+     */
+    protected int getTaxa(MSA msa)
+    {
+        if (msa instanceof Taxable)
+            return ((Taxable) msa).getTaxa();
+        else
+            return msa.getSeqs().size();
+    }
+
+    /**
+     * Returns the length of the sequences in the MSA.
+     * @param msa MSA to get the length of.
+     * @return Length of the sequences in the MSA.
+     */
+    protected int getLength(MSA msa)
+    {
+        if (msa instanceof Lengthable)
+            return ((Lengthable) msa).getLength();
+        else
+            return ((Sequence) msa.getSeqs().firstElement()).getData().length();
+    }
+
+    /**
+     * Returns a string with the MSA type.
+     * @param msa MSA to get the type of.
+     * @return MSA type.
+     */
+    protected String getType(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+            if (type instanceof Nucleotide)
+                logger.log(Level.INFO,"Nucleotide MSA type inferred.");
+            else
+                logger.log(Level.INFO, "Protein MSA type inferred.");
+        }
+
+        if (type instanceof Protein)
+            return "PROTEIN";
+        else if (type instanceof Nucleotide)
+            if (type instanceof DNA)
+                return "DNA";
+            else if (type instanceof RNA)
+                return "RNA";
+            else
+                return "NUCLEOTIDE";
+        else
+            return "UNKNOWN";
+    }
+
+    /**
+     * Writes the NEXUS header.
+     * @param taxa Number of sequences.
+     * @param length Sequences length.
+     * @param type MSA type.
+     * @return NEXUS header.
+     */
+    protected String writeHeader(int taxa, int length, String type)
+    {
+        String out = "#NEXUS" + nl;
+        out += "BEGIN DATA;" + nl;
+        out += "dimensions ntax=" + taxa + " nchar=" + length + ";" + nl;
+        out += "format missing=?" + nl;
+        out += "symbols=\"ABCDEFGHIKLMNOPQRSTUVWXYZ\"" + nl;
+        if (!sequential)
+            out += "interleave ";
+        out += "datatype=" + type + " gap=- match=.;" + nl + nl;
+        out += "matrix" + nl;
+        return out;
+    }
+
+    /**
+     * Writes NEXUS footer.
+     * @return NEXUS footer.
+     */
+    protected String writeFooter()
+    {
+        return ";" + nl + "end;" + nl;
+    }
+
+    /**
+     * Writes a complete sequence.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    protected String writeSequence(String id, int longestId, String data)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(),longestId)
+                        + WriterUtils.align(longestId, 10) + "  ");
+
+        outb.append(data + nl);
+        return outb.toString();
+    }
+
+     /**
+     * Writes a line corresponding to a sequence of the MSA.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length (needed to align).
+     * @param data Sequences data.
+     * @param index Index of the current sequence in the array (needed to
+     * update data).
+     * @return Line in NEXUS format.
+     */
+    protected String writeLine(String id, int longestId, String[] data, int index)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(),longestId)
+                        + WriterUtils.align(longestId, 10) + "  ");
+
+        //Escribir una línea si es posible
+        if (data[index].length() > 50)
+        {
+            outb.append(data[index].substring(0, 50));
+            data[index] = data[index].substring(50);
+        }
+        else
+        {
+            outb.append(data[index]);
+            data[index] =  "";
+        }
+        outb.append(nl);
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/PhylipBioEditWriter.java b/alter-lib/src/writer/PhylipBioEditWriter.java
new file mode 100644
index 0000000..2674066
--- /dev/null
+++ b/alter-lib/src/writer/PhylipBioEditWriter.java
@@ -0,0 +1,52 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+/**
+ * Extends class PhylipWriter to adapt the output to BioEdit.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipBioEditWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipBioEditWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match, logger);
+    }
+
+    /**
+     * Writes the PHYLIP header, adapted to BioEdit.
+     * @param taxa Number of sequences.
+     * @param length Sequences length.
+     * @return PHYLIP header.
+     */
+    @Override
+    protected String writeHeader(int taxa, int length)
+    {
+        return " " + taxa + " " + length + nl;
+    }
+}
diff --git a/alter-lib/src/writer/PhylipCodABCWriter.java b/alter-lib/src/writer/PhylipCodABCWriter.java
new file mode 100755
index 0000000..32b2423
--- /dev/null
+++ b/alter-lib/src/writer/PhylipCodABCWriter.java
@@ -0,0 +1,89 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class PhylipWriter to adapt the output to CodABC.
+ * @author Daniel Glez-Peña 
+ * @version 1.0
+ */
+
+public class PhylipCodABCWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipCodABCWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match,logger);
+    }
+
+    /**
+     * Writes a MSA in PHYLIP format, adapted to CodABC. It checks that the MSA is
+     * not a proteins MSA. It then calls the superclass method.
+     *
+     * @param msa Input MSA.
+     * @return MSA in NEXUS format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is a protein MSA. " +
+                    "It will not be processed by TCS (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+
+    /**
+     * Writes a complete sequence, adaptaed to CodABC. It writes the whole sequence
+     * in a single line.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    @Override
+    protected String writeSequence(String id, int longestId, String data)
+    {
+        //Write ID
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(), longestId)
+                            + WriterUtils.align(longestId, 10) + data + nl);
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/PhylipDnaSPWriter.java b/alter-lib/src/writer/PhylipDnaSPWriter.java
new file mode 100644
index 0000000..238d455
--- /dev/null
+++ b/alter-lib/src/writer/PhylipDnaSPWriter.java
@@ -0,0 +1,88 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class PhylipWriter to adapt the output to dnaSP.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipDnaSPWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipDnaSPWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match,logger);
+    }
+
+    /**
+     * Writes a MSA in PHYLIP format, adapted to dnaSP. It checks that the MSA is
+     * not a protein MSA. It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return MSA in PHYLIP format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is an amino acids MSA. " +
+                    "It will not be processed by dnaSP (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+
+    /**
+     * Writes a complete sequence, adapted to dnaSP. It writes the whole sequence
+     * in a single line.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    @Override
+    protected String writeSequence(String id, int longestId, String data)
+    {
+        //Write ID
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(), longestId)
+                            + WriterUtils.align(longestId, 10) + "  " + data + nl);
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/PhylipJModelTestWriter.java b/alter-lib/src/writer/PhylipJModelTestWriter.java
new file mode 100755
index 0000000..fdea098
--- /dev/null
+++ b/alter-lib/src/writer/PhylipJModelTestWriter.java
@@ -0,0 +1,74 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class PhylipWriter to adapt the output to jModelTest.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipJModelTestWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipJModelTestWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match, logger);
+    }
+
+    /**
+     * Writes a MSA in PHYLIP format, adapted for jModelTest. It checks
+     * that the MSA is not a protein MSA and that it contains 4 or more sequences.
+     * It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return String with the MSA in PHYLIP format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        if (msa.getSeqs().size() < 4)
+            logger.log(Level.WARNING, "MSA contains less than 4 sequences. " +
+                    "It will not be processed by jModelTest.");
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is an amino acids MSA. " +
+                    "It will not be processed by jModelTest (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+}
diff --git a/alter-lib/src/writer/PhylipMegaWriter.java b/alter-lib/src/writer/PhylipMegaWriter.java
new file mode 100644
index 0000000..986cb14
--- /dev/null
+++ b/alter-lib/src/writer/PhylipMegaWriter.java
@@ -0,0 +1,92 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import types.Sequence;
+
+/**
+ * Extends class PhylipWriter to adapt the output to MEGA.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipMegaWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipMegaWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match,logger);
+    }
+
+    /**
+     * Returns the sequence identifier, considering MEGA limitations. In case
+     * the current identifier is repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    @Override
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+        //If ID contains spaces
+        if (id.contains(" ") || id.contains("\t"))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                + "\" contains blanks. Blanks replaced by \"_\".");
+            id = id.replaceAll("[\t ]","_");
+        }
+        //If ID is longer than 256
+        if (id.length() > 256)
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" is longer than 50 characters. ID truncated to \""
+                    + id.substring(0,256) + "\"");
+            id = id.substring(0,256);
+        }
+
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+
+    /**
+     * Writes a complete sequence, adapted to MEGA. It writes the whole sequence
+     * in a single line.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    @Override
+    protected String writeSequence(String id, int longestId, String data)
+    {
+        //Write ID
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(), longestId)
+                            + WriterUtils.align(longestId, 10)+ "  " + data + nl);
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/PhylipPAMLWriter.java b/alter-lib/src/writer/PhylipPAMLWriter.java
new file mode 100755
index 0000000..b91bee0
--- /dev/null
+++ b/alter-lib/src/writer/PhylipPAMLWriter.java
@@ -0,0 +1,93 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import types.Sequence;
+
+/**
+ * Extends class PhylipWriter to adapt the output to PAML.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipPAMLWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipPAMLWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match,logger);
+    }
+
+    /**
+     * Writes the PHYLIP header, adapted to PAML. It writes an "I" in case
+     * it is interleaved.
+     * @param taxa Number of sequences.
+     * @param length Sequences length.
+     * @return PHYLIP header.
+     */
+    @Override
+    protected String writeHeader(int taxa, int length)
+    {
+        if (sequential)
+            return taxa + " " + length + nl;
+        else
+            return taxa + " " + length + " I" + nl;
+    }
+
+    /**
+     * Returns the sequence identifier, considering PAML limitations. In case
+     * the current identifier is repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    @Override
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+        //If ID contains ",:#()$="
+        if (id.contains("(") || id.contains(")")
+                || id.contains(",") || id.contains(":")
+                || id.contains("#") || id.contains("$")
+                || id.contains("="))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                + "\" contains one of \",:#()$=\". Characters removed.");
+            id = id.replaceAll("[,:=()#$]","");
+        }
+        //If ID is longer than 30
+        if (id.length() > 30)
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" is longer than 30 characters. ID truncated to \""
+                    + id.substring(0,30) + "\"");
+            id = id.substring(0,30);
+        }
+
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+}
diff --git a/alter-lib/src/writer/PhylipPhyMLWriter.java b/alter-lib/src/writer/PhylipPhyMLWriter.java
new file mode 100755
index 0000000..d6ab009
--- /dev/null
+++ b/alter-lib/src/writer/PhylipPhyMLWriter.java
@@ -0,0 +1,82 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import types.Sequence;
+
+/**
+ * Extends class PhylipWriter to adapt the output to PhyML.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipPhyMLWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipPhyMLWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match,logger);
+    }
+
+    /**
+     * Returns the sequence identifier, considering PhyML limitations. In case
+     * the current identifier is repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    @Override
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+        //If ID contains "(),:"
+        if (id.contains("(") || id.contains(")")
+                || id.contains(",") || id.contains(":"))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                + "\" contains one of \"(),:\". Characters removed.");
+            id = id.replaceAll("[,:()]","");
+        }
+        //If ID contains spaces
+        if (id.contains(" ") || id.contains("\t"))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                + "\" contains blanks. Blanks replaced by \"_\".");
+            id = id.replaceAll("[\t ]","_");
+        }
+        //If ID is longer than 100
+        if (id.length() > 100)
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" is longer than 100 characters. ID truncated to \""
+                    + id.substring(0,100) + "\"");
+            id = id.substring(0,100);
+        }
+        
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+}
diff --git a/alter-lib/src/writer/PhylipProtTestWriter.java b/alter-lib/src/writer/PhylipProtTestWriter.java
new file mode 100755
index 0000000..2ae7497
--- /dev/null
+++ b/alter-lib/src/writer/PhylipProtTestWriter.java
@@ -0,0 +1,88 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Nucleotide;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class PhylipWriter to adapt the output to ProtTest.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipProtTestWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipProtTestWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential, match, logger);
+    }
+
+    /**
+     * Writes a MSA in PHYLIP format adapted to ProtTest. It checks that it is
+     * a proteins MSA and calls the superclass method.
+     * @param msa Input MSA.
+     * @return MSA in PHYLIP format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Nucleotide)
+        {
+            logger.log(Level.WARNING,"MSA is a nucleotides MSA. " +
+                    "It will not be processed by ProtTest (only protein is processed).");
+        }
+        return super.write(msa);
+    }
+
+    /**
+     * Writes a complete sequence, adapted to ProtTest. It writes the whole sequence
+     * in a single line.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    @Override
+    protected String writeSequence(String id, int longestId, String data)
+    {
+        //Write ID
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(), longestId)
+                            + WriterUtils.align(longestId, 10) + "  " + data + nl);
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/PhylipRAxMLWriter.java b/alter-lib/src/writer/PhylipRAxMLWriter.java
new file mode 100755
index 0000000..b67dd62
--- /dev/null
+++ b/alter-lib/src/writer/PhylipRAxMLWriter.java
@@ -0,0 +1,119 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import types.MSA;
+import types.Sequence;
+
+/**
+ * Extends class PhylipWriter to adapt the output to RAxML.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipRAxMLWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipRAxMLWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match,logger);
+    }
+
+    /**
+     * Writes a MSA in PHYLIP format, adapted for RAxML. It checks
+     * that the MSA contains 4 or more sequences.
+     * It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return String with the MSA in PHYLIP format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        if (msa.getSeqs().size() < 4)
+            logger.log(Level.WARNING, "MSA contains less than 4 sequences. " +
+                    "It will not be processed by RAxML.");
+        return super.write(msa);
+    }
+
+    /**
+     * Returns the sequence identifier, considering RAxML limitations. In case
+     * the current identifier is repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    @Override
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+        //If ID contains "(),:;[]"
+        if (id.contains("(") || id.contains(")")
+                || id.contains(",") || id.contains(":")
+                || id.contains(";") || id.contains("[")
+                || id.contains("]"))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                + "\" contains one of \"()[],:;\". Characters removed.");
+            id = id.replaceAll("[,:;()\\[\\]]","");
+        }
+        //If ID contains spaces
+        if (id.contains(" ") || id.contains("\t"))
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                + "\" contains blanks. Blanks replaced by \"_\".");
+            id = id.replaceAll("[\t ]","_");
+        }
+        //If ID is longer than 256
+        if (id.length() > 256)
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" is longer than 50 characters. ID truncated to \""
+                    + id.substring(0,256) + "\"");
+            id = id.substring(0,256);
+        }
+        
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+
+    /**
+     * Writes a complete sequence, adapted to RAxML. It writes the whole sequence
+     * in a single line.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    @Override
+    protected String writeSequence(String id, int longestId, String data)
+    {
+        //Write ID
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(), longestId)
+                            + WriterUtils.align(longestId, 10) + "  " + data + nl);
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/PhylipSplitsTreeWriter.java b/alter-lib/src/writer/PhylipSplitsTreeWriter.java
new file mode 100644
index 0000000..81cfcce
--- /dev/null
+++ b/alter-lib/src/writer/PhylipSplitsTreeWriter.java
@@ -0,0 +1,58 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+/**
+ * Extends class PhylipWriter to adapt the output to SplitsTree.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipSplitsTreeWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipSplitsTreeWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match,logger);
+    }
+
+    /**
+     * Writes a complete sequence, adapted to SplitsTree. It writes the whole sequence
+     * in a single line.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    @Override
+    protected String writeSequence(String id, int longestId, String data)
+    {
+        //Write ID
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(), longestId)
+                            + WriterUtils.align(longestId, 10) + "  " + data + nl);
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/PhylipTCSWriter.java b/alter-lib/src/writer/PhylipTCSWriter.java
new file mode 100755
index 0000000..5786ba6
--- /dev/null
+++ b/alter-lib/src/writer/PhylipTCSWriter.java
@@ -0,0 +1,94 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class PhylipWriter to adapt the output to TCS.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PhylipTCSWriter extends PhylipWriter
+{
+    /**
+     * Class constructor. Calls superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipTCSWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        super(os,lowerCase,sequential,match,logger);
+    }
+
+    /**
+     * Writes a MSA in PHYLIP format, adapted to TCS. It checks that the MSA is
+     * not a proteins MSA and that it not contains ambiguous caracters. It then
+     * calls the superclass method.
+     * @param msa Input MSA.
+     * @return MSA in NEXUS format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is a protein MSA. " +
+                    "It will not be processed by TCS (only DNA is processed).");
+        }
+        if (WriterUtils.isIUPAC(msa,type))
+        {
+            logger.log(Level.WARNING,"MSA contains IUPAC ambiguous characters. " +
+                    "They will be treated as missing data by TCS.");
+        }
+        return super.write(msa);
+    }
+
+    /**
+     * Writes a complete sequence, adaptaed to TCS. It writes the whole sequence
+     * in a single line.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    @Override
+    protected String writeSequence(String id, int longestId, String data)
+    {
+        //Write ID
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(), longestId)
+                            + WriterUtils.align(longestId, 10) + data + nl);
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/PhylipWriter.java b/alter-lib/src/writer/PhylipWriter.java
new file mode 100755
index 0000000..273d9c1
--- /dev/null
+++ b/alter-lib/src/writer/PhylipWriter.java
@@ -0,0 +1,373 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import types.MSA;
+import types.Lengthable;
+import types.Taxable;
+import types.Sequence;
+
+/**
+ * Implements interface Writer for the PHYLIP format.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class PhylipWriter implements Writer
+{
+    /**
+     * New line characters according to the given output OS.
+     */
+    String nl;
+    /**
+     * Lowercase output.
+     */
+    boolean lowerCase;
+    /**
+     * Sequential output.
+     */
+    boolean sequential;
+    /**
+     * Output match characters.
+     */
+    boolean match;
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+    /**
+     * Class constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param sequential Sequential output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PhylipWriter(String os, boolean lowerCase, boolean sequential, boolean match, String logger)
+    {
+        if (os.equals("macos"))
+            nl = "\r";
+        else if (os.equals("linux"))
+            nl = "\n";
+        else
+            nl = "\r\n";
+        this.lowerCase = lowerCase;
+        this.sequential = sequential;
+        this.match = match;
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Writes a MSA in PHYLIP format.
+     * @param msa Input MSA.
+     * @return MSA in PHYLIP format.
+     */
+    public String write(MSA msa)
+    {
+        //Output
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+        
+        //Instantiate taxa and length
+        int taxa = getTaxa(msa);
+        int length = getLength(msa);
+
+        outb.append(writeHeader(taxa, length));
+
+        //Copy sequences
+        String[] data = new String[msa.getSeqs().size()];
+        LinkedHashSet<String> id = new LinkedHashSet<String>(msa.getSeqs().size());
+        int longestId = 0;
+        for (int i = 0; i < msa.getSeqs().size(); i++)
+        {
+            Sequence seq = (Sequence) msa.getSeqs().elementAt(i);
+            //Copy data
+            data[i] = getData(seq, (Sequence) msa.getSeqs().firstElement());
+            String uid = getId(seq,id);
+            id.add(uid);
+            //Update longest ID
+            if(uid.length() > longestId)
+                longestId = uid.length();
+        }
+        if (sequential)
+            outb.append(sequential(id, longestId, data));
+        else
+            outb.append(interleaved(id, longestId, data));
+
+        logger.log(Level.INFO, "MSA successfully converted to PHYLIP format!");
+        return outb.toString();
+    }
+
+    /**
+     * Writes sequences of a MSA in interleaved PHYLIP.
+     * @param id Sequences identifiers.
+     * @param longestId Longest identifier length (needed to align).
+     * @param data Sequences data.
+     * @return Sequences in interleaved PHYLIP.
+     */
+    private String interleaved(LinkedHashSet<String> id, int longestId, String[] data)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+
+        //Write first sequences with identifier
+        int i = 0;
+        for (String uid:id)
+        {
+            outb.append(writeLine(uid, longestId, data, i));
+            i++;
+        }
+
+        outb.append(nl);
+
+        //Write the rest of the sequences
+        while (!data[0].isEmpty())
+        {
+            i = 0;
+            for (String uid:id)
+            {
+                outb.append(writeLine(longestId, data, i));
+                i++;
+            }
+            outb.append(nl);
+        }
+        return outb.toString();
+    }
+
+    /**
+     * Writes sequences of a MSA in sequential PHYLIP.
+     * @param id Sequences identifiers.
+     * @param longestId Longest identifier length (needed to align).
+     * @param data Sequences data.
+     * @return Sequences in sequential PHYLIP.
+     */
+    private String sequential(LinkedHashSet<String> id, int longestId, String[] data)
+    {
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+
+        int i = 0;
+        for (String uid:id)
+        {
+            outb.append(writeSequence(uid, longestId, data[i]));
+            i++;
+        }
+        return outb.toString();
+    }
+
+    /**
+     * Returns the number of sequences in the MSA.
+     * @param msa MSA to get the number of sequences of.
+     * @return Number of sequences.
+     */
+    protected int getTaxa(MSA msa)
+    {
+        if (msa instanceof Taxable)
+            return ((Taxable) msa).getTaxa();
+        else
+            return msa.getSeqs().size();
+    }
+
+    /**
+     * Returns the length of the sequences in the MSA.
+     * @param msa MSA to get the length of.
+     * @return Length of the sequences in the MSA.
+     */
+    protected int getLength(MSA msa)
+    {
+        if (msa instanceof Lengthable)
+            return ((Lengthable) msa).getLength();
+        else
+            return ((Sequence) msa.getSeqs().firstElement()).getData().length();
+    }
+
+    /**
+     * Returns the sequence identifier. In case the current identifier is
+     * repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+        if (id.length() > 10)
+        {
+            logger.log(Level.WARNING,"ID for sequence \"" + id
+                    + "\" is longer than 10 characters. ID truncated to \""
+                    + id.substring(0,10) + "\"");
+            id = id.substring(0,10);
+        }
+
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+
+    /**
+     * Returns the sequence data, using lowercase or match characters if
+     * necessary.
+     * @param seq Sequence containing the data.
+     * @param first First sequence in the MSA.
+     * @return Sequence data.
+     */
+    protected String getData(Sequence seq, Sequence first)
+    {
+        String data;
+        if (match)
+            data = WriterUtils.writeMatch(seq, first);
+        else
+            data = seq.getData();
+        if (lowerCase)
+            return data.toLowerCase();
+        else
+            return data;
+    }
+
+    /**
+     * Writes the PHYLIP header.
+     * @param taxa Number of sequences.
+     * @param length Sequences length.
+     * @return PHYLIP header.
+     */
+    protected String writeHeader(int taxa, int length)
+    {
+        return taxa + " " + length + nl;
+    }
+
+    /**
+     * Writes a line corresponding to a sequence of the MSA.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length (needed to align).
+     * @param data Sequences data.
+     * @param index Index of the current sequence in the array (needed to
+     * update data).
+     * @return Line in PHYLIP format.
+     */
+    protected String writeLine(String id, int longestId, String[] data, int index)
+    {
+        //Write ID
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(), longestId) +
+                WriterUtils.align(longestId, 10) + "  ");
+
+        //Write a row of 10 character blocks
+        for (int j = 0; j < 5; j++)
+        {
+            //If there are enough characters to make a 10 character block
+            if (data[index].length() > 10)
+            {
+
+                outb.append(data[index].substring(0, 10) + " ");
+                data[index] = data[index].substring(10);
+            }
+            else
+            {
+                outb.append(data[index]);
+                data[index] = "";
+            }
+            //If there are no more characters to write exit the loop
+            if (data[index].isEmpty())
+                break;
+        }
+        outb.append(nl);
+        return outb.toString();
+    }
+
+    /**
+     * Writes a line corresponding to a sequence of the MSA. This method is
+     * used in interleaved PHYLIP when the identifier is omitted before the data.
+     * @param longestId Longest identifier length (needed to align).
+     * @param data Sequences data.
+     * @param index Index of the current sequence in the array (needed to
+     * update data).
+     * @return Line in PHYLIP format.
+     */
+    protected String writeLine(int longestId, String[] data, int index)
+    {
+        //Write spaces to align
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(WriterUtils.align(0, longestId)
+                        + WriterUtils.align(longestId, 10) + "  ");
+        //Write a row of 10 character blocks
+        for (int j = 0; j < 5; j++)
+        {
+            //If there are enough chracters to make a 10 character block
+            if (data[index].length() > 10)
+            {
+                outb.append(data[index].substring(0, 10) + " ");
+                data[index] = data[index].substring(10);
+            }
+            else
+            {
+                outb.append(data[index]);
+                data[index] = "";
+            }
+
+            //If there are no more characters to write, exit the loop.
+            if (data[index].isEmpty())
+                break;
+        }
+        outb.append(nl);
+        return outb.toString();
+    }
+
+    /**
+     * Writes a complete sequence.
+     * @param id Sequence identifier.
+     * @param longestId Longest identifier length.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    protected String writeSequence(String id, int longestId, String data)
+    {
+        //Write ID
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_SEQLENGTH);
+        outb.append(id + WriterUtils.align(id.length(), longestId)
+                            + WriterUtils.align(longestId, 10) + "  ");
+
+        while(!data.isEmpty())
+        {
+            //Write a row with 10 character blocks
+            for (int j = 0; j < 5; j++)
+            {
+                //If there are enough characters to make a 10 character block
+                if (data.length() > 10)
+                {
+                    outb.append(data.substring(0, 10) + " ");
+                    data = data.substring(10);
+                }
+                else
+                {
+                    outb.append(data);
+                    data = "";
+                }
+                //If there are no more characters to write, exit the loop
+                if (data.isEmpty())
+                    break;
+            }
+            outb.append(nl);
+            if (!data.isEmpty())
+            {
+                outb.append(WriterUtils.align(0, longestId)
+                        + WriterUtils.align(longestId, 10) + "  ");
+            }
+        }
+        outb.append(nl);
+        return outb.toString();
+    }
+}
diff --git a/alter-lib/src/writer/PirDnaSPWriter.java b/alter-lib/src/writer/PirDnaSPWriter.java
new file mode 100644
index 0000000..89f8811
--- /dev/null
+++ b/alter-lib/src/writer/PirDnaSPWriter.java
@@ -0,0 +1,69 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extiende la clase PirWriter para adaptar la salida a dnaSP.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PirDnaSPWriter extends PirWriter
+{
+    /**
+     * Constructor de la clase. Llama al constructor de la superclase.
+     * @param os Sistema operativo de salida.
+     * @param lowerCase Salida en letras minúsculas.
+     * @param match Salida codificada con caracteres match.
+     * @param logger Nombre del logger a instanciar.
+     */
+    public PirDnaSPWriter(String os, boolean lowerCase, boolean match, String logger)
+    {
+        super(os,lowerCase,match,logger);
+    }
+
+    /**
+     * Escribe un MSA en formato PIR adaptado a dnaSP. Para ello
+     * comprueba que el MSA no sea de proteínas. Luego llama al método de la superclase.
+     * @param msa MSA de entrada.
+     * @return Cadena con la el MSA en formato PIR.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is an amino acids MSA. " +
+                    "It will not be processed by dnaSP (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+}
diff --git a/alter-lib/src/writer/PirJModelTestWriter.java b/alter-lib/src/writer/PirJModelTestWriter.java
new file mode 100755
index 0000000..9fd9594
--- /dev/null
+++ b/alter-lib/src/writer/PirJModelTestWriter.java
@@ -0,0 +1,73 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.logging.Level;
+import types.MSA;
+import types.Protein;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Extends class PirWriter to adapt the output to jModelTest.
+ * @author Daniel Gomez Blanco
+ * @version 1.0
+ */
+
+public class PirJModelTestWriter extends PirWriter
+{
+    /**
+     * Class constructor. Calls the superclass constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PirJModelTestWriter(String os, boolean lowerCase, boolean match, String logger)
+    {
+        super(os,lowerCase,match,logger);
+    }
+
+    /**
+     * Writes a MSA in PIR format, adapted for jModelTest. It checks
+     * that the MSA is not a protein MSA and that it contains 4 or more sequences.
+     * It then calls the method in the superclass.
+     * @param msa Input MSA.
+     * @return String with the MSA in PIR format.
+     */
+    @Override
+    public String write(MSA msa)
+    {
+        if (msa.getSeqs().size() < 4)
+            logger.log(Level.WARNING, "MSA contains less than 4 sequences. " +
+                    "It will not be processed by jModelTest.");
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+        }
+        if (type instanceof Protein)
+        {
+            logger.log(Level.WARNING,"MSA is an amino acids MSA. " +
+                    "It will not be processed by jModelTest (only DNA is processed).");
+        }
+        return super.write(msa);
+    }
+}
diff --git a/alter-lib/src/writer/PirWriter.java b/alter-lib/src/writer/PirWriter.java
new file mode 100755
index 0000000..7a4c4c5
--- /dev/null
+++ b/alter-lib/src/writer/PirWriter.java
@@ -0,0 +1,248 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import types.DNA;
+import types.DNACircular;
+import types.DNALinear;
+import types.MSA;
+import types.Sequence;
+import types.Describable;
+import types.Nucleotide;
+import types.Protein;
+import types.ProteinComplete;
+import types.ProteinFragment;
+import types.RNA;
+import types.RNACircular;
+import types.RNALinear;
+import types.RNAOther;
+import types.RNAt;
+import types.Type;
+import types.Typeable;
+
+/**
+ * Implements interface Writer for the PIR format.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+public class PirWriter implements Writer
+{
+    /**
+     * New line characters according to the given output OS.
+     */
+    String nl;
+    /**
+     * Lowercase output.
+     */
+    boolean lowerCase;
+    /**
+     * Output match characters.
+     */
+    boolean match;
+    /**
+     * Logger to register information messages.
+     */
+    Logger logger;
+
+    /**
+     * Class constructor.
+     * @param os Output operating system.
+     * @param lowerCase Lowercase output.
+     * @param match Output match characters.
+     * @param logger Logger name.
+     */
+    public PirWriter(String os, boolean lowerCase, boolean match, String logger)
+    {
+        if (os.equals("macos"))
+            nl = "\r";
+        else if (os.equals("linux"))
+            nl = "\n";
+        else
+            nl = "\r\n";
+        this.lowerCase = lowerCase;
+        this.match = match;
+        this.logger = Logger.getLogger(logger);
+    }
+
+    /**
+     * Writes a MSA in PIR format.
+     * @param msa Input MSA.
+     * @return MSA in PIR format.
+     */
+    public String write(MSA msa)
+    {
+        //Output
+        StringBuffer outb = new StringBuffer(STRING_BUFFER_MSALENGTH);
+
+        String type = getType(msa);
+        LinkedHashSet<String> ids = new LinkedHashSet<String>(msa.getSeqs().size());
+        //Write sequences
+        for (int i = 0; i < msa.getSeqs().size(); i++)
+        {
+            //Get sequence
+            Sequence seq = (Sequence) msa.getSeqs().elementAt(i);
+            //Instantiate attributes
+            String id = getId(seq, ids);
+            ids.add(id);
+            String data = getData(seq, (Sequence) msa.getSeqs().firstElement());
+            String desc = getDesc(seq);
+            //Write sequence
+            outb.append(writeSequence(type, id, desc, data));
+        }
+        
+        logger.log(Level.INFO, "MSA successfully converted to PIR format!");
+        return outb.toString();
+    }
+
+    /**
+     * Devuelve una cadena con el identificador de la secuencia. En caso de
+     * que el identificador de secuencia esté repetido se renombra.
+     * @param seq Secuencia de la cual se desea obtener el identificador.
+     * @param ids Secuencias copiadas hasta el momento.
+     * @return Identificador de secuencia único.
+     */
+    protected String getId(Sequence seq, LinkedHashSet<String> ids)
+    {
+        String id = seq.getId();
+
+        return WriterUtils.getUniqueId(ids, id, logger.getName());
+    }
+
+    /**
+     * Returns the sequence identifier. In case the current identifier is
+     * repeated, it will be renamed.
+     * @param seq Sequence containing the identifier.
+     * @param ids Sequences copied so far.
+     * @return Unique sequence identifier.
+     */
+    protected String getData(Sequence seq, Sequence first)
+    {
+        String data;
+        if (match)
+            data = WriterUtils.writeMatch(seq, first);
+        else
+            data = seq.getData();
+        if (lowerCase)
+            return data.toLowerCase();
+        else
+            return data;
+    }
+
+    /**
+     * Returns a sequence description.
+     * @param seq Sequence to get the description of..
+     * @return Sequence description.
+     */
+    protected String getDesc(Sequence seq)
+    {
+        if (seq instanceof Describable)
+            return ((Describable) seq).getDesc();
+        else
+            return "";
+    }
+
+    /**
+     * Returns a string with the type of MSA.
+     * @param msa MSA to get the type of.
+     * @return MSA type.
+     */
+    protected String getType(MSA msa)
+    {
+        //Infer type if the instance is not Typeable
+        Type type = null;
+        if (msa instanceof Typeable)
+            type = ((Typeable) msa).getType();
+        if (type == null)
+        {
+            type = WriterUtils.inferType(msa);
+            if (type instanceof Nucleotide)
+                logger.log(Level.INFO,"Nucleotide MSA type inferred.");
+            else
+                logger.log(Level.INFO, "Protein MSA type inferred.");
+        }
+        if (type instanceof Nucleotide)
+            if (type instanceof DNA)
+                if (type instanceof DNALinear)
+                    return "DL";
+                else if (type instanceof DNACircular)
+                    return "DC";
+                else
+                    return "DL";
+            else if (type instanceof RNA)
+                if (type instanceof RNALinear)
+                    return "RL";
+                else if (type instanceof RNACircular)
+                    return "RC";
+                else if (type instanceof RNAt)
+                    return "N3";
+                else if (type instanceof RNAOther)
+                    return "N1";
+                else
+                    return "RL";
+            else
+                return "DL";
+        else if (type instanceof Protein)
+            if (type instanceof ProteinComplete)
+                return "P1";
+            else if (type instanceof ProteinFragment)
+                return "F1";
+            else
+                return "P1";
+        else
+            return "XX";
+    }
+
+    /**
+     * Writes a complete sequence.
+     * @param type Sequence type.
+     * @param id Sequence identifier.
+     * @param desc Sequence description.
+     * @param data Sequence data.
+     * @return Formatted sequence.
+     */
+    protected String writeSequence(String type, String id, String desc, String data)
+    {
+        String out = "";
+        //Write type, ID and description.
+        out += ">" + type + ";" + id + nl;
+        out += desc + nl;
+
+        //While there are characters to write
+        while (data.length() > 0)
+        {
+            //If there are enough characters to make a line
+            if (data.length() > 60)
+            {
+                out += data.substring(0, 60);
+                data = data.substring(60);
+            }
+            else
+            {
+                out += data;
+                data = "";
+            }
+            out += nl;
+        }
+        out += "*" + nl;
+
+        return out;
+    }
+}
diff --git a/alter-lib/src/writer/Writer.java b/alter-lib/src/writer/Writer.java
new file mode 100755
index 0000000..1ce787b
--- /dev/null
+++ b/alter-lib/src/writer/Writer.java
@@ -0,0 +1,39 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import types.MSA;
+
+/**
+ * Define los métodos que deben implementar todos los escritores.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public interface Writer
+{
+    /**
+     * Devuelve una cadena con el MSA en un formato determinado.
+     * @param msa MSA de entrada.
+     * @return Cadena con el MSA formateado.
+     */
+    public String write(MSA msa);
+
+    public int STRING_BUFFER_MSALENGTH = 10000;
+    public int STRING_BUFFER_SEQLENGTH = 2000;
+}
diff --git a/alter-lib/src/writer/WriterUtils.java b/alter-lib/src/writer/WriterUtils.java
new file mode 100755
index 0000000..ddf937f
--- /dev/null
+++ b/alter-lib/src/writer/WriterUtils.java
@@ -0,0 +1,179 @@
+/*
+ *  This file is part of ALTER.
+ *
+ *  ALTER 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 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  ALTER 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with ALTER.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package writer;
+
+import java.util.LinkedHashSet;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import types.MSA;
+import types.Nucleotide;
+import types.Protein;
+import types.Sequence;
+import types.Type;
+
+/**
+ * Class with static methods commonly used by all writers.
+ * @author Daniel Gomez Blanco
+ * @version 1.1
+ */
+
+public class WriterUtils
+{
+    /**
+     * Returns a string with the number of spaces to align two strings.
+     * @param cur Current string length.
+     * @param longest Longest string length.
+     * @return String with loges - cur spaces.
+     */
+    public static String align (int cur, int longest)
+    {
+        String toret = "";
+        for(int i=cur;i<longest;i++)
+        {
+            toret = toret.concat(" ");
+        }
+        return toret;
+    }
+
+    /**
+     * Infers the MSA type from the characters contained in its sequences.
+     * If the sequences are made up of characters A, C, G, T or U
+     * in an 85% or more, the MSA is considered to be nucleotide. This algorithm
+     * has been tested to be correct in 97,3% of the cases.
+     * @param msa Input MSA.
+     * @return MSA type (Nucleotide or Protein).
+     */
+    public static Type inferType(MSA msa)
+    {
+        //Counters for total read and and nucleotide read
+        int total = 0;
+        int n = 0;
+
+        //Para cada secuencia
+        for (int i=0;i<msa.getSeqs().size();i++)
+        {
+            String seq = ((Sequence) msa.getSeqs().elementAt(i)).getData();
+            for(int j=0;j<seq.length();j++)
+            {
+                if (seq.charAt(j) != '-' && seq.charAt(j) != '?')
+                {
+                    total++;
+                    if (seq.charAt(j) == 'A' || seq.charAt(j) == 'C'
+                            || seq.charAt(j) == 'G' || seq.charAt(j) == 'T'
+                            || seq.charAt(j) == 'U')
+                        n++;
+                }
+            }
+        }
+
+        //Return adequate type
+        if ((100 * n) / total >= 85)
+            return new Nucleotide();
+        else
+            return new Protein();
+    }
+
+    /**
+     * Indicates if a MSA contains ambiguous IUPAC characters or not.
+     * @param msa Input MSA.
+     * @param type Input MSA type.
+     * @return Boolean indicating if the MSA contains ambiguous characters.
+     */
+    public static boolean isIUPAC(MSA msa, Type type)
+    {
+        boolean toret = false;
+
+        //If it is a protein
+        if (type instanceof Protein)
+            for(int i=0; i<msa.getSeqs().size();i++)
+            {
+                String data = ((Sequence) msa.getSeqs().elementAt(i)).getData();
+
+                for(int j=0; j<data.length();j++)
+                    if (data.charAt(j) == 'B' || data.charAt(j) == 'Z'
+                            || data.charAt(j) == 'X')
+                        toret = true;
+            }
+        //If it is a nucleotide
+        else if (type instanceof Nucleotide)
+            for(int i=0; i<msa.getSeqs().size();i++)
+            {
+                String data = ((Sequence) msa.getSeqs().elementAt(i)).getData();
+
+                for(int j=0; j<data.length();j++)
+                    if (data.charAt(j) == 'R' || data.charAt(j) == 'Y'
+                        || data.charAt(j) == 'M' || data.charAt(j) == 'K'
+                        || data.charAt(j) == 'W' || data.charAt(j) == 'S'
+                        || data.charAt(j) == 'B' || data.charAt(j) == 'D'
+                        || data.charAt(j) == 'H' || data.charAt(j) == 'V'
+                        || data.charAt(j) == 'N')
+                        toret = true;
+            }
+        
+        return toret;
+    }
+
+    /**
+     * Writes match characters in the current sequence where the character
+     * in the same position of the first sequence is equal.
+     * @param seq Current sequence.
+     * @param firstSeq First sequence.
+     * @return Sequence data with match characters.
+     */
+    public static String writeMatch(Sequence seq, Sequence firstSeq)
+    {
+        if(seq != firstSeq)
+        {
+            StringBuffer toret = new StringBuffer();
+            String data = seq.getData();
+            String first = firstSeq.getData();
+            for (int i=0;i<data.length();i++)
+                if (first.charAt(i) != '-' && first.charAt(i) != '?'
+                        && data.charAt(i) == first.charAt(i))
+                    toret.append(".");
+                else
+                    toret.append(data.charAt(i));
+            return toret.toString();
+        }
+        else
+            return seq.getData();
+    }
+
+    /**
+     * Returns a unique sequence identifier, checking that it is not repeated
+     * in the hash set given as a parameter, and renaming it if necessary.
+     * @param ids Sequences identifiers.
+     * @param id Current sequence identifier.
+     * @param logger Name of the logger.
+     * @return
+     */
+    public static String getUniqueId(LinkedHashSet<String> ids, String id, String logger)
+    {
+        String oldId = id;
+        int cont = 0;
+        while(ids.contains(id))
+        {
+            int contChars = String.valueOf(cont).length();
+            id = id.substring(0, id.length() - contChars - 1) + "_" + cont;
+            cont++;
+        }
+        if(!oldId.equals(id))
+            Logger.getLogger(logger).log(Level.WARNING, "ID for sequence \"" + oldId + "\" renamed to \"" + id + "\".");
+        return id;
+    }
+}
diff --git a/alter-lib/src/writer/package.html b/alter-lib/src/writer/package.html
new file mode 100755
index 0000000..7a1c546
--- /dev/null
+++ b/alter-lib/src/writer/package.html
@@ -0,0 +1,16 @@
+<!--
+To change this template, choose Tools | Templates
+and open the template in the editor.
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title></title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+  </head>
+  <body>
+    Writers to print MSAs in their correct formats.
+    @author Daniel Gomez Blanco
+    @version 1.1
+  </body>
+</html>
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..111ce0a
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="ALTER" default="buildall" basedir="."> 
+
+  <target name="buildlib">
+    <ant antfile="build.xml" dir="./alter-lib" inheritAll="false"/>   
+    <copy file="./alter-lib/dist/ALTER.jar" tofile="./web/ALTER.jar"/>
+  </target>
+  
+  <target name="buildall" depends="clean, buildlib">
+    <ant antfile="build.xml" dir="./web" inheritAll="false"/>   
+  </target>
+  <target name="clean">
+    <ant antfile="build.xml" dir="./alter-lib" target="clean" inheritAll="false"/>   
+    <ant antfile="build.xml" dir="./web" target="clean" inheritAll="false"/> 
+    <delete file="./web/ALTER.jar"/>
+  </target>
+  
+</project>

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



More information about the debian-med-commit mailing list