[med-svn] [jmodeltest] 02/05: Imported Upstream version 2.1.8+dfsg

Andreas Tille tille at debian.org
Wed Oct 28 21:24:29 UTC 2015


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

tille pushed a commit to branch master
in repository jmodeltest.

commit 5f03be0a750796291ef461047b8d576edc0a49bf
Author: Andreas Tille <tille at debian.org>
Date:   Wed Oct 28 21:53:10 2015 +0100

    Imported Upstream version 2.1.8+dfsg
---
 .hgignore                                          |    2 +
 INSTALL                                            |   28 +-
 Manifest                                           |    5 +
 README.md                                          |   55 +
 build.xml                                          |   77 +
 lib/BrowserLauncher2-all-1_3.jar                   |  Bin 186442 -> 0 bytes
 lib/readseq.jar                                    |  Bin 763870 -> 0 bytes
 manual/biblio.bib                                  |  370 ++++
 manual/images/bic.pdf                              |  Bin 0 -> 9472 bytes
 manual/images/consensus.pdf                        |  Bin 0 -> 8653 bytes
 manual/images/dLRT.png                             |  Bin 0 -> 134234 bytes
 manual/images/hLRT.png                             |  Bin 0 -> 97522 bytes
 manual/images/html-log.pdf                         |  Bin 0 -> 152908 bytes
 manual/images/lkl-settings.pdf                     |  Bin 0 -> 13118 bytes
 manual/images/main-window.pdf                      |  Bin 0 -> 17523 bytes
 manual/images/results.pdf                          |  Bin 0 -> 27952 bytes
 manual/manual.tex                                  |  360 ++++
 manual/natbib.bst                                  | 1288 ++++++++++++++
 manual/natbib.sty                                  |  803 +++++++++
 manual/sec-arguments.tex                           |  178 ++
 manual/sec-config.tex                              |  145 ++
 manual/sec-quickstart.tex                          |  315 ++++
 manual/sec-theory.tex                              |  199 +++
 .../darwin/jmodeltest/ApplicationOptions.java      |  764 ++++++++
 .../jmodeltest/InvalidArgumentException.java       |  108 ++
 .../java/es/uvigo/darwin/jmodeltest/ModelTest.java | 1841 ++++++++++++++++++++
 .../darwin/jmodeltest/ModelTestConfiguration.java  |  188 ++
 .../uvigo/darwin/jmodeltest/ModelTestService.java  |  171 ++
 .../darwin/jmodeltest/WeakStateException.java      |   37 +
 .../exception/AlignmentParseException.java         |   46 +
 .../jmodeltest/exception/CheckedException.java     |   42 +
 .../jmodeltest/exception/InputFileException.java   |   24 +
 .../jmodeltest/exception/InternalException.java    |   44 +
 .../uvigo/darwin/jmodeltest/exe/Distributor.java   |  231 +++
 .../darwin/jmodeltest/exe/GuidedSearchManager.java |  274 +++
 .../darwin/jmodeltest/exe/MultipleDistributor.java |  316 ++++
 .../darwin/jmodeltest/exe/PhymlParallelModel.java  |  118 ++
 .../darwin/jmodeltest/exe/PhymlSingleModel.java    |  542 ++++++
 .../darwin/jmodeltest/exe/ProcessManager.java      |   64 +
 .../uvigo/darwin/jmodeltest/exe/RunConsense.java   |  320 ++++
 .../es/uvigo/darwin/jmodeltest/exe/RunPhyml.java   |  387 ++++
 .../darwin/jmodeltest/exe/RunPhymlClustering.java  |  137 ++
 .../darwin/jmodeltest/exe/RunPhymlHybrid.java      |  301 ++++
 .../uvigo/darwin/jmodeltest/exe/RunPhymlMPJ.java   |  205 +++
 .../darwin/jmodeltest/exe/RunPhymlThread.java      |  190 ++
 .../uvigo/darwin/jmodeltest/exe/StreamGobbler.java |  103 ++
 .../es/uvigo/darwin/jmodeltest/gui/FrameMain.java  | 1225 +++++++++++++
 .../darwin/jmodeltest/gui/FramePreferences.java    |  341 ++++
 .../uvigo/darwin/jmodeltest/gui/FrameResults.java  |  352 ++++
 .../es/uvigo/darwin/jmodeltest/gui/Frame_AIC.java  |  366 ++++
 .../es/uvigo/darwin/jmodeltest/gui/Frame_BIC.java  |  325 ++++
 .../darwin/jmodeltest/gui/Frame_CalcLike.java      |  943 ++++++++++
 .../darwin/jmodeltest/gui/Frame_Consense.java      |  348 ++++
 .../es/uvigo/darwin/jmodeltest/gui/Frame_DT.java   |  313 ++++
 .../darwin/jmodeltest/gui/Frame_LRTcalculator.java |  363 ++++
 .../darwin/jmodeltest/gui/Frame_Progress.java      |  663 +++++++
 .../es/uvigo/darwin/jmodeltest/gui/Frame_hLRT.java |  519 ++++++
 .../darwin/jmodeltest/gui/JModelTestFrame.java     |   34 +
 .../es/uvigo/darwin/jmodeltest/gui/XManager.java   |  258 +++
 .../darwin/jmodeltest/io/AlignmentReader.java      |  139 ++
 .../darwin/jmodeltest/io/DocumentOutputStream.java |  107 ++
 .../uvigo/darwin/jmodeltest/io/HtmlReporter.java   |  664 +++++++
 .../darwin/jmodeltest/io/NullPrintStream.java      |   31 +
 .../es/uvigo/darwin/jmodeltest/io/RFHistogram.java |   99 ++
 .../darwin/jmodeltest/io/TextInputStream.java      |    1 +
 .../darwin/jmodeltest/io/TextOutputStream.java     |  612 +++++++
 .../es/uvigo/darwin/jmodeltest/model/Model.java    |  625 +++++++
 .../darwin/jmodeltest/model/ModelComparator.java   |   46 +
 .../darwin/jmodeltest/model/ModelConstants.java    |  297 ++++
 .../observer/ConsoleProgressObserver.java          |  209 +++
 .../darwin/jmodeltest/observer/ProgressInfo.java   |   97 ++
 .../es/uvigo/darwin/jmodeltest/selection/AIC.java  |  276 +++
 .../es/uvigo/darwin/jmodeltest/selection/AICc.java |  295 ++++
 .../es/uvigo/darwin/jmodeltest/selection/BIC.java  |  277 +++
 .../es/uvigo/darwin/jmodeltest/selection/DT.java   |  272 +++
 .../es/uvigo/darwin/jmodeltest/selection/HLRT.java |  643 +++++++
 .../jmodeltest/selection/InformationCriterion.java |  660 +++++++
 .../darwin/jmodeltest/statistics/Statistics.java   |    1 +
 .../darwin/jmodeltest/threads/SwingWorker.java     |    1 +
 .../darwin/jmodeltest/tree/TreeDistancesCache.java |  146 ++
 .../tree/TreeEuclideanDistancesCache.java          |   44 +
 .../jmodeltest/tree/TreeRFDistancesCache.java      |   44 +
 .../uvigo/darwin/jmodeltest/tree/TreeSummary.java  |  405 +++++
 .../darwin/jmodeltest/tree/TreeUtilities.java      |  170 ++
 .../jmodeltest/utilities/InitialFocusSetter.java   |   42 +
 .../darwin/jmodeltest/utilities/ModelDef.java      |   60 +
 .../jmodeltest/utilities/MyTableCellRenderer.java  |   87 +
 .../darwin/jmodeltest/utilities/MyTableModel.java  |  292 ++++
 .../jmodeltest/utilities/PrintUtilities.java       |  101 ++
 .../darwin/jmodeltest/utilities/Simulation.java    |  491 ++++++
 .../darwin/jmodeltest/utilities/TableMap.java      |   91 +
 .../darwin/jmodeltest/utilities/TableSorter.java   |  326 ++++
 .../darwin/jmodeltest/utilities/Utilities.java     |  489 ++++++
 CHANGELOG => src/main/resources/CHANGELOG          |    6 +
 src/main/resources/COPYING                         |  621 +++++++
 INSTALL => src/main/resources/INSTALL              |    0
 README => src/main/resources/README                |    2 +-
 src/main/resources/THIRDPARTYLICENSES              |  576 ++++++
 {conf => src/main/resources/conf}/jmodeltest.conf  |    0
 .../uvigo/darwin/jmodeltest/gui/icons/JMT24.gif    |  Bin
 .../uvigo/darwin/jmodeltest/gui/icons/JMT48.gif    |  Bin
 .../uvigo/darwin/jmodeltest/gui/icons/JMT96.gif    |  Bin
 .../uvigo/darwin/jmodeltest/gui/icons/Open16.gif   |  Bin
 .../uvigo/darwin/jmodeltest/gui/icons/Open24.gif   |  Bin
 .../main/resources/example-data}/18S_insects2.nex  |    0
 .../main/resources/example-data}/Birds.nex         |    0
 .../main/resources/example-data}/HIV_vpu.ref2.fas  |    0
 .../main/resources/example-data}/HIVpol.groupM.nex |    0
 .../main/resources/example-data}/Hex_EF1a.nex      |    0
 .../main/resources/example-data}/aP6.fas           |    0
 .../main/resources/example-data}/aP6.phy           |    0
 .../main/resources/example-data}/channa.nex        |    0
 .../main/resources/example-data}/data.phy          |    0
 .../main/resources/example-data}/example.nex       |    0
 .../resources/example-data}/gusanos16S.mafft.fas   |    0
 .../resources/example-data}/gusanosCOI.mafft.fas   |    0
 .../main/resources/example-data}/primate-mtDNA.nex |    0
 .../main/resources/example-data}/rodents.nex       |    0
 src/main/resources/exe/phyml/README                |   10 +
 .../resources/extra}/filecluster8.conf.template    |    0
 {extra => src/main/resources/extra}/machines       |    0
 src/main/resources/extra/mpj.tar.gz                |  Bin 0 -> 3293593 bytes
 .../main/resources/resources}/template/index.html  |    0
 .../resources}/template/resources/homeIcon.gif     |  Bin
 .../resources}/template/resources/logo0.png        |  Bin
 .../resources}/template/resources/style.css        |    0
 .../resources}/template/resources/topIcon.gif      |  Bin
 .../main/resources/runjmodeltest-cluster.sh        |    0
 .../main/resources/runjmodeltest-gui.bat           |    0
 .../main/resources/runjmodeltest-gui.sh            |    0
 {trees => src/main/resources/trees}/aP6.tree       |    0
 {trees => src/main/resources/trees}/aP6b.tree      |    0
 132 files changed, 25663 insertions(+), 20 deletions(-)

diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000..0a5c629
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,2 @@
+syntax: glob
+build
diff --git a/INSTALL b/INSTALL
index 751f3e7..81a5000 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,26 +1,16 @@
 Basic Installation
 ==================
 
-No proper installation is required. However, you should keep in mind the following:
+1. Requirements:
 
-1. Decompress the tarball
+* Apache ant 
+	http://ant.apache.org/manual/install.html
+* Java JDK 1.6 
+	http://www.java.com/en/download
 
-   Your OS might allow you to execute jar files directly from the compressed file.
-   However, this will probably lead to errors if PhyML binaries cannot be executed
-   or temporary files cannot be created.
+2. In a command-line window type:
 
-   In Linux/OS X from command console:
+$ cd $JMODELTEST_HOME
+$ ant jar
 
-      $ tar zvxf jmodeltest-2.1.x-yyyymmdd.tar.gz
-
-2. GUI: Run jModelTest.jar, either double clicking or from a command console:
-
-      $ cd $JMODELTEST_HOME
-      $ java -jar jModelTest.jar
-
-3. COMMAND LINE: Run jModelTest.jar with -help argument for information about the
-   arguments:
-
-      $ java -jar jModelTest.jar -help
-
-4. Check the README file or the pdf manual (available at the homepage)
+3. The distribution will be built in $JMODELTEST_HOME/dist/
diff --git a/Manifest b/Manifest
new file mode 100644
index 0000000..eb461eb
--- /dev/null
+++ b/Manifest
@@ -0,0 +1,5 @@
+Main-Class: es.uvigo.darwin.jmodeltest.ModelTest
+Class-Path: lib/appframework-1.0.3.jar lib/prottest-3.4.1.jar lib/mpj.
+ jar lib/pal.jar lib/alter.jar lib/swing-worker-1.1.jar.
+ jar lib/freemarker.jar lib/BrowserLauncher2-all-1_3.
+ jar lib/jfreechart-1.0.14.jar lib/jcommon-1.0.17.jar
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..eaaeb0f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,55 @@
+# jmodeltest2
+
+jModelTest is a tool to carry out statistical selection of best-fit models of nucleotide substitution. It implements five different model selection strategies: hierarchical and dynamical likelihood ratio tests (hLRT and dLRT), Akaike and Bayesian information criteria (AIC and BIC), and a decision theory method (DT). It also provides estimates of model selection uncertainty, parameter importances and model-averaged parameter estimates, including model-averaged tree topologies. jModelTest  [...]
+
+--------
+Download
+--------
+
+New distributions of jModelTest will be hosted in google drive: https://drive.google.com/folderview?id=0ByrkKOPtF_n_OUs3d0dNcnJPYXM#list
+
+--------
+NEWS!
+--------
+
+20/02/2015 - New revision Fixed minor bug in console version. NNI tree search operation was taken as default for ML starting tree, instead of BEST.
+
+20/11/2014 - New revision Fixed some bugs with Windows OS
+
+03/09/2014 - New revision Added --set-local-config and --set-property arguments.
+
+26/08/2014 - New revision Fixed bug with -O argument (hypothesis order for hLRT).
+
+06/08/2014 - New revision Added checkpointing feature and confirmation on run cancel.
+
+05/04/2014 - New revision Added PAUP* block to log files. Fixed bug with DT criterion. Check the whole revision updates at the wiki.
+
+05/06/2013 - New revision Fixed bug with PAUP* block. Added argument for forwarding standard output to a file.
+
+03/01/2013 - New revision Fixed bug with paths including whitespaces. New binaries distribution also includes updated PhyML binaries with a much better performance.
+
+01/08/2012 - The jModelTest paper has been published: Darriba D, Taboada GL, Doallo R, Posada D. 2012. jModelTest 2: more models, new heuristics and parallel computing. Nature Methods 9: 772. Although the main text is quite short, it comes with 15 pages of supplementary material!
+
+--------
+Citation
+--------
+
+When using jModelTest you should cite all these:
+
+Darriba D, Taboada GL, Doallo R, Posada D. 2012. jModelTest 2: more models, new heuristics and parallel computing. Nature Methods 9(8), 772.
+
+Guindon S and Gascuel O (2003). A simple, fast and accurate method to estimate large phylogenies by maximum-likelihood". Systematic Biology 52: 696-704.
+
+--------
+Discussion group
+--------
+
+Please use the jModelTest discussion group for any question: http://groups.google.com/group/jmodeltest
+
+--------
+Disclaimer
+--------
+
+This program 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have rec [...]
+
+These programs are protected by their own license and conditions, and using jModelTest implies agreeing with those conditions as well. 
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..9912efd
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="jModelTest" default="jar" basedir=".">
+
+	<property name="src.dir" location="src/main/java" />
+	<property name="bin.dir" location="build/classes" />
+	<property name="lib.dir" location="lib" />
+	<property name="dist.dir" location="dist" />
+  <property name="exe.dir" location="${dist.dir}/exe/phyml" />
+	<property name="log.dir" location="${dist.dir}/log" />
+	<property name="manual.dir" location="manual" />
+	<property name="src.resources.dir" location="src/main/resources" />
+	<property name="html.template.dir" location="${src.resources.dir}/resources" />
+
+	<property name="jarfile" location="${dist.dir}/${ant.project.name}.jar" />
+	<property name="compile.debug" value="false" />
+
+	<fileset id="lib.jars" dir="${lib.dir}">
+		<include name="**/*.jar" />
+	</fileset>
+
+	<path id="lib.path">
+		<fileset refid="lib.jars" />
+	</path>
+
+	<!-- Stub install target.  Install should depend on the 'jar' target,
+         and copy the built objects to the 'dist' directory. -->
+	<target name="install" description="Install jar" depends="jar">
+	</target>
+
+	<target name="compile" description="Compile code">
+		<mkdir dir="${bin.dir}" />
+		<mkdir dir="${lib.dir}" />
+		<property environment="env" />
+		<property name="java6.boot.classpath" value="${env.JAVA6_BOOTCLASSES}" />
+		<javac srcdir="${src.dir}" destdir="${bin.dir}" includeAntRuntime="no" 
+			target="1.6" source="1.6" bootclasspath="${java5.boot.classpath}"
+			classpathref="lib.path" debug="${compile.debug}">
+			<compilerarg value="-Xlint:all"/>
+		</javac>
+		<copy todir="${bin.dir}/es">
+			<fileset dir="${src.resources.dir}/es" includes="**/*.xml,**/*.properties,**/*.gif,**/*.ico" />
+		</copy>
+
+	</target>
+
+	<target name="jar" depends="compile" description="Build jar">
+		<mkdir dir="${dist.dir}" />
+		<jar jarfile="${jarfile}" basedir="${bin.dir}" manifest="Manifest">
+			<!-- Merge library jars into final jar file
+            <zipgroupfileset refid="lib.jars"/>-->
+		</jar>
+		<mkdir dir="${dist.dir}/lib" />
+		<copy todir="${dist.dir}/lib">
+			<fileset id="lib.jars" dir="${lib.dir}">
+				<include name="**/*.jar" />
+			</fileset>
+		</copy>
+		<copy todir="${dist.dir}">
+			<fileset dir="${src.resources.dir}">
+				<include name="**/*" />
+			</fileset>
+		</copy>
+		<mkdir dir="${log.dir}" />
+		<chmod perm="755" dir="${dist.dir}" includes="*.sh *.bat" />
+    <chmod perm="644" dir="${exe.dir}" includes="*" />
+	</target>
+
+	<target name="run" depends="jar" description="Run jar file">
+		<java jar="${jarfile}" fork="yes" failonerror="true" />
+	</target>
+
+	<target name="clean" description="Remove build and dist directories">
+		<delete dir="${bin.dir}" />
+		<delete dir="${dist.dir}" />
+		<delete dir="${manual.dir}" includes="*.aux *.bbl *.out *.toc *.log *.blg *.dvi" />
+	</target>
+</project>
diff --git a/lib/BrowserLauncher2-all-1_3.jar b/lib/BrowserLauncher2-all-1_3.jar
deleted file mode 100644
index 5e062c7..0000000
Binary files a/lib/BrowserLauncher2-all-1_3.jar and /dev/null differ
diff --git a/lib/readseq.jar b/lib/readseq.jar
deleted file mode 100644
index 9d362e1..0000000
Binary files a/lib/readseq.jar and /dev/null differ
diff --git a/manual/biblio.bib b/manual/biblio.bib
new file mode 100644
index 0000000..9a3b6cc
--- /dev/null
+++ b/manual/biblio.bib
@@ -0,0 +1,370 @@
+ at article{Abdo-2005,
+   author = "Z. Abdo and V.N. Minin and P. Joyce and J. Sullivan",
+   title = "Accounting for uncertainty in the tree topology has little effect on the decision-theoretic approach to model selection in phylogeny estimation",
+   year = "2005",
+   volume = "22",
+   pages = "691--703",
+   journal = "Molecular Biology and Evolution",
+}
+
+ at article{Akaike-1974,
+   author = "H. Akaike",
+   title = "A new look at the statistical model identification",
+   year = "1974",
+   volume = "19",
+   pages = "716--723",
+   journal = "IEEE Transactions on Automatic Control",
+}
+
+ at article{Alfaro-2006",
+   author = "M.E. Alfaro and J.P. Huelsenbeck",
+   title = "Comparative performance of Bayesian and AIC-based measures of phylogenetic model uncertainty",
+   year = "2006",
+   volume = "55",
+   pages = "89--96",
+   journal = "Systematic Biology",
+}
+
+ at article{Burnham-2003,
+   author = "K.P. Burnham and D.R. Anderson",
+   title = "Model selection and multimodel inference: a practical information-theoretic approach",
+   year = "2003",
+   journal = "Springer-Verlag, New York, NY",
+}
+
+ at article{Burnham-1998,
+   author = "K.P. Burnham and D.R. Anderson",
+   title = "Model selection and inference: a practical information-theoretic approach",
+   year = "1998",
+   journal = "Springer-Verlag, New York, NY",
+}
+
+ at article{Felsenstein-1988,
+   author = "J. Felsenstein",
+   title = "Phylogenies from molecular sequences: inference and reliability",
+   year = "1988",
+   volume = "22",
+   pages = "521--565",
+   journal = "Annual Review of Genetics",
+}
+
+ at article{Felsenstein-1981,
+   author = "J. Felsenstein",
+   title = "Evolutionary trees from DNA sequences: A maximum likelihood approach",
+   year = "1981",
+   volume = "17",
+   pages = "368--376",
+   journal = "Journal of Molecular Evolution",
+}
+
+ at article{Felsenstein-2005,
+   author = "J. Felsenstein",
+   title = "PHYLIP (Phylogeny Inference Package)",
+   year = "2005",
+   journal = "Department of Genome Sciences, University of Washington, Seattle",
+}
+
+ at article{Gascuel-1997,
+   author = "O. Gascuel",
+   title = "BIONJ: an improved version of the NJ algorithm based on a simple model of sequence data",
+   year = "1997",
+   volume = "14",
+   pages = "685--695",
+   journal = "Molecular Biology and Evolution",
+}
+
+ at article{Gilbert-2007,
+   author = "D. Gilbert",
+   title = "ReadSeq",
+   year = "2007",
+   journal = "Indiana University, Bloomington",
+}
+
+ at article{Goldman-1993a,
+   author = "N. Goldman",
+   title = "Simple diagnostic statistical test of models of DNA substitution",
+   year = "1993",
+   volume = "37",
+   pages = "650--661",
+   journal = "Journal of Molecular Evolution",
+}
+
+ at article{Goldman-1993b,
+   author = "N. Goldman",
+   title = "Statistical tests of models of DNA substitution",
+   year = "1993",
+   volume = "36",
+   pages = "182--198",
+   journal = "Journal of Molecular Evolution",
+}
+
+ at article{Goldman-2000,
+   author = "N. Goldman and S. Whelan",
+   title = "Statistical tests of gamma-distributed rate heterogeneity in models of sequence evolution in phylogenetics",
+   year = "2000",
+   volume = "17",
+   pages = "975--978",
+   journal = "Molecular Biology and Evolution",
+}
+
+ at article{Guindon-2003,
+   author = "S. Guindon and O. Gascuel",
+   title = "A simple, fast, and accurate algorithm to estimate large phylogenies by maximum likelihood",
+   year = "2003",
+   volume = "52",
+   pages = "696--704",
+   journal = "Systematic Biology",
+}
+
+ at article{Hasegawa-1985,
+   author = "M. Hasegawa and K. Kishino and T. Yano",
+   title = "Dating the human-ape splitting by a molecular clock of mitochondrial DNA",
+   year = "1985",
+   volume = "22",
+   pages = "160--174",
+   journal = "Journal of Molecular Evolution",
+}
+
+ at article{Hoeting-1999,
+   author = "J.A. Hoeting and D. Madigan and A.E. Raftery",
+   title = "Bayesian model averaging: A tutorial",
+   year = "1999",
+   volume = "14",
+   pages = "382--417",
+   journal = "Statistical Science",
+}
+
+ at article{Huelsenbeck-2004,
+   author = "J. Huelsenbeck and B. Larget and M.E. Alfaro",
+   title = "Bayesian Phylogenetic Model Selection Using Reversible Jump Markov Chain Monte Carlo",
+   year = "2004",
+   volume = "21",
+   pages = "1123--1133",
+   journal = "Molecular Biology and Evolution",
+}
+
+ at article{Hurvich-1989,
+   author = "C.M. Hurvich and C.L. Tsai",
+   title = "Regression and time series model selection in small samples",
+   year = "1989",
+   volume = "76",
+   pages = "297--307",
+   journal = "Biometrika",
+}
+
+ at article{Johnson-2003,
+   author = "J.B. Johnson and K.S. Omland",
+   title = "Model selection in ecology and evolution",
+   year = "2003",
+   volume = "19",
+   pages = "101--108",
+   journal = "Trends in Ecology and Evolution",
+}
+
+ at article{Jukes-1969,
+   author = "T.H. Jukes and C.R. Cantor",
+   title = "Evolution of protein molecules",
+   year = "1969",
+   pages = "21--132",
+   journal = "Academic Press, New York, NY",
+}
+
+ at article{Kendall-1979,
+   author = "M. Kendall and A. Stuart",
+   title = "The Advanced Theory of Statistics",
+   year = "1979",
+   journal = "Charles Griffin, London",
+}
+
+ at article{Kimura-1981,
+   author = "M. Kimura",
+   title = "Estimation of evolutionary distances between homologous nucleotide sequences",
+   year = "1981",
+   volume = "78",
+   pages = "454--458",
+   journal = "Proceedings of the National Academy of Sciences, U.S.A",
+}
+
+ at article{Kimura-1980,
+   author = "M. Kimura",
+   title = "A simple method for estimating evolutionary rate of base substitutions through comparative studies of nucleotide sequences",
+   year = "1980",
+   volume = "16",
+   pages = "111--120",
+   journal = "Journal of Molecular Evolution",
+}
+
+ at article{Kullback-1951,
+   author = "S. Kullback, R.A. Leibler",
+   title = "On information and sufficiency",
+   year = "1951",
+   volume = "22",
+   pages = "79--86",
+   journal = "Annals of Mathematical Statistics",
+}
+
+ at article{Madigan-1994,
+   author = "D.M. Madigan and A.E. Raftery",
+   title = "Model selection and accounting for model uncertainty in graphical models using Occam's Window",
+   year = "1994",
+   volume = "59",
+   pages = "1335--1346",
+   journal = "Journal of the American Statistical Association",
+}
+
+ at article{Minin-2003,
+   author = "V. Minin and Z. Abdo and P. Joyce, J. Sullivan",
+   title = "Performance-based selection of likelihood models for phylogeny estimation",
+   year = "2003",
+   volume = "52",
+   pages = "674--683",
+   journal = "Systematic Biology",
+}
+
+ at article{Ohta-1992,
+   author = "T. Ohta",
+   title = "Theoretical study of near neutrality. II. Effect of subdivided population structure with local extinction and recolonization",
+   year = "1992",
+   pages = "917--923",
+   journal = "Genetics",
+}
+
+ at article{Pol-2004,
+   author = "D. Pol",
+   title = "Empirical problems of the hierarchical likelihood ratio test for model selection",
+   year = "2004",
+   volume = "53",
+   pages = "949--962",
+   journal = "Systematic Biology",
+}
+
+ at article{Posada-2001,
+   author = "D. Posada",
+   title = "The effect of branch length variation on the selection of models of molecular evolution",
+   year = "2001",
+   volume = "53",
+   pages = "434--444",
+   journal = "Journal of Molecular Evolution",
+}
+
+ at article{Posada-2003,
+   author = "D. Posada",
+   title = "Using Modeltest and PAUP to select a model of nucleotide substitution",
+   year = "2003",
+   pages = "6.5.1-6.5.14",
+}
+
+ at article{Posada-2004,
+   author = "D. Posada and T.R. Buckley",
+   title = "Model selection and model averaging in phylogenetics: advantages of Akaike Information Criterion and Bayesian approaches over likelihood ratio tests",
+   year = "2004",
+   volume = "53",
+   pages = "793--808",
+   journal = "Systematic Biology",
+}
+
+ at article{Posada-2001a,
+   author = "D. Posada and K. Crandall",
+   title = "Selecting the best-fit model of nucleotide substitution",
+   year = "2001",
+   volume = "50",
+   pages = "580--601",
+   journal = "Systematic Biology",
+}
+
+ at article{Posada-2001b,
+   author = "D. Posada and K. Crandall",
+   title = "Selecting models of nucleotide substitution: an application to human immunodeficiency virus 1 (HIV-1)",
+   year = "2001",
+   volume = "18",
+   pages = "897--906",
+   journal = "Molecular Biology and Evolution",
+}
+
+ at article{Raftery-1996,
+   author = "A.E. Raftery",
+   title = "Hypothesis testing and model selection",
+   year = "1996",
+   pages = "163--187",
+   journal = "Markov chain Monte Carlo in practice. Chapman and Hall, London",
+}
+
+ at article{Schwarz-1978,
+   author = "G. Schwarz",
+   title = "Estimating the dimension of a model",
+   year = "1978",
+   volume = "6",
+   pages = "461--464",
+   journal = "The Annals of Statistics",
+}
+ 
+ at article{Sugiura-1978,
+   author = "N. Sugiura",
+   title = "Further analysis of the data by Akaike's information criterion and the finite corrections",
+   year = "1978",
+   volume = "A7",
+   pages = "13--26",
+   journal = "Communications in Statistics–Theory and Methods",
+}
+
+ at article{Sullivan-2005,
+   author = "J. Sullivan and P. Joyce",
+   title = "Model selection in phylogenetics",
+   year = "2005",
+   volume = "36",
+   pages = "445--466",
+   journal = "Annual Review of Ecology, Evolution and Systematics",
+}
+    
+ at article{Tamura-1993,
+   author = "K. Tamura and M. Nei",
+   title = "Estimation of the number of nucleotide substitutions in the control region of mitochondrial DNA in humans and chimpanzees",
+   year = "1993",
+   volume = "10",
+   pages = "512--526",
+   journal = "Molecular Biology and Evolution",
+}
+ 
+ at article{Tavare-1986,
+   author = "S. Tavar\'e",
+   title = "Some probabilistic and statistical problems in the analysis of DNA sequences",
+   year = "1986",
+   pages = "57--86",
+   journal = "Some mathematical questions in biology - DNA sequence analysis. Amer. Math. Soc., Providence, RI",
+}
+
+ at article{Wasserman-2000,
+   author = "L. Wasserman",
+   title = "Bayesian Model Selection and Model Averaging",
+   year = "2000",
+   volume = "44",
+   pages = "92--107",
+   journal = "Journal of Mathematical Psychology 44:92-107",
+}
+
+ at article{Whelan-1999,
+   author = "S. Whelan and N. Goldman",
+   title = "Distributions of statistics used for the comparison of models of sequence evolution in phylogenetics",
+   year = "1999",
+   volume = "16",
+   pages = "1292--1299",
+   journal = "Molecular Biology and Evolution",
+}
+
+ at article{Yang-1995,
+   author = "Z. Yang and N. Goldman and A.Friday",
+   title = "Maximum likelihood trees from DNA sequences: a peculiar statistical estimation problem",
+   year = "1995",
+   volume = "44",
+   pages = "384--399",
+   journal = "Systematic Biology",
+}
+
+ at article{Zharkikh-1994,
+   author = "A. Zharkikh",
+   title = "Estimation of evolutionary distances between nucleotide sequences",
+   year = "1994",
+   volume = "39",
+   pages = "315--329",
+   journal = "Journal of Molecular Evolution",
+}
diff --git a/manual/images/bic.pdf b/manual/images/bic.pdf
new file mode 100644
index 0000000..5778f1b
Binary files /dev/null and b/manual/images/bic.pdf differ
diff --git a/manual/images/consensus.pdf b/manual/images/consensus.pdf
new file mode 100644
index 0000000..9fd7404
Binary files /dev/null and b/manual/images/consensus.pdf differ
diff --git a/manual/images/dLRT.png b/manual/images/dLRT.png
new file mode 100644
index 0000000..ea7e3a7
Binary files /dev/null and b/manual/images/dLRT.png differ
diff --git a/manual/images/hLRT.png b/manual/images/hLRT.png
new file mode 100644
index 0000000..7442801
Binary files /dev/null and b/manual/images/hLRT.png differ
diff --git a/manual/images/html-log.pdf b/manual/images/html-log.pdf
new file mode 100644
index 0000000..276e106
Binary files /dev/null and b/manual/images/html-log.pdf differ
diff --git a/manual/images/lkl-settings.pdf b/manual/images/lkl-settings.pdf
new file mode 100644
index 0000000..f380d3c
Binary files /dev/null and b/manual/images/lkl-settings.pdf differ
diff --git a/manual/images/main-window.pdf b/manual/images/main-window.pdf
new file mode 100644
index 0000000..ddfdf0f
Binary files /dev/null and b/manual/images/main-window.pdf differ
diff --git a/manual/images/results.pdf b/manual/images/results.pdf
new file mode 100644
index 0000000..0a344a5
Binary files /dev/null and b/manual/images/results.pdf differ
diff --git a/manual/manual.tex b/manual/manual.tex
new file mode 100644
index 0000000..62bc31e
--- /dev/null
+++ b/manual/manual.tex
@@ -0,0 +1,360 @@
+\documentclass[11pt,twoside,a4paper]{article}
+\usepackage{pslatex,palatino,avant,graphicx}
+\usepackage[usenames,dvipsnames]{color}
+\usepackage[margin=2cm]{geometry}
+\usepackage{url}
+\usepackage[square,sort]{natbib}
+
+\usepackage{listings}
+\lstset{ %
+  backgroundcolor=\color{white},   % choose the background color; you must add \usepackage{color} or \usepackage{xcolor}
+  basicstyle=\footnotesize,        % the size of the fonts that are used for the code
+  breakatwhitespace=false,         % sets if automatic breaks should only happen at whitespace
+  breaklines=true,                 % sets automatic line breaking
+  captionpos=b,                    % sets the caption-position to bottom
+  commentstyle=\color{LimeGreen},  % comment style
+  % deletekeywords={...},            % if you want to delete keywords from the given language
+  escapeinside={\%*}{*)},          % if you want to add LaTeX within your code
+  extendedchars=true,              % lets you use non-ASCII characters; for 8-bits encodings only, does not work with UTF-8
+  frame=single,                    % adds a frame around the code
+  keepspaces=true,                 % keeps spaces in text, useful for keeping indentation of code (possibly needs columns=flexible)
+  keywordstyle=\color{BlueGreen},  % keyword style
+  % language=Java,                   % the language of the code
+  % numbers=left,                    % where to put the line-numbers; possible values are (none, left, right)
+  % numbersep=5pt,                   % how far the line-numbers are from the code
+  % numberstyle=\tiny\color{Gray},   % the style that is used for the line-numbers
+  rulecolor=\color{black},         % if not set, the frame-color may be changed on line-breaks within not-black text (e.g. comments (green here))
+  showspaces=false,                % show spaces everywhere adding particular underscores; it overrides 'showstringspaces'
+  showstringspaces=false,          % underline spaces within strings only
+  showtabs=false,                  % show tabs within strings adding particular underscores
+  stepnumber=2,                    % the step between two line-numbers. If it's 1, each line will be numbered
+  stringstyle=\color{RubineRed},   % string literal style
+  tabsize=2,                       % sets default tabsize to 2 spaces
+  title=\lstname,                  % show the filename of files included with \lstinputlisting; also try caption instead of title
+  aboveskip=1em,
+  belowcaptionskip=0em,
+  belowskip=0em
+}
+
+\usepackage{hyperref}
+\hypersetup{
+    colorlinks,
+    citecolor=Violet,
+    filecolor=black,
+    linkcolor=MidnightBlue,
+    urlcolor=MidnightBlue
+}
+
+\begin{document}
+\providecommand{\versionnumber}{0.1.1}
+\title{jModelTest 2.0 Manual v\versionnumber}
+\author{Diego Darriba, David Posada}
+\date{\today}
+\maketitle
+
+\setcounter{tocdepth}{2}
+\tableofcontents
+
+\section{Overview}
+
+jModelTest is a tool to carry out statistical selection of best-fit models of nucleotide substitution. It implements five different model selection strategies: hierarchical and dynamical likelihood ratio tests (hLRT and dLRT), Akaike and Bayesian information criteria (AIC and BIC), and a decision theory method (DT). It also provides estimates of model selection uncertainty, parameter importances and model-averaged parameter estimates, including model-averaged tree topologies. jModelTest  [...]
+
+\subsection{Download}
+
+The main project webpage is located at google code: \url{http://code.google.com/p/jmodeltest2}.
+
+Google Code downloads are now longer available. New distributions of jModelTest will be hosted in google drive.
+
+Online help is available at: \url{http://code.google.com/p/jmodeltest2/w/list}.
+
+Please use the jModelTest discussion group for any question: \url{http://groups.google.com/group/jmodeltest}.
+
+\subsection{Citation}
+
+When using jModelTest you should cite all these:
+
+\begin{itemize}
+\item Darriba D, Taboada GL, Doallo R, Posada D. 2012. jModelTest 2: more models, new heuristics and parallel computing. Nature Methods 9(8), 772.
+\item Guindon S and Gascuel O (2003). A simple, fast and accurate method to estimate large phylogenies by maximum-likelihood". Systematic Biology 52: 696-704. 
+\end{itemize}
+
+\subsection{Disclaimer}
+
+This program 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have rec [...]
+
+These programs are protected by their own license and conditions, and using jModelTest implies agreeing with those conditions as well. 
+
+\subsection{Updates}
+
+\begin{itemize}
+
+  \item 20 Oct 2015 - Version 2.1.8
+
+  \begin{itemize}
+    \item Removed ReadSeq dependency
+    \item Fixed warnings
+    \item Updated prottest jarfile to v3.4
+  \end{itemize}
+
+	\item 20 Feb 2015 - Version 2.1.7
+
+	\begin{itemize}
+  		\item Fixed bug in ML tree search operation. Console version was using NNI moves instead of "BEST" by default.
+	\end{itemize}
+
+	\item 20 Nov 2014 - Version 2.1.7
+
+	\begin{itemize}
+		\item Fixed bug with special characters in paths
+		\item Added initial check of PhyML binaries
+		\item Added notification in case AICc produces negative values
+	\end{itemize}
+
+	\item 06 Aug 2014 - Version 2.1.6
+
+	\begin{itemize}
+		\item Added confirmation window when cancelling running jobs in the GUI
+		\item Added automatic checkpointing files generation
+		\item Added ``-ckp'' argument for loading checkpointing files
+	\end{itemize}
+
+	\item 05 Apr 2014 - Version 2.1.5
+
+	\begin{itemize}
+		\item Updated OS X binary
+		\item Fixed bug with computation of JC model for ``fixed'' topology
+		\item Fixed bug with DT criterion computation
+		\item Added ``-n'' argument for naming executions (the name is included in the log filenames)
+		\item Added ``-getphylip'' argument for converting alignments into PHYLIP format with ALTER
+		\item Fixed bug in PhyML logging in GUI. Added a unique ID for every model in the log file
+		\item Added PAUP* block into log files if required (``-w'' argument)
+		\item Added more verbose error messages 
+	\end{itemize}
+
+	\item 10 Jul 2013 - Version 2.1.4
+
+	\begin{itemize}
+		\item Added phyml auto-logging.
+		\item Added phyml command lines for best-fit models.
+		\item Added phyml log tab in the GUI.
+		\item Removed sample size modes (and ``-n'' argument). Sample size is fixed to alignment size.
+		\item Fixed bug with relative paths when calling from a different path.
+		\item Fixed typos in the GUI. 
+	\end{itemize}
+
+	\item 05 Mar 2013 - Version 2.1.3
+
+	\begin{itemize}
+		\item Fixed bug with PAUP`*` command block.
+		\item Added the possibility to change Inforation Criterion used with the clustering algorithm for the 203 matrices.
+		\item Changed ``-o'' argument for the hypothesis order into ``-O''
+		\item Added ``-o'' argument for forwarding the standard output to a file: -o FILENAME 
+	\end{itemize}
+
+	\item 01 Jan 2013 Version 2.1.2 - Revision 20130103
+
+	\begin{itemize}
+		\item Fixed bug in paths with whitespaces.
+		\item Updated PhyML binaries. 
+	\end{itemize}
+
+	\item 31 Jul 2012 Version 2.1.1 - Revision 20120731
+
+	\begin{itemize}
+		\item Fixed bug with hLRT selection when attempting to use a user-defined topology. 
+	\end{itemize}
+
+	\item 11 Mar 2012 Version 2.1 - Revision 20120511
+
+	\begin{itemize}
+		\item Major updates:
+		\begin{itemize}
+			\item Exhaustive GTR submodels: All the 203 different partitions of the GTR rate matrix can be included in the candidate set of models. When combined with rate variation (+I,+G, +I+G) and equal/unequal base frequencies the total number of possible models is 203 x 8 = 1624. 
+			\item Hill climbing hierarchical clustering: Calculating the likelihood score for a large number of models can be extremely time-consuming. This hill-climbing algorithm implements a hierarchical clustering to search for the best-fit models within the full set of 1624 models, but optimizing at most 288 models while maintaining model selection accuracy. 
+			\item Heuristic filtering: Heuristic reduction of the candidate models set based on a similarity filtering threshold among the GTR rates and the estimates of among-site rate variation. 
+			\item Absolute model fit: Information criterion distances can be calculated for the best-fit model against the unconstrained multinomial model (based on site pattern frequencies). This is computed by default when the alignment does not contain missing data/ambiguities, but can also be approximated otherwise. 
+			\item Topological summary: Tree topologies supported by the different candidate models are summarized in the html log, including confidence intervals constructed from cumulative models weights, plus Robinson-Foulds and Euclidean distances to the best-fit tree for each. 
+		\end{itemize}
+		\item Minor updates:
+		\begin{itemize}
+			\item Corrected a bug in the fixed BIONJ-JC starting topology. F81+I+G was executed instead of JC.
+			\item ``Best'' is now the default tree search operation instead of NNI. ``Best'' computes both NNI and SPR algorithms and selects the best of them.
+			\item User can select the number of threads from GUI. 
+		\end{itemize}
+	\end{itemize}
+
+
+	\item 1 Feb 2012 - Version 2.0.2
+
+	\begin{itemize}
+		\item Added a selection summary at the end of the console output.
+		\item Corrected the table header in the DT results frame (sorting).
+		\item Corrected a bug in DT Criterion where selection could not take place with large alignments.
+		\item Corrected a bug with command console version, where the execution crashed with certain arguments.
+		\item Unified LOCALE for English format. 
+	\end{itemize}
+
+	\item 2 Nov 2011 - Version 2.0.1
+
+	\begin{itemize}
+		\item Improved thread scheduling algorithm.
+		\item OpenMP phyml patch for hybrid execution.
+		\item New argument (machinesfile) for hybrid execution on heterogeneous architectures, or heterogeneous resources distribution. 
+	\end{itemize}
+
+	\item 13 Oct 2011 - Revision 20111013
+
+	\begin{itemize}
+		\item Added conf/jmodeltest.conf file, where you can:
+			Enable/Disable the automatic logging:
+
+			    You might be running a huge dataset and you don't want to generate hundreds or thousands of log files. 
+
+			Set the PhyML binaries location:
+
+			    If you already have installed PhyML in your machine, you can setup jModelTest for use your own binaries. 
+
+		\item Enhanced the html log output. 
+	\end{itemize}
+
+\end{itemize}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\include{sec-quickstart}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{Graphical User Interface}
+\label{sec:gui}
+
+\subsection{Launching the Graphical User Interface}
+
+The main distribution includes a script for launching the interface,  \emph{runjmodeltest-gui.sh}, located under the jModelTest home folder. Other possibility is running the following command line:
+
+\begin{lstlisting}
+$ java -jar jModelTest.jar
+\end{lstlisting}
+
+Moreover, in Windows and MacOS X, it is often possible to double-click the jModelTest.jar file to launch the graphical interface.
+
+The following window will show on the screen:
+
+\begin{center}
+\includegraphics[width=.9\textwidth]{images/main-window}
+\end{center}
+
+\subsection{Menu description}
+
+\begin{minipage}{1\textwidth}
+\small
+\begin{tabular}{l l l l}
+\hline
+{\bf Menu} & {\bf Submenu} & {\bf Description} & {\bf Enabled} \\
+\hline
+File \\
+& Load alignment & Load an input alignment & \\
+& Load checkpoint file & Load a previous snapshot \footnote{See Section~\ref{sec:ckp}} & (i) \\
+& Quit & Exit the program & \\
+\hline
+Analysis \\
+& Compute likelihood scores & Optimize the set of candidate models & (i) \\
+& Do AIC calculations & Calculate Akaike Information Criterion & (ii) \\
+& Do BIC calculations & Calculate Bayesian Information Criterion & (ii) \\
+& Do DT calculations & Calculate Decision Theory & (ii) \\
+& Do hLRT calculations & Calculate hierarchical likelihood ratio test & (ii) \footnote{This test is only available for 3,5,7 and 11 substitution schemes and for fixed topologies (fixed BIONJ-JC tree or user-defined topology)} \\
+& Model-averaged phylogeny & Calculate the consensus tree & (iii \& iv)  \\
+\hline
+Results \\
+& Show results table & Show a table with the selection results & (ii) \\
+& Build HTML log & Create an html webpage with the results & (ii) \\
+\hline
+Tools \\
+& LRT calculator & Likelihood Ratio Test for nexted models & \\
+\hline
+\end{tabular}
+
+\vspace{1em}
+(i) After loading an alignment (ii) After computing the likelihood scores (iii) If the base tree is not fixed (iv) After calculating an Information Criterion
+\end{minipage}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\include{sec-arguments}
+\include{sec-config}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\section{Common Use Cases}
+
+\subsection{Converting Alignment Files}
+
+jModelTest accepts several input alignment file formats. However, it makes use of the ALTER library for converting them into PHYLIP format, accepted by PhyML. If you want to validate your alignment, you can convert it into PHYLIP format using the ``-getPhylip'' argument. It will generate a new file appending ``.phy'' to the input alignment filename, and exit afterwards.
+
+\begin{lstlisting}
+$ java -jar jModelTest -d example-data/aP6.fas -getPhylip
+\end{lstlisting}
+
+In case there is something wrong in the input file, it will exit with the description of the error.
+
+\subsection{Basic Model Selection}
+
+Although jModelTest have many options, most of the users would like to perform a model selection among the 11 substitution schemes, including models with unequal frequencies, gamma rate variation and a proportion of invariable sites. The following command produces this operation, shows the selection results under the 4 available criteria, computes the model-averaged phylogenies (``-a''), computes the parameters importance (``-v'' and ``-p'') and writes the PAUP* block for the best-fit mo [...]
+
+\begin{lstlisting}
+$ java -jar jModelTest -d example-data/aP6.fas -s 11 -f -i -g 4 -AIC -BIC -AICc -DT -p -a -w
+\end{lstlisting}
+
+Note that, by default, jModelTest uses Maximum-Likelihood topologies as the base trees for the model optimization, and checks both NNI and SPR algorithms for the topology search. This obtains the most accurate results, but it is also the most time consuming operation. According to the size of the input alignment, one can directly select one of the algorithms saving time in the computations. As a general rule, for a small number of taxa NNI algorithm would work better, as well as SPR is m [...]
+
+\subsection{Loading Checkpointing Files}
+\label{sec:ckp}
+
+By default, jModelTest saves ``.ckp'' checkpointing files in the log directory. In case of an error occurs, the user can start again the process minimizing the loss of computation. The user is in charge of selecting the checkpointing file and running again jModelTest with the same parameters of the previous execution. Otherwise the results might be wrong.
+
+For finding the correct checkpointing file, if the execution had a user-defined name ``-n argument'', the checkpoing file will have the following format: 
+
+\begin{lstlisting}
+log/[sequenceFileName].[executionName].ckp
+\end{lstlisting}
+
+For example, the following command:
+
+\begin{lstlisting}
+$ java -jar jModelTest -d example-data/aP6.fas -n myTest -s 11 -f -i -g 4 -BIC -AIC
+\end{lstlisting}
+
+Will generate the checkpointing file in \$JMODELTEST\_HOME/log/aP6.fas.myTest.ckp, and in case of a sudden error in the execution, it can be continued using:
+
+\begin{lstlisting}
+$ java -jar jModelTest -d example-data/aP6.fas -n myTest -s 11 -f -i -g 4 -BIC -AIC -ckp log/aP6.fas.myTest.ckp
+\end{lstlisting}
+
+If no execution name was provided, it is automatically generated according to the current date and time with the following format: yyyyMMddhhmmss (e.g., if current time is 17:05:00 August 3 2014, the execution name is 20140803170500, and the checkpointing generated file is:
+
+\begin{lstlisting}
+log/[sequenceFileName].20140803170500.ckp).
+\end{lstlisting}
+
+When using the GUI instead of the command console interface, the checkpointing file can be loaded using the menu item ``File/Load checkpoint file'', that becomes enabled right after loading the alignment.
+
+% \subsection{Finding the Best-fit Model for MrBayes Analysis}
+
+% One common question is how to set the best-fit model obtained with jModelTest into MrBayes. The 3 substitution schemes option covers those models implemented in MrBayes. From the command console, the 3 substitution schemes mode is selected by default, so just make sure you are not modifying it with the ``-s'' argument.
+
+From the GUI, one can choose between the different number of the substituion schemes in the execution settings window.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\include{sec-theory}
+
+
+\bibliographystyle{natbib}
+%\bibliographystyle{achemnat}
+%\bibliographystyle{plainnat}
+%\bibliographystyle{abbrv}
+%\bibliographystyle{bioinformatics}
+%\bibliographystyle{plain}
+\bibliography{biblio}
+
+\end{document}
diff --git a/manual/natbib.bst b/manual/natbib.bst
new file mode 100755
index 0000000..a679e1d
--- /dev/null
+++ b/manual/natbib.bst
@@ -0,0 +1,1288 @@
+%% 
+%% This is file `natbib.bst', generated 
+%% on <1994/9/16> with the docstrip utility (2.2h).
+%% 
+%% The original source files were:
+%% 
+%% genbst.mbs  (with options: `ay,nat,seq-lab,nm-rev,dt-beg,yr-par,vol-bf,
+%%                             volp-com,etal-it')
+%% ---------------------------------------- 
+%% *** Personal bib style, PWD *** 
+%% 
+%% (Here are the specifications of the source file)
+%% \ProvidesFile{genbst.mbs}[1994/09/16 1.5 (PWD)]
+%%   For use with BibTeX version 0.99a or later
+%%     and with LaTeX 2.09 or 2e
+%%-------------------------------------------------------------------
+%% NOTICE:
+%% This file may be used for non-profit purposes.
+%% It may not be distributed in exchange for money,
+%%   other than distribution costs.
+%%
+%% The author provides it `as is' and does not guarantee it in any way.
+%%
+%% Copyright (C) 1994 Patrick W. Daly
+%% Max-Planck-Institut f\"ur Aeronomie
+%% Postfach 20
+%% D-37189 Katlenburg-Lindau
+%% Germany
+%%
+%% E-mail:
+%% SPAN--     nsp::linmpi::daly    (note nsp also known as ecd1)
+%% Internet-- daly at linmpi.dnet.gwdg.de
+%%-----------------------------------------------------------
+%% \CharacterTable
+%%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+%%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+%%   Digits        \0\1\2\3\4\5\6\7\8\9
+%%   Exclamation   \!     Double quote  \"     Hash (number) \#
+%%   Dollar        \$     Percent       \%     Ampersand     \&
+%%   Acute accent  \'     Left paren    \(     Right paren   \)
+%%   Asterisk      \*     Plus          \+     Comma         \,
+%%   Minus         \-     Point         \.     Solidus       \/
+%%   Colon         \:     Semicolon     \;     Less than     \<
+%%   Equals        \=     Greater than  \>     Question mark \?
+%%   Commercial at \@     Left bracket  \[     Backslash     \\
+%%   Right bracket \]     Circumflex    \^     Underscore    \_
+%%   Grave accent  \`     Left brace    \{     Vertical bar  \|
+%%   Right brace   \}     Tilde         \~}
+%%---------------------------------------------------------------------
+ % This is an author-year citation style bibliography. As such, it is
+ % non-standard LaTeX, and requires a special package file to function properly.
+ % Such a package is    natbib.sty   by Patrick W. Daly
+ % The form of the \bibitem entries is
+ %   \bibitem[Jones et al.(1990)]{key}...
+ %   \bibitem[Jones et al.(1990)Jones, Baker, and Smith]{key}...
+ % The essential feature is that the label (the part in brackets) consists
+ % of the author names, as they should appear in the citation, with the year
+ % in parentheses following. There must be no space before the opening
+ % parenthesis!
+ % With natbib v5.3, a full list of authors may also follow the year.
+ % In natbib.sty, it is possible to define the type of enclosures that is
+ % really wanted (brackets or parentheses), but in either case, there must
+ % be parentheses in the label.
+ % The \cite command functions as follows:
+ %   \cite{key} ==>>                Jones et al. (1990)
+ %   \cite[]{key} ==>>              (Jones et al., 1990)
+ %   \cite[chap. 2]{key} ==>>       (Jones et al., 1990, chap. 2)
+ %   \cite[e.g.][]{key} ==>>        (e.g. Jones et al., 1990)
+ %   \cite[e.g.][p. 32]{key} ==>>   (e.g. Jones et al., p. 32)
+ %   \citeauthor{key}               Jones et al.
+ %   \citefullauthor{key}           Jones, Baker, and Smith
+ %   \citeyear{key}                 1990
+%%---------------------------------------------------------------------
+
+ENTRY
+  { address
+    author
+    booktitle
+    chapter
+    edition
+    editor
+    howpublished
+    institution
+    journal
+    key
+    month
+    note
+    number
+    organization
+    pages
+    publisher
+    school
+    series
+    title
+    type
+    volume
+    year
+  }
+  {}
+  { label extra.label sort.label }
+
+INTEGERS { output.state before.all mid.sentence after.sentence after.block }
+
+FUNCTION {init.state.consts}
+{ #0 'before.all :=
+  #1 'mid.sentence :=
+  #2 'after.sentence :=
+  #3 'after.block :=
+}
+
+STRINGS { s t }
+
+FUNCTION {output.nonnull}
+{ 's :=
+  output.state mid.sentence =
+    { ", " * write$ }
+    { output.state after.block =
+        { add.period$ write$
+          newline$
+          "\newblock " write$
+        }
+        { output.state before.all =
+            'write$
+            { add.period$ " " * write$ }
+          if$
+        }
+      if$
+      mid.sentence 'output.state :=
+    }
+  if$
+  s
+}
+
+FUNCTION {output}
+{ duplicate$ empty$
+    'pop$
+    'output.nonnull
+  if$
+}
+
+FUNCTION {output.check}
+{ 't :=
+  duplicate$ empty$
+    { pop$ "empty " t * " in " * cite$ * warning$ }
+    'output.nonnull
+  if$
+}
+
+FUNCTION {fin.entry}
+{ add.period$
+  write$
+  newline$
+}
+
+FUNCTION {new.block}
+{ output.state before.all =
+    'skip$
+    { after.block 'output.state := }
+  if$
+}
+
+FUNCTION {new.sentence}
+{ output.state after.block =
+    'skip$
+    { output.state before.all =
+        'skip$
+        { after.sentence 'output.state := }
+      if$
+    }
+  if$
+}
+
+FUNCTION {not}
+{   { #0 }
+    { #1 }
+  if$
+}
+
+FUNCTION {and}
+{   'skip$
+    { pop$ #0 }
+  if$
+}
+
+FUNCTION {or}
+{   { pop$ #1 }
+    'skip$
+  if$
+}
+
+FUNCTION {non.stop}
+{ duplicate$
+   "}" * add.period$
+   #-1 #1 substring$ "." =
+}
+
+FUNCTION {new.block.checkb}
+{ empty$
+  swap$ empty$
+  and
+    'skip$
+    'new.block
+  if$
+}
+
+FUNCTION {field.or.null}
+{ duplicate$ empty$
+    { pop$ "" }
+    'skip$
+  if$
+}
+
+FUNCTION {emphasize}
+{ duplicate$ empty$
+    { pop$ "" }
+    { "{\em " swap$ * non.stop
+        { "\/}" * }
+        { "}" * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {bolden}
+{ duplicate$ empty$
+    { pop$ "" }
+    { "{\bf " swap$ * "}" * }
+  if$
+}
+
+INTEGERS { nameptr namesleft numnames }
+
+FUNCTION {format.names}
+{ 's :=
+  #1 'nameptr :=
+  s num.names$ 'numnames :=
+  numnames 'namesleft :=
+    { namesleft #0 > }
+    { s nameptr
+      "{vv~}{ll}{, jj}{, f.}" format.name$ 't :=
+      nameptr #1 >
+        {
+          namesleft #1 >
+            { ", " * t * }
+            {
+              numnames #2 >
+                { "," * }
+                'skip$
+              if$
+              t "others" =
+                { " " * "et~al." emphasize * }
+                { " and " * t * }
+              if$
+            }
+          if$
+        }
+        't
+      if$
+      nameptr #1 + 'nameptr :=
+      namesleft #1 - 'namesleft :=
+    }
+  while$
+}
+
+FUNCTION {format.names.ed}
+{ 's :=
+  #1 'nameptr :=
+  s num.names$ 'numnames :=
+  numnames 'namesleft :=
+    { namesleft #0 > }
+    { s nameptr
+      "{f.~}{vv~}{ll}{, jj}"
+      format.name$ 't :=
+      nameptr #1 >
+        {
+          namesleft #1 >
+            { ", " * t * }
+            {
+              numnames #2 >
+                { "," * }
+                'skip$
+              if$
+              t "others" =
+                { " " * "et~al." emphasize * }
+                { " and " * t * }
+              if$
+            }
+          if$
+        }
+        't
+      if$
+      nameptr #1 + 'nameptr :=
+      namesleft #1 - 'namesleft :=
+    }
+  while$
+}
+
+FUNCTION {format.key}
+{ empty$
+    { key field.or.null }
+    { "" }
+  if$
+}
+
+FUNCTION {format.authors}
+{ author empty$
+    { "" }
+    { author format.names }
+  if$
+}
+
+FUNCTION {format.editors}
+{ editor empty$
+    { "" }
+    { editor format.names
+      editor num.names$ #1 >
+        { ", editors" * }
+        { ", editor" * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.in.editors}
+{ editor empty$
+    { "" }
+    { editor format.names.ed
+      editor num.names$ #1 >
+        { ", editors" * }
+        { ", editor" * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.title}
+{ title empty$
+    { "" }
+    { title "t" change.case$
+    }
+  if$
+}
+
+FUNCTION {format.full.names}
+{'s :=
+  #1 'nameptr :=
+  s num.names$ 'numnames :=
+  numnames 'namesleft :=
+    { namesleft #0 > }
+    { s nameptr
+      "{vv~}{ll}" format.name$ 't :=
+      nameptr #1 >
+        {
+          namesleft #1 >
+            { ", " * t * }
+            {
+              numnames #2 >
+                { "," * }
+                'skip$
+              if$
+              t "others" =
+                { " " * "et~al." emphasize * }
+                { " and " * t * }
+              if$
+            }
+          if$
+        }
+        't
+      if$
+      nameptr #1 + 'nameptr :=
+      namesleft #1 - 'namesleft :=
+    }
+  while$
+}
+
+FUNCTION {author.editor.key.full}
+{ author empty$
+    { editor empty$
+        { key empty$
+            { cite$ #1 #3 substring$ }
+            'key
+          if$
+        }
+        { editor format.full.names }
+      if$
+    }
+    { author format.full.names }
+  if$
+}
+
+FUNCTION {author.key.full}
+{ author empty$
+    { key empty$
+         { cite$ #1 #3 substring$ }
+          'key
+      if$
+    }
+    { author format.full.names }
+  if$
+}
+
+FUNCTION {editor.key.full}
+{ editor empty$
+    { key empty$
+         { cite$ #1 #3 substring$ }
+          'key
+      if$
+    }
+    { editor format.full.names }
+  if$
+}
+
+FUNCTION {make.full.names}
+{ type$ "book" =
+  type$ "inbook" =
+  or
+    'author.editor.key.full
+    { type$ "proceedings" =
+        'editor.key.full
+        'author.key.full
+      if$
+    }
+  if$
+}
+
+FUNCTION {output.bibitem}
+{ newline$
+  "\bibitem[" write$
+  label write$
+  ")" make.full.names * "]{" * write$
+  cite$ write$
+  "}" write$
+  newline$
+  ""
+  before.all 'output.state :=
+}
+
+FUNCTION {n.dashify}
+{ 't :=
+  ""
+    { t empty$ not }
+    { t #1 #1 substring$ "-" =
+        { t #1 #2 substring$ "--" = not
+            { "--" *
+              t #2 global.max$ substring$ 't :=
+            }
+            {   { t #1 #1 substring$ "-" = }
+                { "-" *
+                  t #2 global.max$ substring$ 't :=
+                }
+              while$
+            }
+          if$
+        }
+        { t #1 #1 substring$ *
+          t #2 global.max$ substring$ 't :=
+        }
+      if$
+    }
+  while$
+}
+
+FUNCTION {word.in}
+{ "In " }
+
+FUNCTION {format.date}
+{ year duplicate$ empty$
+    { "empty year in " cite$ * "; set to ????" * warning$
+       pop$ "????" }
+    'skip$
+  if$
+  before.all 'output.state :=
+  " (" swap$ * extra.label * ")" *
+}
+
+FUNCTION {format.btitle}
+{ title emphasize
+}
+
+FUNCTION {tie.or.space.connect}
+{ duplicate$ text.length$ #3 <
+    { "~" }
+    { " " }
+  if$
+  swap$ * *
+}
+
+FUNCTION {either.or.check}
+{ empty$
+    'pop$
+    { "can't use both " swap$ * " fields in " * cite$ * warning$ }
+  if$
+}
+
+FUNCTION {format.bvolume}
+{ volume empty$
+    { "" }
+    { "volume" volume tie.or.space.connect
+      series empty$
+        'skip$
+        { " of " * series emphasize * }
+      if$
+      "volume and number" number either.or.check
+    }
+  if$
+}
+
+FUNCTION {format.number.series}
+{ volume empty$
+    { number empty$
+        { series field.or.null }
+        { output.state mid.sentence =
+            { "number" }
+            { "Number" }
+          if$
+          number tie.or.space.connect
+          series empty$
+            { "there's a number but no series in " cite$ * warning$ }
+            { " in " * series * }
+          if$
+        }
+      if$
+    }
+    { "" }
+  if$
+}
+
+FUNCTION {format.edition}
+{ edition empty$
+    { "" }
+    { output.state mid.sentence =
+        { edition "l" change.case$ " edition" * }
+        { edition "t" change.case$ " edition" * }
+      if$
+    }
+  if$
+}
+
+INTEGERS { multiresult }
+
+FUNCTION {multi.page.check}
+{ 't :=
+  #0 'multiresult :=
+    { multiresult not
+      t empty$ not
+      and
+    }
+    { t #1 #1 substring$
+      duplicate$ "-" =
+      swap$ duplicate$ "," =
+      swap$ "+" =
+      or or
+        { #1 'multiresult := }
+        { t #2 global.max$ substring$ 't := }
+      if$
+    }
+  while$
+  multiresult
+}
+
+FUNCTION {format.pages}
+{ pages empty$
+    { "" }
+    { pages multi.page.check
+        { "pages" pages n.dashify tie.or.space.connect }
+        { "page" pages tie.or.space.connect }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.vol.num.pages}
+{ volume field.or.null
+  bolden
+  number empty$
+    'skip$
+    { "(" number * ")" * *
+      volume empty$
+        { "there's a number but no volume in " cite$ * warning$ }
+        'skip$
+      if$
+    }
+  if$
+  pages empty$
+    'skip$
+    { duplicate$ empty$
+        { pop$ format.pages }
+        { ", " * pages n.dashify * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.chapter.pages}
+{ chapter empty$
+    'format.pages
+    { type empty$
+        { "chapter" }
+        { type "l" change.case$ }
+      if$
+      chapter tie.or.space.connect
+      pages empty$
+        'skip$
+        { ", " * format.pages * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.in.ed.booktitle}
+{ booktitle empty$
+    { "" }
+    { editor empty$
+        { word.in booktitle emphasize * }
+        { word.in format.in.editors * ", " * booktitle emphasize * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.thesis.type}
+{ type empty$
+    'skip$
+    { pop$
+      type "t" change.case$
+    }
+  if$
+}
+
+FUNCTION {format.tr.number}
+{ type empty$
+    { "Technical Report" }
+    'type
+  if$
+  number empty$
+    { "t" change.case$ }
+    { number tie.or.space.connect }
+  if$
+}
+
+FUNCTION {format.article.crossref}
+{
+  word.in
+  "\cite{" * crossref * "}" *
+}
+
+FUNCTION {format.book.crossref}
+{ volume empty$
+    { "empty volume in " cite$ * "'s crossref of " * crossref * warning$
+      word.in
+    }
+    { "Volume" volume tie.or.space.connect
+      " of " *
+    }
+  if$
+  "\cite{" * crossref * "}" *
+}
+
+FUNCTION {format.incoll.inproc.crossref}
+{
+  word.in
+  "\cite{" * crossref * "}" *
+}
+
+FUNCTION {article}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  format.date "year" output.check
+  new.block
+  format.title "title" output.check
+  new.block
+  crossref missing$
+    { journal emphasize "journal" output.check
+      format.vol.num.pages output
+    }
+    { format.article.crossref output.nonnull
+      format.pages output
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {book}
+{ output.bibitem
+  author empty$
+    { format.editors "author and editor" output.check
+      editor format.key output
+    }
+    { format.authors output.nonnull
+      crossref missing$
+        { "author and editor" editor either.or.check }
+        'skip$
+      if$
+    }
+  if$
+  format.date "year" output.check
+  new.block
+  format.btitle "title" output.check
+  crossref missing$
+    { format.bvolume output
+      new.block
+      format.number.series output
+      new.sentence
+      publisher "publisher" output.check
+      address output
+    }
+    {
+      new.block
+      format.book.crossref output.nonnull
+    }
+  if$
+  format.edition output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {booklet}
+{ output.bibitem
+  format.authors output
+  author format.key output
+  format.date "year" output.check
+  new.block
+  format.title "title" output.check
+  new.block
+  howpublished output
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {inbook}
+{ output.bibitem
+  author empty$
+    { format.editors "author and editor" output.check
+      editor format.key output
+    }
+    { format.authors output.nonnull
+      crossref missing$
+        { "author and editor" editor either.or.check }
+        'skip$
+      if$
+    }
+  if$
+  format.date "year" output.check
+  new.block
+  format.btitle "title" output.check
+  crossref missing$
+    { format.bvolume output
+      format.chapter.pages "chapter and pages" output.check
+      new.block
+      format.number.series output
+      new.sentence
+      publisher "publisher" output.check
+      address output
+    }
+    { format.chapter.pages "chapter and pages" output.check
+      new.block
+      format.book.crossref output.nonnull
+    }
+  if$
+  format.edition output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {incollection}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  format.date "year" output.check
+  new.block
+  format.title "title" output.check
+  new.block
+  crossref missing$
+    { format.in.ed.booktitle "booktitle" output.check
+      format.bvolume output
+      format.number.series output
+      format.chapter.pages output
+      new.sentence
+      publisher "publisher" output.check
+      address output
+      format.edition output
+    }
+    { format.incoll.inproc.crossref output.nonnull
+      format.chapter.pages output
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {inproceedings}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  format.date "year" output.check
+  new.block
+  format.title "title" output.check
+  new.block
+  crossref missing$
+    { format.in.ed.booktitle "booktitle" output.check
+      format.bvolume output
+      format.number.series output
+      format.pages output
+      address output
+      new.sentence
+      organization output
+      publisher output
+    }
+    { format.incoll.inproc.crossref output.nonnull
+      format.pages output
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {conference} { inproceedings }
+
+FUNCTION {manual}
+{ output.bibitem
+  format.authors output
+  author format.key output
+  format.date "year" output.check
+  new.block
+  format.btitle "title" output.check
+  organization address new.block.checkb
+  organization output
+  address output
+  format.edition output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {mastersthesis}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  format.date "year" output.check
+  new.block
+  format.btitle "title" output.check
+  new.block
+  "Master's thesis" format.thesis.type output.nonnull
+  school "school" output.check
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {misc}
+{ output.bibitem
+  format.authors output
+  author format.key output
+  format.date "year" output.check
+  new.block
+  format.title output
+  new.block
+  howpublished output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {phdthesis}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  format.date "year" output.check
+  new.block
+  format.btitle "title" output.check
+  new.block
+  "Ph.D. thesis" format.thesis.type output.nonnull
+  school "school" output.check
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {proceedings}
+{ output.bibitem
+  format.editors output
+  editor format.key output
+  format.date "year" output.check
+  new.block
+  format.btitle "title" output.check
+  format.bvolume output
+  format.number.series output
+  address output
+  new.sentence
+  organization output
+  publisher output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {techreport}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  format.date "year" output.check
+  new.block
+  format.title "title" output.check
+  new.block
+  format.tr.number output.nonnull
+  institution "institution" output.check
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {unpublished}
+{ output.bibitem
+  format.authors "author" output.check
+  author format.key output
+  format.date "year" output.check
+  new.block
+  format.title "title" output.check
+  new.block
+  note "note" output.check
+  fin.entry
+}
+
+FUNCTION {default.type} { misc }
+
+MACRO {jan} {"January"}
+
+MACRO {feb} {"February"}
+
+MACRO {mar} {"March"}
+
+MACRO {apr} {"April"}
+
+MACRO {may} {"May"}
+
+MACRO {jun} {"June"}
+
+MACRO {jul} {"July"}
+
+MACRO {aug} {"August"}
+
+MACRO {sep} {"September"}
+
+MACRO {oct} {"October"}
+
+MACRO {nov} {"November"}
+
+MACRO {dec} {"December"}
+
+MACRO {acmcs} {"ACM Computing Surveys"}
+
+MACRO {acta} {"Acta Informatica"}
+
+MACRO {cacm} {"Communications of the ACM"}
+
+MACRO {ibmjrd} {"IBM Journal of Research and Development"}
+
+MACRO {ibmsj} {"IBM Systems Journal"}
+
+MACRO {ieeese} {"IEEE Transactions on Software Engineering"}
+
+MACRO {ieeetc} {"IEEE Transactions on Computers"}
+
+MACRO {ieeetcad}
+ {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"}
+
+MACRO {ipl} {"Information Processing Letters"}
+
+MACRO {jacm} {"Journal of the ACM"}
+
+MACRO {jcss} {"Journal of Computer and System Sciences"}
+
+MACRO {scp} {"Science of Computer Programming"}
+
+MACRO {sicomp} {"SIAM Journal on Computing"}
+
+MACRO {tocs} {"ACM Transactions on Computer Systems"}
+
+MACRO {tods} {"ACM Transactions on Database Systems"}
+
+MACRO {tog} {"ACM Transactions on Graphics"}
+
+MACRO {toms} {"ACM Transactions on Mathematical Software"}
+
+MACRO {toois} {"ACM Transactions on Office Information Systems"}
+
+MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"}
+
+MACRO {tcs} {"Theoretical Computer Science"}
+
+READ
+
+FUNCTION {sortify}
+{ purify$
+  "l" change.case$
+}
+
+INTEGERS { len }
+
+FUNCTION {chop.word}
+{ 's :=
+  'len :=
+  s #1 len substring$ =
+    { s len #1 + global.max$ substring$ }
+    's
+  if$
+}
+
+FUNCTION {format.lab.names}
+{ 's :=
+  s #1 "{vv~}{ll}" format.name$
+  s num.names$ duplicate$
+  #2 >
+    { pop$ " " * "et~al." emphasize * }
+    { #2 <
+        'skip$
+        { s #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" =
+            { " " * "et~al." emphasize * }
+            { " and " * s #2 "{vv~}{ll}" format.name$ * }
+          if$
+        }
+      if$
+    }
+  if$
+}
+
+FUNCTION {author.key.label}
+{ author empty$
+    { key empty$
+        { cite$ #1 #3 substring$ }
+        'key
+      if$
+    }
+    { author format.lab.names }
+  if$
+}
+
+FUNCTION {author.editor.key.label}
+{ author empty$
+    { editor empty$
+        { key empty$
+            { cite$ #1 #3 substring$ }
+            'key
+          if$
+        }
+        { editor format.lab.names }
+      if$
+    }
+    { author format.lab.names }
+  if$
+}
+
+FUNCTION {editor.key.label}
+{ editor empty$
+    { key empty$
+        { cite$ #1 #3 substring$ }
+        'key
+      if$
+    }
+    { editor format.lab.names }
+  if$
+}
+
+FUNCTION {calc.label}
+{ type$ "book" =
+  type$ "inbook" =
+  or
+    'author.editor.key.label
+    { type$ "proceedings" =
+        'editor.key.label
+        'author.key.label
+      if$
+    }
+  if$
+  "("
+  *
+  year duplicate$ empty$
+     { pop$ "????" }
+     { purify$ #-1 #4 substring$ }
+  if$
+  *
+  'label :=
+}
+
+FUNCTION {sort.format.names}
+{ 's :=
+  #1 'nameptr :=
+  ""
+  s num.names$ 'numnames :=
+  numnames 'namesleft :=
+    { namesleft #0 > }
+    { nameptr #1 >
+        { "   " * }
+        'skip$
+      if$
+      s nameptr
+      "{vv{ } }{ll{ }}{  f{ }}{  jj{ }}"
+      format.name$ 't :=
+      nameptr numnames = t "others" = and
+        { "et al" * }
+        { numnames #2 > nameptr #2 = and
+          { "zzzzzz" * #1 'namesleft := }
+          { t sortify * }
+        if$
+        }
+      if$
+      nameptr #1 + 'nameptr :=
+      namesleft #1 - 'namesleft :=
+    }
+  while$
+}
+
+FUNCTION {sort.format.title}
+{ 't :=
+  "A " #2
+    "An " #3
+      "The " #4 t chop.word
+    chop.word
+  chop.word
+  sortify
+  #1 global.max$ substring$
+}
+
+FUNCTION {author.sort}
+{ author empty$
+    { key empty$
+        { "to sort, need author or key in " cite$ * warning$
+          ""
+        }
+        { key sortify }
+      if$
+    }
+    { author sort.format.names }
+  if$
+}
+
+FUNCTION {author.editor.sort}
+{ author empty$
+    { editor empty$
+        { key empty$
+            { "to sort, need author, editor, or key in " cite$ * warning$
+              ""
+            }
+            { key sortify }
+          if$
+        }
+        { editor sort.format.names }
+      if$
+    }
+    { author sort.format.names }
+  if$
+}
+
+FUNCTION {editor.sort}
+{ editor empty$
+    { key empty$
+        { "to sort, need editor or key in " cite$ * warning$
+          ""
+        }
+        { key sortify }
+      if$
+    }
+    { editor sort.format.names }
+  if$
+}
+
+FUNCTION {presort}
+{ calc.label
+  label sortify
+  "    "
+  *
+  type$ "book" =
+  type$ "inbook" =
+  or
+    'author.editor.sort
+    { type$ "proceedings" =
+        'editor.sort
+        'author.sort
+      if$
+    }
+  if$
+  #1 entry.max$ substring$
+  'sort.label :=
+  sort.label
+  *
+  "    "
+  *
+  title field.or.null
+  sort.format.title
+  *
+  #1 entry.max$ substring$
+  'sort.key$ :=
+}
+
+ITERATE {presort}
+
+SORT
+
+STRINGS { last.label next.extra }
+
+INTEGERS { last.extra.num }
+
+FUNCTION {initialize.extra.label.stuff}
+{ #0 int.to.chr$ 'last.label :=
+  "" 'next.extra :=
+  #0 'last.extra.num :=
+}
+
+FUNCTION {forward.pass}
+{ last.label label =
+    { last.extra.num #1 + 'last.extra.num :=
+      last.extra.num int.to.chr$ 'extra.label :=
+    }
+    { "a" chr.to.int$ 'last.extra.num :=
+      "" 'extra.label :=
+      label 'last.label :=
+    }
+  if$
+}
+
+FUNCTION {reverse.pass}
+{ next.extra "b" =
+    { "a" 'extra.label := }
+    'skip$
+  if$
+  extra.label 'next.extra :=
+  label extra.label * 'label :=
+}
+
+EXECUTE {initialize.extra.label.stuff}
+
+ITERATE {forward.pass}
+
+REVERSE {reverse.pass}
+
+FUNCTION {bib.sort.order}
+{ sort.label
+  "    "
+  *
+  year field.or.null sortify
+  *
+  "    "
+  *
+  title field.or.null
+  sort.format.title
+  *
+  #1 entry.max$ substring$
+  'sort.key$ :=
+}
+
+ITERATE {bib.sort.order}
+
+SORT
+
+FUNCTION {begin.bib}
+{ preamble$ empty$
+    'skip$
+    { preamble$ write$ newline$ }
+  if$
+  "\begin{thebibliography}{}" write$ newline$
+}
+
+EXECUTE {begin.bib}
+
+EXECUTE {init.state.consts}
+
+ITERATE {call.type$}
+
+FUNCTION {end.bib}
+{ newline$
+  "\end{thebibliography}" write$ newline$
+}
+
+EXECUTE {end.bib}
+%% End of customized bst file 
+
diff --git a/manual/natbib.sty b/manual/natbib.sty
new file mode 100755
index 0000000..4c8c948
--- /dev/null
+++ b/manual/natbib.sty
@@ -0,0 +1,803 @@
+%%
+%% This is file `natbib.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% natbib.dtx  (with options: `package,all')
+%% =============================================
+%% IMPORTANT NOTICE:
+%% 
+%% This program can be redistributed and/or modified under the terms
+%% of the LaTeX Project Public License Distributed from CTAN
+%% archives in directory macros/latex/base/lppl.txt; either
+%% version 1 of the License, or any later version.
+%% 
+%% This is a generated file.
+%% It may not be distributed without the original source file natbib.dtx.
+%% 
+%% Full documentation can be obtained by LaTeXing that original file.
+%% Only a few abbreviated comments remain here to describe the usage.
+%% =============================================
+%% Copyright 1993-2000 Patrick W Daly
+%% Max-Planck-Institut f\"ur Aeronomie
+%% Max-Planck-Str. 2
+%% D-37191 Katlenburg-Lindau
+%% Germany
+%% E-mail: daly at linmpi.mpg.de
+\NeedsTeXFormat{LaTeX2e}[1995/06/01]
+\ProvidesPackage{natbib}
+        [2000/07/24 7.0a (PWD)]
+ % This package reimplements the LaTeX \cite command to be used for various
+ % citation styles, both author-year and numerical. It accepts BibTeX
+ % output intended for many other packages, and therefore acts as a
+ % general, all-purpose citation-style interface.
+ %
+ % With standard numerical .bst files, only numerical citations are
+ % possible. With an author-year .bst file, both numerical and
+ % author-year citations are possible.
+ %
+ % If author-year citations are selected, \bibitem must have one of the
+ %   following forms:
+ %   \bibitem[Jones et al.(1990)]{key}...
+ %   \bibitem[Jones et al.(1990)Jones, Baker, and Williams]{key}...
+ %   \bibitem[Jones et al., 1990]{key}...
+ %   \bibitem[\protect\citeauthoryear{Jones, Baker, and Williams}{Jones
+ %       et al.}{1990}]{key}...
+ %   \bibitem[\protect\citeauthoryear{Jones et al.}{1990}]{key}...
+ %   \bibitem[\protect\astroncite{Jones et al.}{1990}]{key}...
+ %   \bibitem[\protect\citename{Jones et al., }1990]{key}...
+ %   \harvarditem[Jones et al.]{Jones, Baker, and Williams}{1990}{key}...
+ %
+ % This is either to be made up manually, or to be generated by an
+ % appropriate .bst file with BibTeX.
+ %                            Author-year mode     ||   Numerical mode
+ % Then, \citet{key}  ==>>  Jones et al. (1990)    ||   Jones et al. [21]
+ %       \citep{key}  ==>> (Jones et al., 1990)    ||   [21]
+ % Multiple citations as normal:
+ % \citep{key1,key2}  ==>> (Jones et al., 1990; Smith, 1989) || [21,24]
+ %                           or  (Jones et al., 1990, 1991)  || [21,24]
+ %                           or  (Jones et al., 1990a,b)     || [21,24]
+ % \cite{key} is the equivalent of \citet{key} in author-year mode
+ %                         and  of \citep{key} in numerical mode
+ % Full author lists may be forced with \citet* or \citep*, e.g.
+ %       \citep*{key}      ==>> (Jones, Baker, and Williams, 1990)
+ % Optional notes as:
+ %   \citep[chap. 2]{key}    ==>> (Jones et al., 1990, chap. 2)
+ %   \citep[e.g.,][]{key}    ==>> (e.g., Jones et al., 1990)
+ %   \citep[see][pg. 34]{key}==>> (see Jones et al., 1990, pg. 34)
+ %  (Note: in standard LaTeX, only one note is allowed, after the ref.
+ %   Here, one note is like the standard, two make pre- and post-notes.)
+ %   \citealt{key}          ==>> Jones et al. 1990
+ %   \citealt*{key}         ==>> Jones, Baker, and Williams 1990
+ %   \citealp{key}          ==>> Jones et al., 1990
+ %   \citealp*{key}         ==>> Jones, Baker, and Williams, 1990
+ % Additional citation possibilities (both author-year and numerical modes)
+ %   \citeauthor{key}       ==>> Jones et al.
+ %   \citeauthor*{key}      ==>> Jones, Baker, and Williams
+ %   \citeyear{key}         ==>> 1990
+ %   \citeyearpar{key}      ==>> (1990)
+ %   \citetext{priv. comm.} ==>> (priv. comm.)
+ % Note: full author lists depends on whether the bib style supports them;
+ %       if not, the abbreviated list is printed even when full requested.
+ %
+ % For names like della Robbia at the start of a sentence, use
+ %   \Citet{dRob98}         ==>> Della Robbia (1998)
+ %   \Citep{dRob98}         ==>> (Della Robbia, 1998)
+ %   \Citeauthor{dRob98}    ==>> Della Robbia
+ %
+ %
+ % Citation aliasing is achieved with
+ %   \defcitealias{key}{text}
+ %   \citetalias{key}  ==>> text
+ %   \citepalias{key}  ==>> (text)
+ %
+ % Defining the citation style of a given bib style:
+ % Use \bibpunct (in the preamble only) with 6 mandatory arguments:
+ %    1. opening bracket for citation
+ %    2. closing bracket
+ %    3. citation separator (for multiple citations in one \cite)
+ %    4. the letter n for numerical styles, s for superscripts
+ %        else anything for author-year
+ %    5. punctuation between authors and date
+ %    6. punctuation between years (or numbers) when common authors missing
+ % One optional argument is the character coming before post-notes. It
+ %   appears in square braces before all other arguments. May be left off.
+ % Example (and default) \bibpunct[, ]{(}{)}{;}{a}{,}{,}
+ %
+ % To make this automatic for a given bib style, named newbib, say, make
+ % a local configuration file, natbib.cfg, with the definition
+ %   \newcommand{\bibstyle at newbib}{\bibpunct...}
+ % Then the \bibliographystyle{newbib} will cause \bibstyle at newbib to
+ % be called on THE NEXT LATEX RUN (via the aux file).
+ %
+ % Such preprogrammed definitions may be invoked in the text (preamble only)
+ %  by calling \citestyle{newbib}. This is only useful if the style specified
+ %  differs from that in \bibliographystyle.
+ %
+ % With \citeindextrue and \citeindexfalse, one can control whether the
+ % \cite commands make an automatic entry of the citation in the .idx
+ % indexing file. For this, \makeindex must also be given in the preamble.
+ %
+ % LaTeX2e Options: (for selecting punctuation)
+ %   round  -  round parentheses are used (default)
+ %   square -  square brackets are used   [option]
+ %   curly  -  curly braces are used      {option}
+ %   angle  -  angle brackets are used    <option>
+ %   colon  -  multiple citations separated by colon (default)
+ %   comma  -  separated by comma
+ %   authoryear - selects author-year citations (default)
+ %   numbers-  selects numerical citations
+ %   super  -  numerical citations as superscripts
+ %   sort   -  sorts multiple citations according to order in ref. list
+ %   sort&compress   -  like sort, but also compresses numerical citations
+ %   longnamesfirst  -  makes first citation full author list
+ %   sectionbib - puts bibliography in a \section* instead of \chapter*
+ % Punctuation so selected dominates over any predefined ones.
+ % LaTeX2e options are called as, e.g.
+ %        \usepackage[square,comma]{natbib}
+ % LaTeX the source file natbib.dtx to obtain more details
+ % or the file natnotes.tex for a brief reference sheet.
+ %-----------------------------------------------------------
+\@ifclassloaded{aguplus}{\PackageError{natbib}
+  {The aguplus class already includes natbib coding,\MessageBreak
+   so you should not add it explicitly}
+  {Type <Return> for now, but then later remove\MessageBreak
+   the command \protect\usepackage{natbib} from the document}
+  \endinput}{}
+\@ifclassloaded{nlinproc}{\PackageError{natbib}
+  {The nlinproc class already includes natbib coding,\MessageBreak
+   so you should not add it explicitly}
+  {Type <Return> for now, but then later remove\MessageBreak
+   the command \protect\usepackage{natbib} from the document}
+  \endinput}{}
+\@ifclassloaded{egs}{\PackageError{natbib}
+  {The egs class already includes natbib coding,\MessageBreak
+   so you should not add it explicitly}
+  {Type <Return> for now, but then later remove\MessageBreak
+   the command \protect\usepackage{natbib} from the document}
+  \endinput}{}
+ % Define citation punctuation for some author-year styles
+ % One may add and delete at this point
+ % Or put additions into local configuration file natbib.cfg
+\newcommand\bibstyle at chicago{\bibpunct{(}{)}{;}{a}{,}{,}}
+\newcommand\bibstyle at named{\bibpunct{[}{]}{;}{a}{,}{,}}
+\newcommand\bibstyle at agu{\bibpunct{[}{]}{;}{a}{,}{,~}}%Amer. Geophys. Union
+\newcommand\bibstyle at egs{\bibpunct{(}{)}{;}{a}{,}{,}}%Eur. Geophys. Soc.
+\newcommand\bibstyle at agsm{\bibpunct{(}{)}{,}{a}{}{,}\gdef\harvardand{\&}}
+\newcommand\bibstyle at kluwer{\bibpunct{(}{)}{,}{a}{}{,}\gdef\harvardand{\&}}
+\newcommand\bibstyle at dcu{\bibpunct{(}{)}{;}{a}{;}{,}\gdef\harvardand{and}}
+\newcommand\bibstyle at aa{\bibpunct{(}{)}{;}{a}{}{,}} %Astronomy & Astrophysics
+\newcommand\bibstyle at pass{\bibpunct{(}{)}{;}{a}{,}{,}}%Planet. & Space Sci
+\newcommand\bibstyle at anngeo{\bibpunct{(}{)}{;}{a}{,}{,}}%Annales Geophysicae
+\newcommand\bibstyle at nlinproc{\bibpunct{(}{)}{;}{a}{,}{,}}%Nonlin.Proc.Geophys.
+ % Define citation punctuation for some numerical styles
+\newcommand\bibstyle at cospar{\bibpunct{/}{/}{,}{n}{}{}%
+     \gdef\NAT at biblabelnum##1{##1.}}
+\newcommand\bibstyle at esa{\bibpunct{(Ref.~}{)}{,}{n}{}{}%
+     \gdef\NAT at biblabelnum##1{##1.\hspace{1em}}}
+\newcommand\bibstyle at nature{\bibpunct{}{}{,}{s}{}{\textsuperscript{,}}%
+     \gdef\NAT at biblabelnum##1{##1.}}
+ % The standard LaTeX styles
+\newcommand\bibstyle at plain{\bibpunct{[}{]}{,}{n}{}{,}}
+\let\bibstyle at alpha=\bibstyle at plain
+\let\bibstyle at abbrv=\bibstyle at plain
+\let\bibstyle at unsrt=\bibstyle at plain
+ % The author-year modifications of the standard styles
+\newcommand\bibstyle at plainnat{\bibpunct{[}{]}{,}{a}{,}{,}}
+\let\bibstyle at abbrvnat=\bibstyle at plainnat
+\let\bibstyle at unsrtnat=\bibstyle at plainnat
+\newif\ifNAT at numbers \NAT at numbersfalse
+\newif\ifNAT at super \NAT at superfalse
+\DeclareOption{numbers}{\NAT at numberstrue
+   \ExecuteOptions{square,comma,nobibstyle}}
+\DeclareOption{super}{\NAT at supertrue\NAT at numberstrue
+   \renewcommand\NAT at open{}\renewcommand\NAT at close{}
+   \ExecuteOptions{nobibstyle}}
+\DeclareOption{authoryear}{\NAT at numbersfalse
+   \ExecuteOptions{round,colon,bibstyle}}
+\DeclareOption{round}{%
+      \renewcommand\NAT at open{(} \renewcommand\NAT at close{)}
+   \ExecuteOptions{nobibstyle}}
+\DeclareOption{square}{%
+      \renewcommand\NAT at open{[} \renewcommand\NAT at close{]}
+   \ExecuteOptions{nobibstyle}}
+\DeclareOption{angle}{%
+      \renewcommand\NAT at open{$<$} \renewcommand\NAT at close{$>$}
+   \ExecuteOptions{nobibstyle}}
+\DeclareOption{curly}{%
+      \renewcommand\NAT at open{\{} \renewcommand\NAT at close{\}}
+   \ExecuteOptions{nobibstyle}}
+\DeclareOption{comma}{\renewcommand\NAT at sep{,}
+   \ExecuteOptions{nobibstyle}}
+\DeclareOption{colon}{\renewcommand\NAT at sep{;}
+   \ExecuteOptions{nobibstyle}}
+\DeclareOption{nobibstyle}{\let\bibstyle=\@gobble}
+\DeclareOption{bibstyle}{\let\bibstyle=\@citestyle}
+\newif\ifNAT at openbib \NAT at openbibfalse
+\DeclareOption{openbib}{\NAT at openbibtrue}
+\DeclareOption{sectionbib}{\def\NAT at sectionbib{on}}
+\def\NAT at sort{0}
+\DeclareOption{sort}{\def\NAT at sort{1}}
+\DeclareOption{sort&compress}{\def\NAT at sort{2}}
+\@ifpackageloaded{cite}{\PackageWarningNoLine{natbib}
+  {The `cite' package should not be used\MessageBreak
+   with natbib. Use option `sort' instead}\ExecuteOptions{sort}}{}
+\newif\ifNAT at longnames\NAT at longnamesfalse
+\DeclareOption{longnamesfirst}{\NAT at longnamestrue}
+\DeclareOption{nonamebreak}{\def\NAT at nmfmt#1{\mbox{\NAT at up#1}}}
+\def\NAT at nmfmt#1{{\NAT at up#1}}
+\renewcommand\bibstyle[1]{\@ifundefined{bibstyle@#1}{\relax}
+     {\csname bibstyle@#1\endcsname}}
+\AtBeginDocument{\global\let\bibstyle=\@gobble}
+\let\@citestyle\bibstyle
+\newcommand\citestyle[1]{\@citestyle{#1}\let\bibstyle\@gobble}
+\@onlypreamble{\citestyle}\@onlypreamble{\@citestyle}
+\newcommand\bibpunct[7][, ]%
+  {\gdef\NAT at open{#2}\gdef\NAT at close{#3}\gdef
+   \NAT at sep{#4}\global\NAT at numbersfalse\ifx #5n\global\NAT at numberstrue
+   \else
+   \ifx #5s\global\NAT at numberstrue\global\NAT at supertrue
+   \fi\fi
+   \gdef\NAT at aysep{#6}\gdef\NAT at yrsep{#7}%
+   \gdef\NAT at cmt{#1}%
+   \global\let\bibstyle\@gobble
+  }
+\@onlypreamble{\bibpunct}
+\newcommand\NAT at open{(} \newcommand\NAT at close{)}
+\newcommand\NAT at sep{;}
+\ProcessOptions
+\newcommand\NAT at aysep{,} \newcommand\NAT at yrsep{,}
+\newcommand\NAT at cmt{, }
+\newcommand\NAT at cite%
+    [3]{\ifNAT at swa\NAT@@open\if*#2*\else#2\ \fi
+        #1\if*#3*\else\NAT at cmt#3\fi\NAT@@close\else#1\fi\endgroup}
+\newcommand\NAT at citenum%
+    [3]{\ifNAT at swa\NAT@@open\if*#2*\else#2\ \fi
+        #1\if*#3*\else\NAT at cmt#3\fi\NAT@@close\else#1\fi\endgroup}
+\newcommand\NAT at citesuper[3]{\ifNAT at swa
+\unskip\hspace{1\p@}\textsuperscript{#1}%
+   \if*#3*\else\ (#3)\fi\else #1\fi\endgroup}
+\providecommand
+  \textsuperscript[1]{\mbox{$^{\mbox{\scriptsize#1}}$}}
+\providecommand\@firstofone[1]{#1}
+\newcommand\NAT at citexnum{}
+\def\NAT at citexnum[#1][#2]#3{%
+ \NAT at sort@cites{#3}%
+ \let\@citea\@empty
+  \@cite{\def\NAT at num{-1}\let\NAT at last@yr\relax\let\NAT at nm\@empty
+    \@for\@citeb:=\NAT at cite@list\do
+    {\edef\@citeb{\expandafter\@firstofone\@citeb}%
+     \if at filesw\immediate\write\@auxout{\string\citation{\@citeb}}\fi
+     \@ifundefined{b@\@citeb\@extra at b@citeb}{%
+       {\reset at font\bfseries?}
+        \NAT at citeundefined\PackageWarning{natbib}%
+       {Citation `\@citeb' on page \thepage \space undefined}}%
+     {\let\NAT at last@num\NAT at num\let\NAT at last@nm\NAT at nm
+      \NAT at parse{\@citeb}%
+      \ifNAT at longnames\@ifundefined{bv@\@citeb\@extra at b@citeb}{%
+        \let\NAT at name=\NAT at all@names
+        \global\@namedef{bv@\@citeb\@extra at b@citeb}{}}{}%
+      \fi
+      \ifNAT at full\let\NAT at nm\NAT at all@names\else
+        \let\NAT at nm\NAT at name\fi
+      \ifNAT at swa
+       \ifnum\NAT at ctype>1\relax\@citea
+        \hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+            \ifnum\NAT at ctype=2\relax\NAT at test{\NAT at ctype}%
+            \else\NAT at alias
+            \fi\hyper at natlinkend\else
+       \ifnum\NAT at sort>1
+         \begingroup\catcode`\_=8
+            \ifcat _\ifnum\z@<0\NAT at num _\else A\fi
+              \global\let\NAT at nm=\NAT at num \else \gdef\NAT at nm{-2}\fi
+            \ifcat _\ifnum\z@<0\NAT at last@num _\else A\fi
+              \global\@tempcnta=\NAT at last@num \global\advance\@tempcnta by\@ne
+              \else \global\@tempcnta\m at ne\fi
+         \endgroup
+         \ifnum\NAT at nm=\@tempcnta
+           \ifx\NAT at last@yr\relax
+             \edef\NAT at last@yr{\@citea \mbox{\noexpand\citenumfont{\NAT at num}}}%
+           \else
+             \edef\NAT at last@yr{--\penalty\@m\mbox{\noexpand\citenumfont{\NAT at num}}}%
+           \fi
+         \else
+           \NAT at last@yr \@citea \mbox{\citenumfont{\NAT at num}}%
+           \let\NAT at last@yr\relax
+         \fi
+       \else
+         \@citea \mbox{\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+           {\citenumfont{\NAT at num}}\hyper at natlinkend}%
+       \fi
+       \fi
+       \def\@citea{\NAT at sep\penalty\@m\NAT at space}%
+      \else
+        \ifcase\NAT at ctype\relax
+          \ifx\NAT at last@nm\NAT at nm \NAT at yrsep\penalty\@m\NAT at space\else
+          \@citea \NAT at test{1}\ \NAT@@open
+          \if*#1*\else#1\ \fi\fi \NAT at mbox{%
+          \hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+          {\citenumfont{\NAT at num}}\hyper at natlinkend}%
+          \def\@citea{\NAT@@close\NAT at sep\penalty\@m\ }%
+        \or\@citea
+          \hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+           \NAT at test{\NAT at ctype}\hyper at natlinkend
+          \def\@citea{\NAT at sep\penalty\@m\ }%
+        \or\@citea
+          \hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+           \NAT at test{\NAT at ctype}\hyper at natlinkend
+          \def\@citea{\NAT at sep\penalty\@m\ }%
+        \or\@citea
+          \hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+           \NAT at alias\hyper at natlinkend
+          \def\@citea{\NAT at sep\penalty\@m\ }%
+        \fi
+      \fi
+      }}%
+      \ifnum\NAT at sort>1\relax\NAT at last@yr\fi
+      \ifNAT at swa\else\ifnum\NAT at ctype=0\if*#2*\else
+      \NAT at cmt#2\fi \NAT@@close\fi\fi}{#1}{#2}}
+\newcommand\NAT at test[1]{\ifnum#1=1 \ifx\NAT at nm\NAT at noname
+  {\reset at font\bfseries(author?)}\PackageWarning{natbib}
+  {Author undefined for citation`\@citeb'
+   \MessageBreak
+   on page \thepage}\else \NAT at nm \fi
+  \else \if\relax\NAT at date\relax
+  {\reset at font\bfseries(year?)}\PackageWarning{natbib}
+  {Year undefined for citation`\@citeb'
+   \MessageBreak
+   on page \thepage}\else \NAT at date \fi \fi}
+\let\citenumfont=\relax
+\newcommand\NAT at citex{}
+\def\NAT at citex%
+  [#1][#2]#3{%
+  \NAT at sort@cites{#3}%
+  \let\@citea\@empty
+  \@cite{\let\NAT at nm\@empty\let\NAT at year\@empty
+    \@for\@citeb:=\NAT at cite@list\do
+    {\edef\@citeb{\expandafter\@firstofone\@citeb}%
+     \if at filesw\immediate\write\@auxout{\string\citation{\@citeb}}\fi
+     \@ifundefined{b@\@citeb\@extra at b@citeb}{\@citea%
+       {\reset at font\bfseries ?}\NAT at citeundefined
+                 \PackageWarning{natbib}%
+       {Citation `\@citeb' on page \thepage \space undefined}\def\NAT at date{}}%
+     {\let\NAT at last@nm=\NAT at nm\let\NAT at last@yr=\NAT at year
+     \NAT at parse{\@citeb}%
+      \ifNAT at longnames\@ifundefined{bv@\@citeb\@extra at b@citeb}{%
+        \let\NAT at name=\NAT at all@names
+        \global\@namedef{bv@\@citeb\@extra at b@citeb}{}}{}%
+      \fi
+     \ifNAT at full\let\NAT at nm\NAT at all@names\else
+       \let\NAT at nm\NAT at name\fi
+     \ifNAT at swa\ifcase\NAT at ctype
+       \if\relax\NAT at date\relax
+         \@citea\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+         \NAT at nmfmt{\NAT at nm}\NAT at date\hyper at natlinkend
+       \else
+         \ifx\NAT at last@nm\NAT at nm\NAT at yrsep
+            \ifx\NAT at last@yr\NAT at year
+              \hyper at natlinkstart{\@citeb\@extra at b@citeb}\NAT at exlab
+              \hyper at natlinkend
+            \else\unskip\
+              \hyper at natlinkstart{\@citeb\@extra at b@citeb}\NAT at date
+              \hyper at natlinkend
+            \fi
+         \else\@citea\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+           \NAT at nmfmt{\NAT at nm}%
+           \hyper at natlinkbreak{\NAT at aysep\ }{\@citeb\@extra at b@citeb}%
+           \NAT at date\hyper at natlinkend
+         \fi
+       \fi
+     \or\@citea\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+         \NAT at nmfmt{\NAT at nm}\hyper at natlinkend
+     \or\@citea\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+         \NAT at date\hyper at natlinkend
+     \or\@citea\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+         \NAT at alias\hyper at natlinkend
+     \fi \def\@citea{\NAT at sep\ }%
+     \else\ifcase\NAT at ctype
+        \if\relax\NAT at date\relax
+          \@citea\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+          \NAT at nmfmt{\NAT at nm}\hyper at natlinkend
+        \else
+         \ifx\NAT at last@nm\NAT at nm\NAT at yrsep
+            \ifx\NAT at last@yr\NAT at year
+              \hyper at natlinkstart{\@citeb\@extra at b@citeb}\NAT at exlab
+              \hyper at natlinkend
+            \else\unskip\
+              \hyper at natlinkstart{\@citeb\@extra at b@citeb}\NAT at date
+              \hyper at natlinkend
+            \fi
+         \else\@citea\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+           \NAT at nmfmt{\NAT at nm}%
+           \hyper at natlinkbreak{\ \NAT@@open\if*#1*\else#1\ \fi}%
+              {\@citeb\@extra at b@citeb}%
+           \NAT at date\hyper at natlinkend\fi
+        \fi
+       \or\@citea\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+         \NAT at nmfmt{\NAT at nm}\hyper at natlinkend
+       \or\@citea\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+         \NAT at date\hyper at natlinkend
+       \or\@citea\hyper at natlinkstart{\@citeb\@extra at b@citeb}%
+         \NAT at alias\hyper at natlinkend
+       \fi \if\relax\NAT at date\relax\def\@citea{\NAT at sep\ }%
+           \else\def\@citea{\NAT@@close\NAT at sep\ }\fi
+     \fi
+     }}\ifNAT at swa\else\if*#2*\else\NAT at cmt#2\fi
+     \if\relax\NAT at date\relax\else\NAT@@close\fi\fi}{#1}{#2}}
+\newif\ifNAT at par \NAT at partrue
+\newcommand\NAT@@open{\ifNAT at par\NAT at open\fi}
+\newcommand\NAT@@close{\ifNAT at par\NAT at close\fi}
+\newcommand\NAT at alias{\@ifundefined{al@\@citeb\@extra at b@citeb}{%
+  {\reset at font\bfseries(alias?)}\PackageWarning{natbib}
+  {Alias undefined for citation `\@citeb'
+  \MessageBreak on page \thepage}}{\@nameuse{al@\@citeb\@extra at b@citeb}}}
+\let\NAT at up\relax
+\newcommand\NAT at Up[1]{{\let\protect\@unexpandable at protect\let~\relax
+  \expandafter\NAT at deftemp#1}\expandafter\NAT at UP\NAT at temp}
+\newcommand\NAT at deftemp[1]{\xdef\NAT at temp{#1}}
+\newcommand\NAT at UP[1]{\let\@tempa\NAT at UP\ifcat a#1\MakeUppercase{#1}%
+  \let\@tempa\relax\else#1\fi\@tempa}
+\newcommand\shortcites[1]{%
+  \@bsphack\@for\@citeb:=#1\do
+  {\edef\@citeb{\expandafter\@firstofone\@citeb}%
+   \global\@namedef{bv@\@citeb\@extra at b@citeb}{}}\@esphack}
+\newcommand\NAT at biblabel[1]{\hfill}
+\newcommand\NAT at biblabelnum[1]{\bibnumfmt{#1}}
+\newcommand\bibnumfmt[1]{[#1]}
+\def\@tempa#1{[#1]}
+\ifx\@tempa\@biblabel\let\@biblabel\@empty\fi
+\newcommand\NAT at bibsetnum[1]{\settowidth\labelwidth{\@biblabel{#1}}%
+   \setlength{\leftmargin}{\labelwidth}\addtolength{\leftmargin}{\labelsep}%
+   \setlength{\itemsep}{\bibsep}\setlength{\parsep}{\z@}%
+   \ifNAT at openbib
+     \addtolength{\leftmargin}{4mm}%
+     \setlength{\itemindent}{-4mm}%
+     \setlength{\listparindent}{\itemindent}%
+     \setlength{\parsep}{0pt}%
+   \fi
+}
+\newlength{\bibhang}
+\setlength{\bibhang}{1em}
+\newlength{\bibsep}
+{\@listi \global\bibsep\itemsep \global\advance\bibsep by\parsep}
+
+\newcommand\NAT at bibsetup%
+   [1]{\setlength{\leftmargin}{\bibhang}\setlength{\itemindent}{-\leftmargin}%
+       \setlength{\itemsep}{\bibsep}\setlength{\parsep}{\z@}}
+\newcommand\NAT at set@cites{\ifNAT at numbers
+  \ifNAT at super \let\@cite\NAT at citesuper
+     \def\NAT at mbox##1{\unskip\nobreak\hspace{1\p@}\textsuperscript{##1}}%
+     \let\citeyearpar=\citeyear
+     \let\NAT at space\relax\else
+     \let\NAT at mbox=\mbox
+     \let\@cite\NAT at citenum \def\NAT at space{ }\fi
+  \let\@citex\NAT at citexnum
+  \ifx\@biblabel\@empty\let\@biblabel\NAT at biblabelnum\fi
+  \let\@bibsetup\NAT at bibsetnum
+  \def\natexlab##1{}%
+ \else
+  \let\@cite\NAT at cite
+  \let\@citex\NAT at citex
+  \let\@biblabel\NAT at biblabel
+  \let\@bibsetup\NAT at bibsetup
+  \def\natexlab##1{##1}%
+ \fi}
+\AtBeginDocument{\NAT at set@cites}
+\AtBeginDocument{\ifx\SK at def\@undefined\else
+\ifx\SK at cite\@empty\else
+  \SK at def\@citex[#1][#2]#3{\SK@\SK@@ref{#3}\SK@@citex[#1][#2]{#3}}\fi
+\ifx\SK at citeauthor\@undefined\def\HAR at checkdef{}\else
+  \let\citeauthor\SK at citeauthor
+  \let\citefullauthor\SK at citefullauthor
+  \let\citeyear\SK at citeyear\fi
+\fi}
+\AtBeginDocument{\@ifpackageloaded{hyperref}{%
+  \ifnum\NAT at sort=2\def\NAT at sort{1}\fi}{}}
+\newif\ifNAT at full\NAT at fullfalse
+\newif\ifNAT at swa
+\DeclareRobustCommand\citet
+   {\begingroup\NAT at swafalse\def\NAT at ctype{0}\NAT at partrue
+     \@ifstar{\NAT at fulltrue\NAT at citetp}{\NAT at fullfalse\NAT at citetp}}
+\newcommand\NAT at citetp{\@ifnextchar[{\NAT@@citetp}{\NAT@@citetp[]}}
+\newcommand\NAT@@citetp{}
+\def\NAT@@citetp[#1]{\@ifnextchar[{\@citex[#1]}{\@citex[][#1]}}
+\DeclareRobustCommand\citep
+   {\begingroup\NAT at swatrue\def\NAT at ctype{0}\NAT at partrue
+         \@ifstar{\NAT at fulltrue\NAT at citetp}{\NAT at fullfalse\NAT at citetp}}
+\DeclareRobustCommand\cite
+    {\begingroup\def\NAT at ctype{0}\NAT at partrue\NAT at swatrue
+      \@ifstar{\NAT at fulltrue\NAT at cites}{\NAT at fullfalse\NAT at cites}}
+\newcommand\NAT at cites{\@ifnextchar [{\NAT@@citetp}{%
+     \ifNAT at numbers\else
+     \NAT at swafalse
+     \fi
+    \NAT@@citetp[]}}
+\DeclareRobustCommand\citealt
+   {\begingroup\NAT at swafalse\def\NAT at ctype{0}\NAT at parfalse
+         \@ifstar{\NAT at fulltrue\NAT at citetp}{\NAT at fullfalse\NAT at citetp}}
+\DeclareRobustCommand\citealp
+   {\begingroup\NAT at swatrue\def\NAT at ctype{0}\NAT at parfalse
+         \@ifstar{\NAT at fulltrue\NAT at citetp}{\NAT at fullfalse\NAT at citetp}}
+\DeclareRobustCommand\citeauthor
+   {\begingroup\NAT at swafalse\def\NAT at ctype{1}\NAT at parfalse
+    \@ifstar{\NAT at fulltrue\NAT at citetp}{\NAT at fullfalse\NAT at citetp}}
+\DeclareRobustCommand\Citet
+   {\begingroup\NAT at swafalse\def\NAT at ctype{0}\NAT at partrue
+     \let\NAT at up\NAT at Up
+     \@ifstar{\NAT at fulltrue\NAT at citetp}{\NAT at fullfalse\NAT at citetp}}
+\DeclareRobustCommand\Citep
+   {\begingroup\NAT at swatrue\def\NAT at ctype{0}\NAT at partrue
+     \let\NAT at up\NAT at Up
+         \@ifstar{\NAT at fulltrue\NAT at citetp}{\NAT at fullfalse\NAT at citetp}}
+\DeclareRobustCommand\Citealt
+   {\begingroup\NAT at swafalse\def\NAT at ctype{0}\NAT at parfalse
+     \let\NAT at up\NAT at Up
+         \@ifstar{\NAT at fulltrue\NAT at citetp}{\NAT at fullfalse\NAT at citetp}}
+\DeclareRobustCommand\Citealp
+   {\begingroup\NAT at swatrue\def\NAT at ctype{0}\NAT at parfalse
+     \let\NAT at up\NAT at Up
+         \@ifstar{\NAT at fulltrue\NAT at citetp}{\NAT at fullfalse\NAT at citetp}}
+\DeclareRobustCommand\Citeauthor
+   {\begingroup\NAT at swafalse\def\NAT at ctype{1}\NAT at parfalse
+     \let\NAT at up\NAT at Up
+    \@ifstar{\NAT at fulltrue\NAT at citetp}{\NAT at fullfalse\NAT at citetp}}
+\DeclareRobustCommand\citeyear
+   {\begingroup\NAT at swafalse\def\NAT at ctype{2}\NAT at parfalse\NAT at citetp}
+\DeclareRobustCommand\citeyearpar
+   {\begingroup\NAT at swatrue\def\NAT at ctype{2}\NAT at partrue\NAT at citetp}
+\newcommand\citetext[1]{\NAT at open#1\NAT at close}
+\DeclareRobustCommand\citefullauthor
+   {\citeauthor*}
+\newcommand\defcitealias[2]{%
+   \@ifundefined{al@#1\@extra at b@citeb}{}
+   {\PackageWarning{natbib}{Overwriting existing alias for citation #1}}
+   \@namedef{al@#1\@extra at b@citeb}{#2}}
+\DeclareRobustCommand\citetalias{\begingroup
+   \NAT at swafalse\def\NAT at ctype{3}\NAT at parfalse\NAT at citetp}
+\DeclareRobustCommand\citepalias{\begingroup
+   \NAT at swatrue\def\NAT at ctype{3}\NAT at partrue\NAT at citetp}
+\renewcommand\nocite[1]{\@bsphack
+  \@for\@citeb:=#1\do{%
+    \edef\@citeb{\expandafter\@firstofone\@citeb}%
+    \if at filesw\immediate\write\@auxout{\string\citation{\@citeb}}\fi
+    \if*\@citeb\else
+    \@ifundefined{b@\@citeb\@extra at b@citeb}{%
+       \NAT at citeundefined \PackageWarning{natbib}%
+       {Citation `\@citeb' undefined}}{}\fi}%
+  \@esphack}
+\newcommand\NAT at parse[1]{{%
+     \let\protect=\@unexpandable at protect\let~\relax
+     \let\active at prefix=\@gobble
+     \xdef\NAT at temp{\csname b@#1\@extra at b@citeb\endcsname}}%
+     \expandafter\NAT at split\NAT at temp
+     \expandafter\NAT at parse@date\NAT at date??????@@%
+     \ifciteindex\NAT at index\fi
+}
+\newcommand\NAT at split[4]{%
+  \gdef\NAT at num{#1}\gdef\NAT at name{#3}\gdef\NAT at date{#2}%
+  \gdef\NAT at all@names{#4}%
+  \ifx\NAT at noname\NAT at all@names \gdef\NAT at all@names{#3}\fi}
+\newcommand\NAT at parse@date{}
+\def\NAT at parse@date#1#2#3#4#5#6@@{%
+  \ifnum\the\catcode`#1=11\def\NAT at year{}\def\NAT at exlab{#1}\else
+  \ifnum\the\catcode`#2=11\def\NAT at year{#1}\def\NAT at exlab{#2}\else
+  \ifnum\the\catcode`#3=11\def\NAT at year{#1#2}\def\NAT at exlab{#3}\else
+  \ifnum\the\catcode`#4=11\def\NAT at year{#1#2#3}\def\NAT at exlab{#4}\else
+    \def\NAT at year{#1#2#3#4}\def\NAT at exlab{{#5}}\fi\fi\fi\fi}
+\newcommand\NAT at index{}
+\let\NAT at makeindex=\makeindex
+\renewcommand\makeindex{\NAT at makeindex
+  \renewcommand\NAT at index{\@bsphack\begingroup
+     \def~{\string~}\@wrindex{\NAT at idxtxt}}}
+\newcommand\NAT at idxtxt{\NAT at name\ \NAT at open\NAT at date\NAT at close}
+\@ifundefined{@indexfile}{}{\let\NAT at makeindex\relax\makeindex}
+\newif\ifciteindex \citeindexfalse
+\newcommand\citeindextype{default}
+\newcommand\NAT at index@alt{{\let\protect=\noexpand\let~\relax
+  \xdef\NAT at temp{\NAT at idxtxt}}\expandafter\NAT at exp\NAT at temp\@nil}
+\newcommand\NAT at exp{}
+\def\NAT at exp#1\@nil{\mbox{}\index[\citeindextype]{#1}}
+
+\AtBeginDocument{%
+\@ifpackageloaded{index}{\let\NAT at index=\NAT at index@alt}{}}
+\newcommand\NAT at ifcmd{\futurelet\NAT at temp\NAT at ifxcmd}
+\newcommand\NAT at ifxcmd{\ifx\NAT at temp\relax\else\expandafter\NAT at bare\fi}
+\def\NAT at bare#1(#2)#3(@)#4\@nil#5{%
+  \if @#2
+  \expandafter\NAT at apalk#1, , \@nil{#5}\else
+  \stepcounter{NAT at ctr}%
+  \NAT at wrout{\arabic {NAT at ctr}}{#2}{#1}{#3}{#5}
+\fi
+}
+\newcommand\NAT at wrout[5]{%
+\if at filesw
+      {\let\protect\noexpand\let~\relax
+       \immediate
+       \write\@auxout{\string\bibcite{#5}{{#1}{#2}{{#3}}{{#4}}}}}\fi
+\ignorespaces}
+\def\NAT at noname{{}}
+\renewcommand\bibitem{%
+  \@ifnextchar[{\@lbibitem}{%
+    \global\NAT at stdbsttrue
+    \stepcounter{NAT at ctr}\@lbibitem[\arabic{NAT at ctr}]}}
+\def\@lbibitem[#1]#2{%
+  \if\relax\@extra at b@citeb\relax\else
+    \@ifundefined{br@#2\@extra at b@citeb}{}{%
+     \@namedef{br@#2}{\@nameuse{br@#2\@extra at b@citeb}}}\fi
+   \@ifundefined{b@#2\@extra at b@citeb}{\def\NAT at num{}}{\NAT at parse{#2}}%
+   \item[\hfil\hyper at natanchorstart{#2\@extra at b@citeb}\@biblabel{\NAT at num}%
+    \hyper at natanchorend]%
+    \NAT at ifcmd#1(@)(@)\@nil{#2}}
+\ifx\SK at lbibitem\@undefined\else
+   \let\SK at lbibitem\@lbibitem
+   \def\@lbibitem[#1]#2{%
+     \SK at lbibitem[#1]{#2}\SK@\SK@@label{#2}\ignorespaces}\fi
+\newif\ifNAT at stdbst \NAT at stdbstfalse
+
+\AtEndDocument
+  {\ifNAT at stdbst\if at filesw\immediate\write\@auxout{\string
+   \global\string\NAT at numberstrue}\fi\fi
+  }
+\providecommand\bibcite{}
+\renewcommand\bibcite[2]{\@ifundefined{b@#1\@extra at binfo}\relax
+     {\NAT at citemultiple
+      \PackageWarningNoLine{natbib}{Citation `#1' multiply defined}}%
+  \global\@namedef{b@#1\@extra at binfo}{#2}}
+\AtEndDocument{\NAT at swatrue\let\bibcite\NAT at testdef}
+\newcommand\NAT at testdef[2]{%
+  \def\NAT at temp{#2}\expandafter \ifx \csname b@#1\@extra at binfo\endcsname
+    \NAT at temp \else \ifNAT at swa \NAT at swafalse
+       \PackageWarningNoLine{natbib}{Citation(s) may have
+          changed.\MessageBreak
+          Rerun to get citations correct}\fi\fi}
+\newcommand\NAT at apalk{}
+\def\NAT at apalk#1, #2, #3\@nil#4{\if\relax#2\relax
+  \global\NAT at stdbsttrue
+  \NAT at wrout{#1}{}{}{}{#4}\else
+  \stepcounter{NAT at ctr}%
+  \NAT at wrout{\arabic {NAT at ctr}}{#2}{#1}{}{#4}\fi}
+\newcommand\citeauthoryear{}
+\def\citeauthoryear#1#2#3(@)(@)\@nil#4{\stepcounter{NAT at ctr}\if\relax#3\relax
+   \NAT at wrout{\arabic {NAT at ctr}}{#2}{#1}{}{#4}\else
+   \NAT at wrout{\arabic {NAT at ctr}}{#3}{#2}{#1}{#4}\fi}
+\newcommand\citestarts{\NAT at open}
+\newcommand\citeends{\NAT at close}
+\newcommand\betweenauthors{and}
+\newcommand\astroncite{}
+\def\astroncite#1#2(@)(@)\@nil#3{\stepcounter{NAT at ctr}\NAT at wrout{\arabic
+{NAT at ctr}}{#2}{#1}{}{#3}}
+\newcommand\citename{}
+\def\citename#1#2(@)(@)\@nil#3{\expandafter\NAT at apalk#1#2, \@nil{#3}}
+\newcommand\harvarditem[4][]%
+    {\if\relax#1\relax\bibitem[#2(#3)]{#4}\else
+        \bibitem[#1(#3)#2]{#4}\fi }
+\newcommand\harvardleft{\NAT at open}
+\newcommand\harvardright{\NAT at close}
+\newcommand\harvardyearleft{\NAT at open}
+\newcommand\harvardyearright{\NAT at close}
+\AtBeginDocument{\providecommand{\harvardand}{and}}
+\newcommand\harvardurl[1]{\textbf{URL:} \textit{#1}}
+\providecommand\bibsection{}
+\@ifundefined{chapter}%
+  {\renewcommand\bibsection{\section*{\refname
+    \@mkboth{\MakeUppercase{\refname}}{\MakeUppercase{\refname}}}}}
+  {\@ifundefined{NAT at sectionbib}%
+    {\renewcommand\bibsection{\chapter*{\bibname
+     \@mkboth{\MakeUppercase{\bibname}}{\MakeUppercase{\bibname}}}}}
+    {\renewcommand\bibsection{\section*{\bibname
+     \ifx\@mkboth\@gobbletwo\else\markright{\MakeUppercase{\bibname}}\fi}}}}
+\@ifclassloaded{amsart}%
+  {\renewcommand\bibsection{\section*{\refname}}}{}
+\@ifclassloaded{amsbook}%
+  {\renewcommand\bibsection{\chapter*{\bibname}}}{}
+\@ifundefined{bib at heading}{}{\let\bibsection\bib at heading}
+\newcounter{NAT at ctr}
+\renewenvironment{thebibliography}[1]{%
+ \bibsection
+ \vspace{1\p@}\parindent \z@\bibpreamble\bibfont\list
+   {\@biblabel{\arabic{NAT at ctr}}}{\@bibsetup{#1}%
+    \setcounter{NAT at ctr}{0}}%
+    \ifNAT at openbib
+      \renewcommand\newblock{\par}
+    \else
+      \renewcommand\newblock{\hskip .11em \@plus.33em \@minus.07em}%
+    \fi
+    \sloppy\clubpenalty4000\widowpenalty4000
+    \sfcode`\.=1000\relax
+    \let\citeN\cite \let\shortcite\cite
+    \let\citeasnoun\cite\fontsize{7}{9}\selectfont
+ }{\def\@noitemerr{%
+  \PackageWarning{natbib}
+     {Empty `thebibliography' environment}}%
+  \endlist\vskip-\lastskip}
+\let\bibfont\relax
+\let\bibpreamble\relax
+\providecommand\reset at font{\relax}
+\providecommand\bibname{Bibliography}
+\providecommand\refname{References}
+\newcommand\NAT at citeundefined{\gdef \NAT at undefined {%
+    \PackageWarningNoLine{natbib}{There were undefined citations}}}
+\let \NAT at undefined \relax
+\newcommand\NAT at citemultiple{\gdef \NAT at multiple {%
+    \PackageWarningNoLine{natbib}{There were multiply defined citations}}}
+\let \NAT at multiple \relax
+\AtEndDocument{\NAT at undefined\NAT at multiple}
+\providecommand\@mkboth[2]{}
+\providecommand\MakeUppercase{\uppercase}
+\providecommand{\@extra at b@citeb}{}
+\gdef\@extra at binfo{}
+\providecommand\hyper at natanchorstart[1]{}
+\providecommand\hyper at natanchorend{}
+\providecommand\hyper at natlinkstart[1]{}
+\providecommand\hyper at natlinkend{}
+\providecommand\hyper at natlinkbreak[2]{#1}
+\@ifundefined{bbl at redefine}{}{%
+ \bbl at redefine\nocite#1{%
+  \@safe at activestrue\org at nocite{#1}\@safe at activesfalse}%
+\bbl at redefine\@lbibitem[#1]#2{%
+  \@safe at activestrue\org@@lbibitem[#1]{#2}\@safe at activesfalse}%
+}
+\AtBeginDocument{\@ifundefined{bbl at redefine}{}{%
+\bbl at redefine\@citex[#1][#2]#3{%
+  \@safe at activestrue\org@@citex[#1][#2]{#3}\@safe at activesfalse}%
+\bbl at redefine\NAT at testdef#1#2{%
+  \@safe at activestrue\org at NAT@testdef{#1}{#2}\@safe at activesfalse}%
+\@ifundefined{org@@lbibitem}{%
+\bbl at redefine\@lbibitem[#1]#2{%
+  \@safe at activestrue\org@@lbibitem[#1]{#2}\@safe at activesfalse}}{}%
+}}
+\ifnum\NAT at sort>0
+\newcommand\NAT at sort@cites[1]{%
+\@tempcntb\m at ne
+\let\@celt\delimiter
+\def\NAT at num@list{}%
+\def\NAT at cite@list{}%
+\def\NAT at nonsort@list{}%
+\@for \@citeb:=#1\do{\NAT at make@cite at list}%
+\edef\NAT at cite@list{\NAT at cite@list\NAT at nonsort@list}%
+\edef\NAT at cite@list{\expandafter\NAT at xcom\NAT at cite@list @@}}
+\begingroup \catcode`\_=8
+\gdef\NAT at make@cite at list{%
+     \edef\@citeb{\expandafter\@firstofone\@citeb}%
+    \@ifundefined{b@\@citeb\@extra at b@citeb}{\def\NAT at num{A}}%
+    {\NAT at parse{\@citeb}}%
+      \ifcat _\ifnum\z@<0\NAT at num _\else A\fi
+       \@tempcnta\NAT at num \relax
+       \ifnum \@tempcnta>\@tempcntb
+          \edef\NAT at num@list{\NAT at num@list \@celt{\NAT at num}}%
+          \edef\NAT at cite@list{\NAT at cite@list\@citeb,}%
+          \@tempcntb\@tempcnta
+       \else
+          \let\NAT@@cite at list=\NAT at cite@list \def\NAT at cite@list{}%
+          \edef\NAT at num@list{\expandafter\NAT at num@celt \NAT at num@list \@gobble @}%
+          {\let\@celt=\NAT at celt\NAT at num@list}%
+       \fi
+    \else
+       \edef\NAT at nonsort@list{\NAT at nonsort@list\@citeb,}%
+ \fi}
+\endgroup
+\def\NAT at celt#1{\ifnum #1<\@tempcnta
+  \xdef\NAT at cite@list{\NAT at cite@list\expandafter\NAT at nextc\NAT@@cite at list @@}%
+  \xdef\NAT@@cite at list{\expandafter\NAT at restc\NAT@@cite at list}%
+ \else
+  \xdef\NAT at cite@list{\NAT at cite@list\@citeb,\NAT@@cite at list}\let\@celt\@gobble%
+ \fi}
+\def\NAT at num@celt#1#2{\ifx \@celt #1%
+     \ifnum #2<\@tempcnta
+        \@celt{#2}%
+        \expandafter\expandafter\expandafter\NAT at num@celt
+     \else
+        \@celt{\number\@tempcnta}\@celt{#2}%
+  \fi\fi}
+\def\NAT at nextc#1,#2@@{#1,}
+\def\NAT at restc#1,#2{#2}
+\def\NAT at xcom#1,@@{#1}
+\else
+ \newcommand\NAT at sort@cites[1]{\edef\NAT at cite@list{#1}}\fi
+\InputIfFileExists{natbib.cfg}
+       {\typeout{Local config file natbib.cfg used}}{}
+%% 
+%% <<<<< End of generated file <<<<<<
+%%
+%% End of file `natbib.sty'.
diff --git a/manual/sec-arguments.tex b/manual/sec-arguments.tex
new file mode 100644
index 0000000..181137a
--- /dev/null
+++ b/manual/sec-arguments.tex
@@ -0,0 +1,178 @@
+\section{Command Line Arguments}
+\label{sec:arguments}
+
+\begin{itemize}
+
+\item  {\bf -a}
+
+Estimate model-averaged phylogeny for each active criterion. See Section \ref{sec:consensus} for more details.
+
+\item  {\bf -AIC}
+
+Calculate the Akaike Information Criterion. See Section \ref{sec:aic}.
+
+\item  {\bf -AICc}
+
+Calculate the corrected Akaike Information Criterion. See Section \ref{sec:aic}.
+
+\item  {\bf -BIC}
+
+Calculate the Bayesian Information Criterion. See Section \ref{sec:bic}.
+
+\item  {\bf -DT}
+
+Calculate the decision theory criterion. See Section \ref{sec:dt}.
+
+\item  {\bf -c} confidenceInterval
+
+Sets the confidence interval for the model selection process (default is 100).
+
+\item  {\bf -d} inputFile
+
+Sets the input data file. jModelTest makes use of the ALTER library for converting several alignment formats to PHYLIP.
+
+\item  {\bf -dLRT}
+
+Perform dynamical likelihood ratio tests. See Section \ref{sec:dlrt} for more details.
+
+\item  {\bf -f}
+
+Include models with unequals base frecuencies.
+
+\item  {\bf -g} numberOfRateCategories
+
+Include models with rate variation among sites and sets the number of categories. Usually 4 categories are enough.
+
+\item  {\bf -getPhylip}
+
+Converts the input file into phylip format and exits. For example, the following command will generate a new PHYLIP file named ``input.nex.phy''.
+\begin{lstlisting}
+$java -jar jModelTest.jar -d input.nex -getPhylip
+\end{lstlisting}
+
+\item  {\bf -G} threshold
+
+Heuristic search. Requires a threshold > 0 (e.g., -G 0.1)
+
+\item  {\bf -h} confidenceInterval
+
+Sets the confidence level for the hLRTs (default is 0.01)
+
+\item  {\bf -help}
+
+Displays a help message
+
+\item  {\bf -hLRT}
+
+Perform hierarchical likelihood ratio tests. See Section \ref{sec:hlrt} for more details.
+
+\item  {\bf -H}
+
+Information criterion for clustering search (AIC, AICc, BIC). (e.g., -H AIC) (default is BIC)
+
+\item  {\bf -i}
+
+Include models with a proportion invariable sites.
+
+\item  {\bf -machinesfile} machinesFile
+
+Gets the processors per host from a machines file (for MPI execution).
+
+\item  {\bf -n} logSuffix
+
+Execution name appended to the log filenames. By default, current time is used: yyyyMMddhhmmss.
+
+\item  {\bf -o} outputFile
+
+Redirects the output to a file.
+
+\item  {\bf -O} {ftvwxgp}
+
+Sets the hypothesis order for the hLRTs (e.g., -hLRT -O gpftv) (default is ftvwxgp)
+\begin{itemize}
+\item {\bf f} frequencies
+\item {\bf t} transition/transversion ratio
+\item {\bf v} 2ti4tv for subst=3 / 2ti for subst>3
+\item {\bf w} 2tv
+\item {\bf x} 4tv
+\item {\bf g} gamma
+\item {\bf p} proportion of invariable sites
+\end{itemize}
+
+See Section \ref{sec:hlrt} for more details.
+
+\item  {\bf -p}
+
+Calculate the parameter importances. See Section \ref{sec:param-importances}.
+
+\item  {\bf -r}
+
+Backward selection for the hLRT (default is forward).
+
+\item  {\bf -s} 3|5|7|11|203
+
+Sets the number of substitution schemes.
+\begin{itemize}
+     \item {\bf 3} JC/F81, K80/HKY, SYM/GTR (used by default).
+     \item {\bf 5} JC/F81, K80/HKY, TrNef/TrN, TPM1/TPM1uf, SYM/GTR.
+     \item {\bf 7} JC/F81, K80/HKY, TrNef/TrN, TPM1/TPM1uf, TIM1ef/TIM1, TVMef/TVM, SYM/GTR.
+     \item {\bf 11} All models defined in Table~\ref{table-models}.
+     \item {\bf 203} All possible GTR submatrices.
+\end{itemize}
+
+\item  {\bf -S} NNI|SPR|BEST
+
+Defines the tree topology search operation option for Maximum-Likelihood search: 
+\begin{itemize}
+     \item {\bf NNI} Nearest Neighbour Interchange (fast).
+     \item {\bf SPR} Subtree Pruning and Regrafting (slower).
+     \item {\bf BEST} Best of NNI and SPR (slowest option) (used by default).
+\end{itemize}
+
+\item  {\bf --set-local-config} configFile
+\label{pp:args-config}
+
+Allows the user to set a local configuration file in replacement of conf/jmodeltest.conf.
+See Section~\ref{sec:config} for more details.
+
+\item  {\bf --set-property} propertyName=propertyValue
+
+Allows the user to set a especific value for a property in replacement of the existing parameter in conf/jmodeltest.conf.
+See Section~\ref{sec:config} for more details.
+
+e.g., --set-property log-dir=myHome/myLogDirectory
+
+\item  {\bf -t} fixed|BIONJ|ML
+
+Base tree for likelihood calculations (e.g., -t BIONJ):
+\begin{itemize}
+     \item {\bf fixed}  Fixed BIONJ topology from JC model
+     \item {\bf BIONJ}  Neighbor-Joining topology for each model
+     \item {\bf ML}     Maximum Likelihood topology for each model (default)
+\end{itemize}
+
+\item  {\bf -tr} numberOfThreads
+
+Number of threads to execute (default is the number of logical processors in the machine).
+
+\item  {\bf -u} treeFile
+
+Fixed tree for likelihood calculations defined by the user. If a user tree is defined with this command, -t argument is ignored.
+
+\item  {\bf -uLnL}
+
+Calculate delta AIC,AICc,BIC against unconstrained likelihood.
+
+\item  {\bf -v}
+
+Do model averaging and parameter importances. See Section \ref{sec:model-averaging}.
+
+\item  {\bf -w}
+
+Prints out the PAUP block.
+
+\item  {\bf -z}
+
+Strict consensus type for model-averaged phylogeny (default is majority rule). See Section \ref{sec:consensus}.
+
+\end{itemize}
diff --git a/manual/sec-config.tex b/manual/sec-config.tex
new file mode 100644
index 0000000..be63075
--- /dev/null
+++ b/manual/sec-config.tex
@@ -0,0 +1,145 @@
+\section{Global Configuration}
+\label{sec:config}
+
+jModelTest contains some global configuration parameters in the file conf/jmodeltest.conf. In case you are sharing the jModelTest distribution between multiple users, it is possible to set a local configuration file for your own using the {\bf \texttt{--}set-local-config} argument in the command file. You can also change one or several properties by using the {\bf \texttt{--}set-property} argument. See Page~\pageref{pp:args-config} for the reference about this commands.
+
+For example:
+\begin{lstlisting}
+$ java -jar jModelTest -d example-data/aP6.phy -f -i -g 4 -s 11 --set-property log-dir=myLogDir --set-property exe-dir=path/to/my/phyml
+\end{lstlisting}
+
+This file has the following content:
+
+\begin{verbatim}
+#######################################
+# jModelTest Configuration properties #
+#######################################
+
+##########################################################
+#                                                        #
+# Automatic Logging                                      #
+#                                                        #
+# If html-logging is "enabled", every time the user runs #
+# jModelTest, a new html log file will be created in the #
+# log directory.                                         #
+# If phyml-logging is "enabled", PhyML streams are saved #
+# Default log directory is $JMODELTEST_HOME/log, but can #
+# be modified using the log-dir property.                #
+#                                                        #
+##########################################################
+checkpointing  = enabled
+html-logging   = enabled
+phyml-logging  = enabled
+log-dir        = log
+
+##########################################################
+#                                                        #
+# Phyml Binaries path                                    #
+#                                                        #
+# By default, jModelTest will search for the PhyML       #
+# executables in $JMODELTEST_HOME/exe/phyml. User can    #
+# define a different path, wether absolute (starting     #
+# with '/' or 'C:\') or relative to $JMODELTEST_HOME     #
+# directory using exe-dir property.                      #
+#                                                        #
+# If an usable version of PhyML is installed system-wide #
+# (for example, from the Ubuntu/Debian repositories),    #
+# the user can set 'global-phyml-exe' property to true   #
+# and jModelTest will use the global binary instead of   #
+# local ones.                                            #
+#                                                        #
+##########################################################
+global-phyml-exe    = false
+exe-dir	            = exe/phyml
+
+##########################################################
+#                                                        #
+# Thread Scheduling Configuration                        #
+#                                                        #
+# Properties below are specific properties for the       #
+# thread scheduling behavior. Those are the default      #
+# number of threads for executing each sort of model.    #
+#                                                        #
+# If the specified number of threads is higher than the  #
+# total number of cores in the machine, the whole        #
+# machine will be used for that models.                  #
+#                                                        #
+##########################################################
+gamma-threads    = 4
+inv-threads      = 2
+uniform-threads	 = 1
+\end{verbatim}
+
+\subsection{Logging properties}
+
+All the logs generated by jModelTest will be stored in the folder defined by the {\bf log-dir} property. The tool generates 3 different kinds of log files:
+\begin{itemize}
+\item {\bf PhyML logs}. The output of PhyML for every model optimization. This files are useful when an error occurs during the model optimization.
+\item {\bf HTML logs}. The results of the model selection in html format. This provides an easy visualization of the results.
+\item {\bf checkpoint files}. Snapshots are stored during the execution, and these can be used for restoring a previous run at the last stable point.
+\end{itemize}
+
+Using the properties one can enable or disable each log independently. If there is no {\bf log-dir}, all logs will be disabled independently on their value. Thus, for example a system administrator could comment that property in the configuration file, and users can set their own log directory in the command line:
+
+\begin{verbatim}
+checkpointing  = enabled
+html-logging   = enabled
+phyml-logging  = enabled
+# log-dir        = log     <-- This line is commented
+\end{verbatim}
+
+Now setting the custom log directory will generate all the log files there, as long as those are enabled in the configuration file. Otherwise, no log will be generated.
+
+\begin{center}
+\begin{tabular}{|l|l|l|}
+\hline
+{\bf Property} & {\bf Values} & {\bf Default} \\
+checkpointing  & enabled/disabled & enabled \\
+html-logging   & enabled/disabled & enabled \\
+phyml-logging  & enabled/disabled & enabled \\
+log-dir        & logging directory & log/ \\
+\hline
+\end{tabular}
+\end{center}
+
+\subsection{PhyML binary properties}
+
+jModelTest distribution includes PhyML binaries in exe/phyml directory. However, it is possible that you already have PhyML installed in your system and for some reason you prefer to use that distribution. In such a case, setting the {\bf global-phyml-exe} property to true, jModelTest will try to run a ``phyml'' command that is expected to be in the PATH. Also if you want to set a different path than default for finding the PhyML binaries you can change the {\bf exe-dir} property.
+
+In that directory, an executable file called ``phyml'' will have priority. If it does not exist, jModelTest will try to execute the binary called ``PhyML\_3.0\_PLATFORM''. For example, ``PhyML\_3.0\_linux64''. Thus, if you have a working phyml binary you can place it in the binaries directory with the name ``phyml''.
+
+\begin{center}
+\begin{tabular}{|l|l|l|}
+\hline
+{\bf Property} & {\bf Values} & {\bf Default} \\
+global-phyml-exe & true/false &  false \\
+exe-dir	         & path to local PhyML & exe/phyml \\ 
+\hline
+\end{tabular}
+\end{center}
+
+TIP: A workaround for setting the global PhyML executable in case that its name differs from ``phyml'' is creating a symbolic link in the binaries directory. For example:
+
+\begin{lstlisting}
+$ cd $JMODELTEST_HOME/exe/phyml
+$ ln -s phyml `which $MY_PHYML_GLOBAL_EXECUTABLE`
+\end{lstlisting}
+
+\subsection{Hybrid shared-distributed memory execution properties}
+
+The following properties are used only with the hybrid memory parallel execution. The dynamic shared memory scheduler can use a different number of threads for model optimization depending on the model parameters. For example, models with rate heterogeneity will take a longer time to optimize the parameters. This way, assigning a different number of threads used for the parallel optimization of each model will improve the efficiency by minimizing the parallel overhead.
+
+Note that for enabling the hybrid memory parallelization you need to create your own PhyML binaries applying a patch directly to the PhyML source code and compiling it for you system. You can ask us about it.
+
+The default values work fine for a hybrid execution using 8 and 16 core-nodes.
+
+\begin{center}
+\begin{tabular}{|l|l|l|}
+\hline
+{\bf Property} & {\bf Values} & {\bf Default} \\
+gamma-threads  & \#threads for +G and +I+G models & 4 \\
+inv-threads    & \#threads for +I models & 2 \\
+uniform-threads& \#threads for models without rate heterogeneity & 1 \\
+\hline
+\end{tabular}
+\end{center}
diff --git a/manual/sec-quickstart.tex b/manual/sec-quickstart.tex
new file mode 100644
index 0000000..c681159
--- /dev/null
+++ b/manual/sec-quickstart.tex
@@ -0,0 +1,315 @@
+\section{Getting Started}
+
+\subsection{Operating Systems}
+
+Since jModelTest is a Java application, it can be used in every OS that can execute a Java Runtime Environment (JRE). The most common Operating Systems and many other include a JRE (OpenJDK, Sun JRE, ...), or at least it is possible to download one. However, jModelTest depends on third-party binaries (PhyML), that are distributed for Windows, Linux and OsX, and it is even possible to download PhyML sources (http://code.google.com/p/phyml) and compile them for a particular architecture.
+
+\subsection{Working with the repository}
+
+This tool is distributed under GPL v3 license. The source code is freely available at google code repository. You can checkout the repository at \url{http://code.google.com/p/jmodeltest2/source}.
+
+\subsection{User interfaces}
+
+jModelTest can be executed from two different user interfaces, GUI or Console. The Graphical User Interface (GUI) is intended for execution on common desktop computers with multicore processors -most users will probably use this. On the other hand, HPC environments, like multicore clusters, require a non-interactive processing (batch processes), so jModelTest has to be executed from the Command Console Interface. Results are given in plain text format, but an html log is also created.
+
+\subsubsection{Graphical User Interface}
+
+\begin{enumerate}
+\item Execute the script for the Graphical User Interface (runjmodeltest-gui.sh). The main jModelTest frame should pop up on the screen:
+
+\begin{center}
+\includegraphics[width=.9\textwidth]{images/main-window}
+\end{center}
+
+\item Load an input alignment file using the {\bf File/Load Alignment} option.
+
+\item Go to {\bf Analysis/Compute Likelihood Scores} and select the candidate models and the options for model optimization (optionally you can set a base topology from a file). Press Enter or the {\bf Compute Likelihoods} button.
+
+\begin{center}
+\includegraphics[width=.6\textwidth]{images/lkl-settings}
+\end{center}
+
+\item Perform statistical selection among the optimized models. For example, we can calculate the Bayesian Information Criterion using {\bf Analysis/Do BIC calculations...} option, or any other. You can find a Criteria comparison in terms of accuracy in the \href{http://www.nature.com/nmeth/journal/v9/n8/extref/nmeth.2109-S1.pdf}{supplementary material} of the \href{http://www.nature.com/nmeth/journal/v9/n8/full/nmeth.2109.html}{jModelTest publication}.
+
+\begin{center}
+\includegraphics[width=.6\textwidth]{images/bic}
+\end{center}
+
+The results will be shown in the main console.
+
+\item Take a look at the results table in {\bf Results/Show results table}. Best model is the one with the lowest criterion value (BIC column in the example) and therefore delta = 0.
+
+\begin{center}
+\includegraphics[width=.9\textwidth]{images/results}
+\end{center}
+
+\item Build a consensus tree from a given selection criteria using {\bf Analysis/Model-averaged phylogeny}:
+
+\begin{center}
+\includegraphics[width=.6\textwidth]{images/consensus}
+\end{center}
+
+\item Finally, you can save the results displayed in the main console using {\bf Edit/Save console}. Alternatively, you can get a formatted HTML document using {\bf Results/Build HTML log}:
+
+\begin{center}
+\includegraphics[width=.9\textwidth]{images/html-log}
+\end{center}
+
+Take a look at Section \ref{sec:gui} for further information.
+
+\end{enumerate}
+
+\subsubsection{Command Console Interface}
+
+\begin{enumerate}
+\item Execute the following command line:
+\begin{lstlisting}
+$ java -jar jModelTest.jar -d example-data/aP6.fas -g 4 -i -f -AIC -BIC -a
+\end{lstlisting}
+
+This will test all 88 models (gamma models with 4 rate categories), and then perform the model selection using Akaike (AIC) and Bayesian (BIC) criteria, calculating also a model averaged phylogeny (-a).
+
+See Section~\ref{sec:arguments} for information about supported arguments.
+
+\item This will generate the following output:
+
+\begin{enumerate}
+
+\item Header:
+
+\begin{lstlisting}
+----------------------------- jModeltest 2.0 -----------------------------
+(c) 2011-onwards Diego Darriba, David Posada,
+Department of Biochemistry, Genetics and Immunology
+University of Vigo, 36310 Vigo, Spain. e-mail: ddarriba at udc.es, dposada at uvigo.es
+--------------------------------------------------------------------------------
+Wed Oct 05 12:56:47 CEST 2011
+Linux 2.6.38-11-generic-pae, arch: i386, bits: 32, numcores: 2
+
+jModelTest 2.0  Copyright (C) 2011 Diego Darriba, David Posada
+This program comes with ABSOLUTELY NO WARRANTY
+This is free software, and you are welcome to redistribute it
+under certain conditions
+ 
+Notice: This program may contain errors. Please inspect results carefully.
+\end{lstlisting}
+
+\item Execution options:
+
+\begin{lstlisting} 
+Arguments = -d example-data/aP6.fas -g 4 -i -f -AIC -BIC -a
+
+Reading data file "aP6.fas"... OK.
+  number of sequences: 6
+  number of sites: 631
+ 
+ 
+---------------------------------------------------------------
+*                                                             *
+*        COMPUTATION OF LIKELIHOOD SCORES WITH PHYML          *
+*                                                             *
+---------------------------------------------------------------
+ 
+::Settings::
+ Phyml version = 3.0
+ Phyml binary = PhyML_3.0_linux32
+ Candidate models = 24
+  number of substitution schemes = 3
+  including models with equal/unequal base frequencies (+F)
+  including models with/without a proportion of invariable sites (+I)
+  including models with/without rate variation among sites (+G) (nCat = 4)
+ Optimized free parameters (K) = substitution parameters + 9 branch lengths + topology 
+ Base tree for likelihood calculations = ML tree
+ Tree topology search operation = NNI
+computing likelihood scores for 24 models with Phyml 3.0
+\end{lstlisting}
+
+\item Real time optimization results (progress):
+
+\begin{lstlisting}
+::Progress::
+
+Model 		 Exec. Time 	 Total Time 	 -lnL
+-------------------------------------------------------------------------
+JC		00h:00:00:01	00h:00:00:01	1114,9772
+JC+G		00h:00:00:04	00h:00:00:05	1106,4431
+...
+GTR+G		00h:00:00:06	00h:00:06:07	1054,7203
+GTR+I+G		00h:00:01:02	00h:00:07:05	1051,8403
+\end{lstlisting}
+
+\item Sorted and complete optimization results:
+
+\begin{lstlisting}
+   Model = JC
+   partition = 000000
+   -lnL = 1114.9772
+   K = 10 
+ 
+   Model = JC+I
+   partition = 000000
+   -lnL = 1103.1113
+   K = 11
+   p-inv = 0.9080 
+
+...
+
+   Model = GTR+I+G
+   partition = 012345
+   -lnL = 1051.8403
+   K = 20
+   freqA = 0.4235 
+   freqC = 0.1520 
+   freqG = 0.2022 
+   freqT = 0.2224 
+   R(a) [AC] =  0.8709
+   R(b) [AG] =  0.4152
+   R(c) [AT] =  0.6049
+   R(d) [CG] =  1.2523
+   R(e) [CT] =  0.9482
+   R(f) [GT] =  1.0000
+   p-inv = 0.5940
+   gamma shape = 0.0120 
+ 
+ 
+Computation of likelihood scores completed. It took 00h:00:07:05.
+\end{lstlisting}
+
+\item Selected Information Criteria (best model and all models sorted according to each criterion):
+
+\begin{lstlisting}
+---------------------------------------------------------------
+*                                                             *
+*             AKAIKE INFORMATION CRITERION (AIC)              *
+*                                                             *
+---------------------------------------------------------------
+ 
+ Model selected: 
+   Model = F81+I
+   partition = 000000
+   -lnL = 1053.5428
+   K = 14
+   freqA = 0.4200 
+   freqC = 0.1558 
+   freqG = 0.2015 
+   freqT = 0.2227 
+   p-inv = 0.9030 
+ 
+ML tree (NNI) for the best AIC model = (((P5:0.01021829,P4:0.00719757):0.00151199,(P6:0.00680664,P1:0.00000003):0.00204596):0.01267608,P3:0.01665876,P2:0.00459802);
+ 
+ 
+* AIC MODEL SELECTION : Selection uncertainty
+ 
+Model             -lnL    K         AIC      delta      weight cumWeight
+------------------------------------------------------------------------ 
+F81+I        1053.5428   14   2135.0855     0.0000      0.4332    0.4332 
+HKY+I        1053.0700   15   2136.1401     1.0545      0.2557    0.6890 
+F81+I+G      1053.5430   15   2137.0859     2.0004      0.1594    0.8483
+...
+K80          1114.5049   11   2251.0098   115.9243   2.91e-026    1.0000 
+SYM          1114.4117   15   2258.8235   123.7380   5.85e-028    1.0000
+------------------------------------------------------------------------
+-lnL:	negative log likelihod
+ K:	number of estimated parameters
+ AIC:	Akaike Information Criterion
+ delta:	AIC difference
+ weight:	AIC weight
+ cumWeight:	cumulative AIC weight
+ 
+ 
+* AIC MODEL SELECTION : Confidence interval
+ 
+There are 24 models in the 100% confidence interval: [ F81+I HKY+I F81+I+G HKY+I+G F81+G GTR+I HKY+G GTR+I+G GTR+G F81 HKY GTR JC+I K80+I JC+I+G K80+I+G JC+G K80+G SYM+I SYM+I+G SYM+G JC K80 SYM ] 
+\end{lstlisting}
+
+\item Consensus tree of the optimized phylogenies using the criterion weights:
+ 
+\begin{lstlisting}
+---------------------------------------------------------------
+*                                                             *
+*                    MODEL AVERAGED PHYLOGENY                 *
+*                                                             *
+---------------------------------------------------------------
+ 
+Selection criterion: . . . . AIC
+Confidence interval: . . . . 1.00
+Consensus type:. . . . . . . 50% majority rule
+ 
+ 
+Using 24 models in the 1.00 confidence interval = F81+I HKY+I F81+I+G HKY+I+G F81+G GTR+I HKY+G GTR+I+G GTR+G F81 HKY GTR JC+I K80+I JC+I+G K80+I+G JC+G K80+G SYM+I SYM+I+G SYM+G JC K80 SYM  
+
+Bipartitions included in the consensus tree
+ 
+    123456
+    ****** ( 1.0 )
+    ****-- ( 1.0 )
+    **---- ( 0.94244 )
+    --**-- ( 1.0 )
+
+ 
+                        +-----------6 P4
+                      +-8
+                      | +----------------5 P5
++---------------------9
+|                     |  +-4 P1
+|                     +--7
+|                        +----------3 P6
+|
++------2 P2
+|
++---------------------------1 P3
+
+ 
+(P3:0.016613,P2:0.004598,((P6:0.006790,P1:0.000000)1.00:0.002046,(P5:0.010191,P4:0.007198)0.94:0.001510)1.00:0.012665);
+ 
+Note: this tree is unrooted. Branch lengths are the expected number of substitutions per site. Labels next to parentheses represent phylogenetic uncertainty due to model selection (see documentation)
+\end{lstlisting}
+
+\item Also a HTML log is automatically stored in the ``log'' directory.
+
+\end{enumerate}
+\end{enumerate}
+
+\subsection{High Performance Environments}
+
+\subsubsection{Shared memory architectures (multicore systems)}
+
+Both the GUI and Console interfaces can be used for shared memory architectures. See Graphical User Interface or Command Console Interface. In some dedicated HPC environments you can only use the console interface, for example when using a bath-queuing system like Oracle Grid Engine. Additionally, in the console version you can specify the number of threads you want to use using the -tr'' option. By default, the total number of cores in the machine is used.
+
+\subsubsection{Distributed memory architectures (HPC clusters)}
+
+\begin{enumerate}
+\item Besides the multithreading support, it is possible to run jModelTest in a cluster. This feature has been implemented using a Java message-passing (MPJ) library, MPJ Express (http://mpj-express.org/). To execute jModelTest in a cluster environment you have to:
+
+\begin{lstlisting}
+$ export $JMODELTEST_HOME=[path_to_jModelTest]
+$ cd $JMODELTEST_HOME
+$ tar zvxf mpj.tar.gz
+$ export MPJ_HOME=$JMODELTEST_HOME/mpj
+$ export PATH=$MPJ_HOME/bin:$PATH
+$ cp $JMODELTEST_HOME/extra/machines $JMODELTEST_HOME
+\end{lstlisting}
+
+You can also add the last two lines to ~/.bashrc to automatically set these variables at console startup.
+
+\item \$JMODELTEST\_HOME/machines file contains the set of computing nodes where the mpj processes will be executed. By default it points to the localhost machine, so you should change it if you want to run a parallel execution over a cluster machine, just writing on each line the particular computing nodes (e.g. see filecluster8.conf.template).
+
+\item Start the MPJ Express daemons:
+
+\begin{lstlisting}
+$ mpjboot machines
+\end{lstlisting}
+
+The application ``mpjboot'' should be in the execution path (it is located at \$MPJ\_HOME/bin). A ssh service must be running in the machines listed in the machines file. Moreover, port 10000 should be free. For more details refer to the MPJ Express documentation.
+
+\item Run jModelTest. For this, the jModelTest distribution provides a bash script: 'runjmodeltest-cluster.sh'
+
+The basic syntax is:
+
+./runjmodeltest-cluster.sh \$NUMBER\_OF\_PROCESSORS \$APPLICATION\_PARAMETERS
+
+\begin{lstlisting}
+$ ./runjmodeltest-cluster.sh 2 -d example-data/aP6.fas -s 11 -i -g 4 -f -AIC -a
+\end{lstlisting}
+
+\end{enumerate}
diff --git a/manual/sec-theory.tex b/manual/sec-theory.tex
new file mode 100644
index 0000000..94d8157
--- /dev/null
+++ b/manual/sec-theory.tex
@@ -0,0 +1,199 @@
+\section{Theoretical Background}
+
+All phylogenetic methods make assumptions, whether explicit or implicit, about the process of DNA substitution \citep{Felsenstein-1988}. Consequently, all the methods of phylogenetic inference depend on their underlying substitution models. To have confidence in inferences it is necessary to have confidence in the models \citep{Goldman-1993b}. Because of this, it makes sense to justify the use of a particular model. Statistical model selection is one way of doing this. For a review of mo [...]
+
+
+\subsection{Models of nucleotide substitution}
+
+Models of evolution are sets of assumptions about the process of nucleotide substitution. They describe the different probabilities of change from one nucleotide to another along a phylogenetic tree, allowing us to choose among different phylogenetic hypotheses to explain the data at hand. Comprehensive reviews of model of evolution are offered elsewhere. jmodeltest implementes all 203 types of reversible substitution matrices, with when combined with unequal/equal base frequencies, gamm [...]
+
+\begin{table}[h!]
+\caption{Named substitution models jModelTest2 (a few of the 1624 possible). Any of these models can include invariable sites (+I), rate variation among sites (+G), or both (+I+G).}
+\footnotesize
+\begin{tabular}{l l l l l l}
+\hline
+{\bf Model} & {\bf Reference} & {\bf Free}   & {\bf Base}  & {\bf Substitution rates} & {\bf Substitution} \\
+            &                 & {\bf param.} & {\bf freq.} &                          & {\bf code} \\
+\hline
+JC & \citep{Jukes-1969} & 0 & equal & AC=AG=AT=CG=CT=GT & 000000 \\
+\hline
+F81 & \citep{Felsenstein-1981} & 3 & unequal & AC=AG=AT=CG=CT=GT & 000000 \\
+\hline
+K80 & \citep{Kimura-1980} & 1 & equal & AC=AT=CG=GT;AG=GT & 010010 \\
+\hline
+HKY & \citep{Hasegawa-1985} & 4 & unequal & AC=AT=CG=GT;AG=GT & 010010 \\
+\hline
+TrNef & \citep{Tamura-1993} & 2 & equal & AC=AT=CG=GT;AG;GT & 010020 \\
+\hline
+TrN & \citep{Tamura-1993} & 5 & unequal & AC=AT=CG=GT;AG;GT & 010020 \\
+\hline
+TPM1 & =K81 \citep{Kimura-1981} & 2 & equal & AC=GT;AG=CT;AT=CG & 012210 \\
+\hline
+TPM1uf & \citep{Kimura-1981} & 5 & unequal & AC=GT;AG=CT;AT=CG & 012210 \\
+\hline
+TPM2 & & 2 & equal & AC=AT;CG=GT;AG=CT & 010212 \\
+\hline
+TPM2uf & & 5 & unequal & AC=AT;CG=GT;AG=CT & 010212 \\
+\hline
+TPM3 & & 2 & equal & AC=AT;AG=GT;AG=CT & 012012 \\
+\hline
+TPM3uf & & 5 & unequal & AC=CG;AT=GT;AG=CT & 012012 \\
+\hline
+TIM1 & \citep{Posada-2003} & 3 & equal & AC=GT;AT=CG;AG;CT & 012230 \\
+\hline
+TIM1uf & \citep{Posada-2003} & 6 & unequal & AC=GT;AT=CG;AG;CT & 012230 \\
+\hline
+TIM2 & & 3 & equal & AC=AT;CG=GT;AG;CT & 010232 \\
+\hline
+TIM2uf & & 6 & unequal & AC=AT;CG=GT;AG;CT & 010232 \\
+\hline
+TIM3 & & 3 & equal & AC=CG;AT=GT;AG;CT & 012032 \\
+\hline
+TIM3uf & & 6 & unequal & AC=CG;AT=GT;AG;CT & 012032 \\
+\hline
+TVMef & \citep{Posada-2003} & 4 & equal & AC;CG;AT;GT;AG=CT & 012314 \\
+\hline
+TVM & \citep{Posada-2003} & 7 & unequal & AC;CG;AT;GT;AG=CT & 012314 \\
+\hline
+SYM & \citep{Zharkikh-1994} & 5 & equal & AC;CG;AT;GT;AG;CT & 012345 \\
+\hline
+GTR & =REV \citep{Tavare-1986} & 8 & unequal & AC;CG;AT;GT;AG;CT & 012345 \\
+\hline
+\end{tabular}
+\label{table-models}
+\end{table}
+
+
+\subsection{Sequential Likelihood Ratio Tests (sLRT)}
+\label{sec:slrt}
+
+In traditional statistical theory, a widely accepted statistic for testing the goodness of fit of models is the likelihood ratio test (LRT): 
+\[
+LRT=2(l_1-l_0)
+\]
+where $l_1$ is the maximum likelihood under the more parameter-rich, complex model (alternative hypothesis) and $l_0$ is the maximum likelihood under the less parameter-rich simple model (null hypothesis).
+ When the models compared are nested (the null hypothesis is a special case of the alternative hypothesis) and the null hypothesis is correct, the LRT statistic is asymptotically distributed as a χ2 with q degrees of freedom, where q is the difference in number of free parameters between the two models \citep{Kendall-1979, Goldman-1993b}. Note that, to preserve the nesting of the models, the likelihood scores need to be estimated upon the same tree. When some parameter is fixed at its bo [...]
+
+\subsection{Hierarchical Likelihood Ratio Tests (hLRT)}
+\label{sec:hlrt}
+
+Likelihood ratio tests can be carried out sequentially by adding parameters (forward selection) to a simple model (JC), or by removing parameters (backward selection) from a complex model (GTR+I+G) in a specific order or hierarchy (hLRT; see Figure below). The performance of hierarchical LRTs for phylogenetic model selection has been discussed by \citet{Posada-2004}.
+
+\begin{center}
+\includegraphics[width=.9\textwidth]{images/hLRT.png}
+\end{center}
+
+Figure. Example of a particular forward hierarchy of likelihood ratio tests for 24 models. At any level the null hypothesis (model on top) is either accepted (A) or rejected (R). In this example the model selected is GTR+I.
+
+\subsection{Dynamical Likelihood Ratio Tests (dLRT)}
+\label{sec:dlrt}
+
+Alternatively, the order in which parameters are added or removed can be selected automatically. One option to accomplish this is to add the parameter that maximizes a significant gain in likelihood during forward selection, or to add the parameter that minimizes a non-significant loss in likelihood during backward selection \citep{Posada-2001a}. In this case, the order of the tests is not specified a priori, but it will depend on the particular data.
+
+\begin{center}
+\includegraphics[width=.9\textwidth]{images/dLRT.png}
+\end{center}
+
+Figure. Dynamical likelihood ratio tests for 24 models. At any level a hypothesis is either accepted (A) or rejected (R). In this example the model selected is GTR+I. Hypotheses tested are: F = base frequencies; S = substitution type; I = proportion of invariable sites; G = gamma rates.
+
+\subsection{Information Criteria}
+\subsubsection{Akaike Information Criterion}
+\label{sec:aic}
+
+The Akaike information criterion (AIC, \citep{Akaike-1974} is an asymptotically unbiased estimator of the Kullback-Leibler information quantity \citep{Kullback-1951}. We can think of the AIC as the amount of information lost when we use a specific model to approximate the real process of molecular evolution. Therefore, the model with the smallest AIC is preferred. The AIC is computed as:
+
+\[
+AIC=-2l+2k
+\]
+
+where l is the maximum log-likelihood value of the data under this model and Ki is the number of free parameters in the model, including branch lengths if they were estimated \emph{de novo}. When sample size ($n$) is small compared to the number of parameters (say, $\frac{n}{K} < 40$) the use of a second order AIC, AICc \citep{Sugiura-1978, Hurvich-1989}, is recommended:
+
+\[
+AIC_c=AIC+\frac{(2k(k+1))}{(n-k-1)}
+\]
+
+The AIC compares several candidate models simultaneously, it can be used to compare both nested and non-nested models, and model-selection uncertainty can be easily quantified using the AIC differences and Akaike weights (see Model uncertainty below). \citet{Burnham-2003} provide an excellent introduction to the AIC and model selection in general.
+
+\subsubsection{Bayesian Information Criterion}
+\label{sec:bic}
+
+An alternative to the use of the AIC is the Bayesian Information Criterion (BIC) \citep{Schwarz-1978}:
+
+\[
+BIC=-2l + k log(n)
+\]
+
+Given equal priors for all competing models, choosing the model with the smallest BIC is equivalent to selecting the model with the maximum posterior probability. Alternatively, Bayes factors for models of molecular evolution can be calculated using reversible jump MCMC \citep{Huelsenbeck-2004}. We can easily use the BIC instead of the AIC to calculate BIC differences or BIC weights.
+
+\subsubsection{Performance Based Selection}
+\label{sec:dt}
+
+\citet{Minin-2003} developed a novel approach that selects models on the basis of their phylogenetic performance, measured as the expected error on branch lengths estimates weighted by their BIC. Under this decision theoretic framework (DT) the best model is the one with that minimizes the risk function:
+
+\[
+C_i \approx \sum_{j=1}^n||\hat{B_i} - \hat{B_j}||\frac{e^{\frac{-BIC_j}{2}}}{\sum_{j=1}^R(e^\frac{-BIC_i}{2})}
+\]
+
+where 
+
+\[
+||\hat{B_i} - \hat{B_j}||^2 = \sum_{l=1}^{2t-3}(\hat{B_{il}} - \hat{B_{jl}})^2
+\]
+
+and where t is the number of taxa. Indeed, simulations suggested that models selected with this criterion result in slightly more accurate branch length estimates than those obtained under models selected by the hLRTs \citep{Minin-2003, Abdo-2005}.
+
+\subsection{Model Uncertainty}
+
+The AIC, Bayesian and DT methods can rank the models, allowing us to assess how confident we are in the model selected. For these measures we could present their differences ($\Delta$). For example, for the $i^{th}$ model, the AIC (BIC, DT) difference is:
+
+\[
+\Delta_i = AIC_i - min(AIC)
+\]
+
+where $min(AIC)$ is the smallest AIC value among all candidate models. The AIC differences are easy to interpret and allow a quick comparison and ranking of candidate models. As a rough rule of thumb, models having $\Delta_i$ within 1-2 of the best model have substantial support and should receive consideration. Models having $\Delta_i$ within 3-7 of the best model have considerably less support, while models with $\Delta_i > 10$ have essentially no support. Very conveniently, we can use [...]
+
+\[
+\omega_i = \frac{e^{\frac{-\Delta_i}{2}}}{\sum_{r=1}^R(e^\frac{-\Delta_r}{2})}
+\]
+
+which can be interpreted, from a Bayesian perspective, as the probability that a model is the best approximation to the truth given the data. The weights for every model add to 1, so we can establish an approximate 95\% confidence set of models for the best models by summing the weights from largest to smallest from largest to smallest until the sum is 0.95 \citep{Burnham-1998, Burnham-2003}. This interval can also be set up stochastically (see above ``Model selection and averaging''). N [...]
+
+\subsection{Model Averaging}
+\label{sec:model-averaging}
+
+Often there is some uncertainty in selecting the best candidate model. In such cases, or just one when does not want to rely on a single model, inferences can be drawn from all models (or an optimal subset) simultaneously. This is known as model averaging or multimodel inference. See \citet{Posada-2004} and references therein for an explanation of application of these techniques in the context of phylogenetics.
+
+Within the AIC or Bayesian frameworks, it is straightforward to obtain a model-averaged estimate of any parameter \citep{Madigan-1994, Raftery-1996, Hoeting-1999, Wasserman-2000, Burnham-2003, Posada-2003}. For example, a model-averaged estimate of the substitution rate between adenine and cytosine using the Akaike weights for R candidate models would be:
+
+\[
+\widehat{\overline{\phi_{A-C}}} = \frac{\sum_{r=1}^R \omega_i I_{\phi_{A-C}}(M_i) \phi_{A-C_i}}{\omega_+(\phi_{A-C})}
+\]
+
+where
+
+\[
+\omega_+(\phi_{A-C}) = \sum_{i=1}^R \omega_i I_{\phi_{A-C}}(M_i)
+\]
+
+and
+
+\[
+I_{\phi_{A-C}}(M_i) = \left\{ 
+\begin{array}{c l}
+1 &  \mbox{$\phi_{A-C}$ is in model $M_i$}\\
+0 & \mbox{otherwise}
+\end{array}
+\right.
+\]
+
+Note that need to be careful when interpreting the relative importance of parameters. When the number of candidate models is less than the number of possible combinations of parameters, the presence-absence of some pairs of parameters can be correlated, and so their relative importances.
+
+\subsection{Model Averaged Phylogeny}
+\label{sec:consensus}
+
+Indeed, the averaged parameter could be the topology itself, so we could construct a model-averaged estimate of phylogeny. For example, one could estimate a ML tree for all models (or a best subset) and with those one could build a weighted consensus tree using the corresponding Akaike weights. See \citet{Posada-2004} for a practical example.
+
+\subsection{Parameter Importance}
+\label{sec:param-importances}
+
+It is possible to estimate the relative importance of any parameter by summing the weights across all models that include the parameters we are interested in. For example, the relative importance of the substitution rate between adenine and cytosine across all candidate models is simply the denominator above, $\omega_+(\phi_{A-C})$
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/ApplicationOptions.java b/src/main/java/es/uvigo/darwin/jmodeltest/ApplicationOptions.java
new file mode 100644
index 0000000..f632b4e
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/ApplicationOptions.java
@@ -0,0 +1,764 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.PushbackReader;
+import java.io.Serializable;
+import java.io.StringReader;
+import java.util.Vector;
+
+import pal.alignment.Alignment;
+import pal.datatype.DataType;
+import pal.tree.TreeParseException;
+import es.uvigo.darwin.jmodeltest.exception.AlignmentParseException;
+import es.uvigo.darwin.jmodeltest.io.AlignmentReader;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.model.ModelConstants;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+/**
+ * This class gathers the parameters of a single execution of jModelTest 2. It
+ * is a singleton class.
+ * 
+ * @author Diego Darriba
+ * 
+ */
+public class ApplicationOptions implements Serializable {
+
+	private static final long serialVersionUID = -3961572952922591321L;
+	private static final int AMBIGUOUS_DATATYPE_STATE = 4;
+
+	/** Tree topology search algorithms */
+	public static enum TreeSearch {
+		NNI, SPR, BEST
+	};
+
+	private static ApplicationOptions instance;
+	private static Vector<String> testOrder;
+
+	private File inputDataFile, inputTreeFile;
+	private File alignmentFile, treeFile;
+	private File ckpFile;
+	private File logFile;
+	private Alignment alignment;
+	private boolean isAmbiguous;
+	private boolean forceCheckULnL = false;
+	private double unconstrainedLnL = 0.0d;
+	private int numPatterns = 0;
+
+	// Newick user tree
+	private String userTree;
+
+	/*
+	 * Number of threads for shared memory execution or static thread scheduling
+	 */
+	private int numberOfThreads = Runtime.getRuntime().availableProcessors();
+	/*
+	 * Number of threads for dynamic thread scheduling
+	 */
+	private File machinesFile;
+
+	public boolean threadScheduling = false;
+
+	public boolean doAIC = false;
+	public boolean doAICc = false;
+	public boolean doBIC = false;
+	public boolean doDT = false;
+	public boolean doDLRT = false;
+	public boolean doHLRT = false;
+	// whether to include the parameter base frequencies
+	public boolean doF = false;
+	public boolean doI = false; // whether to include the parameter pinv
+	public boolean doG = false; // whether to include gamma
+	public int numGammaCat = 4;
+
+	public boolean backwardHLRTSelection = false;
+	public double confidenceLevelHLRT = 0.01;
+
+	public boolean writePAUPblock = false;
+	public boolean doImportances = false;
+	public boolean doModelAveraging = false;
+	public boolean doAveragedPhylogeny = false;
+	public double confidenceInterval = 1.0; // by default include all models
+
+	// for specific simulations
+	public boolean doingSimulations = false;
+	public String simulationsName = "";
+
+	// whether to use the same user fixed topology for all calculations
+	public boolean userTopologyExists = false;
+	// whether to use the same BIONJ-JC fixed tree for all calculations
+	public boolean fixedTopology = false;
+	// whether to optimize the BIONJ-model tree by ML
+	public boolean optimizeMLTopology = true;
+
+	public TreeSearch treeSearchOperations = TreeSearch.BEST;
+
+	// Threshold for the guided search mode. A QST == 0.0 means no model
+	// but the GTR one is optimized. A high QST means the whole set of
+	// set of models will be optimized.
+	private double guidedSearchThreshold = 0.0d;
+	private boolean doClusteringSearch = false;
+	private int heuristicInformationCriterion = InformationCriterion.IC_BIC;
+
+	private int numSites;
+	private int numTaxa;
+	private int numBranches;
+	private int numInvariableSites;
+	private int numModels;
+
+	private String executionName;
+	
+	public String consensusType = "50% majority rule"; // consensus type
+														// for model
+														// averaged
+														// phylogeny
+	public boolean countBLasParameters = true; // whether to count branch
+	// lengths as parameters
+
+	private int substTypeCode = 0; // number of substitution types to
+									// consider
+	private ApplicationOptions() { }
+
+	public void createCkpFile() {
+		if (ckpFile != null && ckpFile.exists())
+			return;
+		
+		try {
+			if (executionName == null) {
+				executionName = Utilities.getCurrentTime("yyyyMMddHHmmss");
+			}
+			if (ModelTestConfiguration.isCkpEnabled() && getInputFile() != null) {
+				ckpFile = new File(ModelTestConfiguration.getLogDir() + File.separator + getInputFile().getName() 
+						+ "." + executionName + ".ckp");
+			} else {
+				ckpFile = File.createTempFile("jmodeltest", ".ckp");
+				ckpFile.deleteOnExit();
+			}
+		} catch (IOException e) {
+			System.err.println("Error creating checkpointing file");
+		}
+	}
+	
+	public void createLogFile() {
+		try {
+			if (executionName == null) {
+				executionName = Utilities.getCurrentTime("yyyyMMddHHmmss");
+			}
+			if (ModelTestConfiguration.isPhymlLogEnabled() && getInputFile() != null) {
+				logFile = new File(ModelTestConfiguration.getLogDir() + File.separator + getInputFile().getName() 
+						+ ".phyml." + executionName + ".log");
+			} else {
+				logFile = File.createTempFile("jmodeltest-phyml", ".log");
+				logFile.deleteOnExit();
+			}
+		} catch (IOException e) {
+			System.err.println("Error creating PhyML log file");
+		}
+	}
+	
+	public void deleteLogFile() {
+		if (!ModelTestConfiguration.isPhymlLogEnabled()) {
+			logFile.delete();
+		}
+	}
+	
+	// This method copies the input files into the scratch.
+	// It is important to speed up the I/O in distributed memory.
+	public void buildWorkFiles() throws IOException {
+		File workDataFile = getAlignmentFile();
+		if (!workDataFile.exists()) {
+			workDataFile.createNewFile();
+			workDataFile.deleteOnExit();
+		}
+		try {
+			String alnStr = ModelTestService.readAlignment(inputDataFile, alignmentFile);
+
+			PushbackReader pr = new PushbackReader(
+					new StringReader(alnStr));
+			setAlignment(
+					AlignmentReader.createAlignment(
+							new PrintWriter(System.err), pr, true));
+		} catch (AlignmentParseException e) {
+			e.printStackTrace();
+		}
+
+		if (userTree != null) {
+			File workTreeFile = getTreeFile();
+			if (!workTreeFile.exists()) {
+				workTreeFile.createNewFile();
+				workTreeFile.deleteOnExit();
+			}
+			TextOutputStream out = new TextOutputStream(getTreeFile()
+					.getAbsolutePath());
+			out.print(getUserTree());
+			out.close();
+		}
+	}
+
+	public static ApplicationOptions getInstance() {
+		if (instance == null) {
+			instance = new ApplicationOptions();
+		}
+		return instance;
+	}
+
+	/****************************
+	 * setCandidateModels *********************** * Build the set of candidate
+	 * models * *
+	 ************************************************************************/
+
+	public void setCandidateModels() {
+		boolean includeModel;
+
+		// fill in list of models
+		ModelTest.setCandidateModels(new Model[getNumModels()]);
+
+		if (substTypeCode < 4) {
+			int j = 0;
+			for (int i = 0; i < ModelTest.MAX_NUM_MODELS; i++) {
+				includeModel = true;
+				if (ModelConstants.substType[i] > substTypeCode)
+					includeModel = false;
+				if (!doF && !ModelConstants.equalBaseFrequencies[i]) // is F
+					includeModel = false;
+				if (!doI
+						&& (ModelConstants.rateVariation[i] == 1 || ModelConstants.rateVariation[i] == 3))
+					includeModel = false;
+				if (!doG
+						&& (ModelConstants.rateVariation[i] == 2 || ModelConstants.rateVariation[i] == 3))
+					includeModel = false;
+
+				if (includeModel) {
+					loadModelConstraints(ModelTest.getCandidateModel(j), j, i);
+					j++;
+				}
+			}
+		} else {
+			int j = 0;
+			for (int ratesCount = 1; ratesCount <= 6; ratesCount++) {
+				for (String partition : ModelConstants.fullModelSet
+						.get(ratesCount)) {
+					boolean baseFrequencies;
+					int rateVariation;
+					for (int k = 0; k < 8; k++) {
+						baseFrequencies = (k / 4 == 1);
+						rateVariation = (k % 4);
+						includeModel = true;
+						if (!doF && baseFrequencies)
+							includeModel = false;
+						if (!doI && (rateVariation == 1 || rateVariation == 3))
+							includeModel = false;
+						if (!doG && (rateVariation == 2 || rateVariation == 3))
+							includeModel = false;
+						if (includeModel) {
+							loadModelConstraints(
+									ModelTest.getCandidateModel(j), j,
+									partition, baseFrequencies, rateVariation,
+									ratesCount);
+							j++;
+						}
+					}
+				}
+			}
+		}
+
+		if (ModelTest.buildGUI || ModelTest.testingOrder == null) {
+			// set set of hypotheses for hLRTs in default order
+			testOrder = new Vector<String>();
+			// we need to reinitialize the hypotheses list in case it existed
+			// before..
+			testOrder.removeAllElements();
+
+			if (doF)
+				testOrder.add("freq");
+
+			switch (substTypeCode) {
+			case 0:
+				testOrder.add("titv");
+				testOrder.add("2ti4tv");
+				break;
+			case 1:
+				testOrder.add("titv");
+				testOrder.add("2ti");
+				testOrder.add("2tv");
+				break;
+			case 2:
+			case 3:
+			case 4:
+				testOrder.add("titv");
+				testOrder.add("2ti");
+				testOrder.add("2tv");
+				testOrder.add("4tv");
+			}
+
+			if (doI)
+				testOrder.add("pinv");
+
+			if (doG)
+				testOrder.add("gamma");
+
+			// ModelTest.testingOrder.removeAllElements();
+
+			ModelTest.testingOrder = testOrder;
+		}
+	}
+
+	/************************
+	 * loadModelConstraints ************************ * Loads initial definitions
+	 * of models * * *
+	 ***********************************************************************/
+
+	public void loadModelConstraints(Model currentModel, int order, int modelNo) {
+		int modelParameters, BL;
+		boolean pF, pT, pV, pR, pI, pG;
+
+		// initialize
+		pT = pV = pR = pI = pG = false;
+
+		pF = !ModelConstants.equalBaseFrequencies[modelNo];
+
+		if (ModelConstants.numTransitions[modelNo] == 1
+				&& ModelConstants.numTransversions[modelNo] == 1) {
+			pT = true;
+		} else if (ModelConstants.numTransitions[modelNo] > 1
+				|| ModelConstants.numTransversions[modelNo] > 1) {
+			pR = true;
+		}
+
+		/*
+		 * find out first wich models in phyml give titv if
+		 * (Model.numTransitions[modelNo] == 2 ||
+		 * Model.numTransversions[modelNo] == 2) { pV = true; }
+		 */
+
+		switch (ModelConstants.rateVariation[modelNo]) {
+		case 1:
+			pI = true;
+			break;
+		case 2:
+			pG = true;
+			break;
+		case 3:
+			pI = true;
+			pG = true;
+			break;
+		}
+
+		if (countBLasParameters)
+			BL = getNumBranches();
+		else
+			BL = 0;
+
+		if (optimizeMLTopology)
+			modelParameters = ModelConstants.freeParameters[modelNo] + BL + 1;
+		else
+			modelParameters = ModelConstants.freeParameters[modelNo] + BL;
+
+		ModelTest.getCandidateModels()[order] = new Model(order + 1,
+				ModelConstants.modelName[modelNo],
+				ModelConstants.modelCode[modelNo], modelParameters, pF, pT, pV,
+				pR, pI, pG, ModelConstants.numTransitions[modelNo],
+				ModelConstants.numTransversions[modelNo]);
+		
+		if (ModelTest.getLoadedModels() != null && ModelTest.getLoadedModels().length > 0) {
+			for (Model model : ModelTest.getLoadedModels()) {
+				if (model.getName().equals(ModelTest.getCandidateModels()[order].getName()) 
+						&& model.getLnL() > 0.0) {
+					/* load from checkpoint */
+					Model otherModel = ModelTest.getCandidateModels()[order];
+					otherModel.setLnL(model.getLnL());
+					otherModel.setLnLIgnoringGaps(model.getLnLIgnoringGaps());
+					otherModel.setShape(model.getShape());
+					otherModel.setfA(model.getfA());
+					otherModel.setfC(model.getfC());
+					otherModel.setfG(model.getfG());
+					otherModel.setfT(model.getfT());
+					otherModel.setRa(model.getRa());
+					otherModel.setRb(model.getRb());
+					otherModel.setRc(model.getRc());
+					otherModel.setRd(model.getRd());
+					otherModel.setRe(model.getRe());
+					otherModel.setRf(model.getRf());
+					otherModel.setPinv(model.getPinv());
+					otherModel.setKappa(model.getKappa());
+					otherModel.setTitv(model.getTitv());
+					try {
+						otherModel.setTreeString(model.getTreeString());
+					} catch (TreeParseException e) {
+						e.printStackTrace();
+					}
+					model.setLnL(0.0);
+					break;
+				}
+			}
+		}
+	}
+
+	public void loadModelConstraints(Model currentModel, int order,
+			String partition, boolean baseFrequencies, int rateVariation,
+			int ratesCount) {
+		int modelParameters, BL, nTi, nTv;
+		boolean pF, pT, pV, pR, pI, pG;
+
+		pT = pV = pR = pI = pG = false;
+
+		pF = baseFrequencies;
+
+		switch (rateVariation) {
+		case 1:
+			pI = true;
+			break;
+		case 2:
+			pG = true;
+			break;
+		case 3:
+			pI = true;
+			pG = true;
+			break;
+		}
+
+		if (countBLasParameters)
+			BL = getNumBranches();
+		else
+			BL = 0;
+
+		modelParameters = (ratesCount - 1) + (pF ? 3 : 0) + (pI ? 1 : 0)
+				+ (pG ? 1 : 0) + BL + (optimizeMLTopology ? 1 : 0);
+
+		String modelName;
+
+		if (ModelConstants.codeList.contains(partition)) {
+			int index = ModelConstants.codeList.indexOf(partition);
+			if (pF)
+				index += 4;
+			if (pI)
+				index += 1;
+			if (pG)
+				index += 2;
+			modelName = ModelConstants.modelName[index];
+			nTi = ModelConstants.numTransitions[index];
+			nTv = ModelConstants.numTransversions[index];
+			if (nTi == 1 && nTv == 1) {
+				pT = true;
+			} else if (nTi > 1 || nTv > 1) {
+				pR = true;
+			}
+		} else {
+			modelName = partition + (pI ? "+I" : "") + (pG ? "+G" : "")
+					+ (pF ? "+F" : "");
+			nTi = 0;// ModelConstants.getNumberOfTransitions(partition);
+			nTv = 0;// ModelConstants.getNumberOfTransversions(partition);
+			pT = false;
+			pR = true;
+		}
+		ModelTest.getCandidateModels()[order] = new Model(order + 1, modelName,
+				partition, modelParameters, pF, pT, pV, pR, pI, pG, 0, 0);
+		
+		if (ModelTest.getLoadedModels() != null && ModelTest.getLoadedModels().length > 0) {
+			for (Model model : ModelTest.getLoadedModels()) {
+				if (model.getName().equals(ModelTest.getCandidateModels()[order].getName()) 
+						&& model.getLnL() > 0.0) {
+					/* load from checkpoint */
+					Model otherModel = ModelTest.getCandidateModels()[order];
+					otherModel.setLnL(model.getLnL());
+					otherModel.setLnLIgnoringGaps(model.getLnLIgnoringGaps());
+					otherModel.setShape(model.getShape());
+					otherModel.setfA(model.getfA());
+					otherModel.setfC(model.getfC());
+					otherModel.setfG(model.getfG());
+					otherModel.setfT(model.getfT());
+					otherModel.setRa(model.getRa());
+					otherModel.setRb(model.getRb());
+					otherModel.setRc(model.getRc());
+					otherModel.setRd(model.getRd());
+					otherModel.setRe(model.getRe());
+					otherModel.setRf(model.getRf());
+					otherModel.setPinv(model.getPinv());
+					otherModel.setKappa(model.getKappa());
+					otherModel.setTitv(model.getTitv());
+					try {
+						otherModel.setTreeString(model.getTreeString());
+					} catch (TreeParseException e) {
+						e.printStackTrace();
+					}
+					model.setLnL(0.0);
+					break;
+				}
+			}
+		}
+	}
+
+	public File getInputFile() {
+		return inputDataFile;
+	}
+
+	public File getInputTreeFile() {
+		return inputTreeFile;
+	}
+
+	public void setInputFile(File file) {
+		this.inputDataFile = file;
+	}
+
+	public void setInputTreeFile(File file) {
+		this.inputTreeFile = file;
+	}
+
+	public File getAlignmentFile() {
+		if (alignmentFile == null) {
+			try {
+				alignmentFile = File.createTempFile("jmodeltest", ".phy");
+				alignmentFile.deleteOnExit();
+			} catch (IOException e) {
+				alignmentFile = inputDataFile;
+			}
+		}
+		return alignmentFile;
+	}
+
+	public Alignment getAlignment() {
+		return alignment;
+	}
+
+	public void setAlignment(Alignment alignment) {
+		this.alignment = alignment;
+		setNumTaxa(alignment.getSequenceCount());
+		setNumSites(alignment.getSiteCount());
+		setNumBranches(2 * numTaxa - 3);
+		setNumInvariableSites(Utilities.calculateInvariableSites(alignment));
+
+		DataType dt = alignment.getDataType();
+		// check ambiguity
+		isAmbiguous = false;
+		if (alignment.getDataType().isAmbiguous()) {
+			isAmbiguous = true;
+		} else {
+			for (int i = 0; i < numTaxa; i++) {
+				String seq = alignment.getAlignedSequenceString(i);
+				if (seq.indexOf(Alignment.GAP) >= 0) {
+					isAmbiguous = true;
+					break;
+				}
+				for (int j = 0; j < seq.length(); j++) {
+					if (dt.getState(seq.charAt(j)) == AMBIGUOUS_DATATYPE_STATE) {
+						isAmbiguous = true;
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	public boolean isForceCheckULnL() {
+		return forceCheckULnL;
+	}
+
+	public void setForceCheckULnL(boolean forceCheckULnL) {
+		this.forceCheckULnL = forceCheckULnL;
+	}
+
+	public double getUnconstrainedLnL() {
+		return unconstrainedLnL;
+	}
+
+	public void setUnconstrainedLnL(double unconstrainedLikelihood) {
+		this.unconstrainedLnL = unconstrainedLikelihood;
+	}
+
+	public int getNumPatterns() {
+		return numPatterns;
+	}
+
+	public void setNumPatterns(int numPatterns) {
+		this.numPatterns = numPatterns;
+	}
+
+	public boolean isAmbiguous() {
+		return isAmbiguous;
+	}
+
+	public String getExecutionName() {
+		return executionName;
+	}
+
+	public void setExecutionName(String executionName) {
+		this.executionName = executionName;
+	}
+
+	public File getTreeFile() {
+		if (treeFile == null) {
+			try {
+				treeFile = File.createTempFile("jmodeltest", ".tree");
+				treeFile.deleteOnExit();
+			} catch (IOException e) {
+				treeFile = inputTreeFile;
+			}
+
+		}
+		return treeFile;
+	}
+
+	public File getCkpFile() {
+		return ckpFile;
+	}
+	
+	public File getLogFile() {
+		return logFile;
+	}
+
+	public String getUserTree() {
+		return userTree;
+	}
+
+	public void setUserTree(String tree) {
+		this.userTree = tree;
+	}
+
+	/**
+	 * @param substTypeCode
+	 *            the substTypeCode to set
+	 */
+	public void setSubstTypeCode(int substTypeCode) {
+		this.substTypeCode = substTypeCode;
+		this.doClusteringSearch = (substTypeCode == 4);
+	}
+
+	/**
+	 * @return the substTypeCode
+	 */
+	public int getSubstTypeCode() {
+		return substTypeCode;
+	}
+
+	public double getSampleSize() {
+		return numSites;
+	}
+
+	public static void setInstance(ApplicationOptions newInstance) {
+		File alignmentFile = instance.alignmentFile;
+		File treeFile = instance.treeFile;
+		instance = newInstance;
+		instance.alignmentFile = alignmentFile;
+		instance.treeFile = treeFile;
+	}
+
+	public int getNumberOfThreads() {
+		return numberOfThreads;
+	}
+
+	public void setNumberOfThreads(int numberOfThreads) {
+		this.numberOfThreads = numberOfThreads;
+	}
+
+	public boolean isGuidedSearch() {
+		return guidedSearchThreshold > 1e-6;
+	}
+
+	public double getGuidedSearchThreshold() {
+		return guidedSearchThreshold;
+	}
+
+	public void setGuidedSearchThreshold(double guidedSearchThreshold) {
+		this.guidedSearchThreshold = guidedSearchThreshold;
+	}
+
+	public void setMachinesFile(File machinesFile) throws FileNotFoundException {
+		if (ModelTest.HOSTS_TABLE.containsKey(ModelTest.getHostname())) {
+
+			setNumberOfThreads(
+					ModelTest.HOSTS_TABLE.get(ModelTest.getHostname()));
+
+		} else {
+			System.err.println("");
+			System.err.println("WARNING: Machines File format is wrong.");
+			System.err.println("         This host: " + ModelTest.getHostname()
+					+ " does not exist");
+			System.err.println("         Using a single thread");
+			System.err.println("");
+			this.numberOfThreads = 1;
+		}
+	}
+
+	public File getMachinesFile() {
+		return machinesFile;
+	}
+
+	public boolean isClusteringSearch() {
+		return doClusteringSearch;
+	}
+
+	public void setClusteringSearch(boolean doClusteringSearch) {
+		this.doClusteringSearch = doClusteringSearch;
+	}
+
+	public int getHeuristicInformationCriterion() {
+		return heuristicInformationCriterion;
+	}
+
+	public void setHeuristicInformationCriterion(
+			int heuristicInformationCriterion) {
+		this.heuristicInformationCriterion = heuristicInformationCriterion;
+	}
+
+	public int getNumSites() {
+		return numSites;
+	}
+
+	public void setNumSites(int numSites) {
+		this.numSites = numSites;
+	}
+
+	public int getNumTaxa() {
+		return numTaxa;
+	}
+
+	public void setNumTaxa(int numTaxa) {
+		this.numTaxa = numTaxa;
+	}
+
+	public int getNumBranches() {
+		return numBranches;
+	}
+
+	public void setNumBranches(int numBranches) {
+		this.numBranches = numBranches;
+	}
+
+	public int getNumInvariableSites() {
+		return numInvariableSites;
+	}
+
+	public void setNumInvariableSites(int numInvariableSites) {
+		this.numInvariableSites = numInvariableSites;
+	}
+
+	public int getNumModels() {
+		return numModels;
+	}
+
+	public void setNumModels(int numModels) {
+		this.numModels = numModels;
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/InvalidArgumentException.java b/src/main/java/es/uvigo/darwin/jmodeltest/InvalidArgumentException.java
new file mode 100644
index 0000000..d2a0613
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/InvalidArgumentException.java
@@ -0,0 +1,108 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest;
+
+import java.io.File;
+
+public class InvalidArgumentException extends RuntimeException {
+
+	private static final long serialVersionUID = 201104031313L;
+
+	public InvalidArgumentException(String message) {
+		super(message);
+	}
+
+	public static class UnexistentCriterionException extends
+			InvalidArgumentException {
+
+		private static final long serialVersionUID = 201104031313L;
+
+		public UnexistentCriterionException(int criterion) {
+			super("Attempting to create an unexistent criterion type: "
+					+ criterion);
+		}
+
+	}
+
+	public static class InvalidInputFileException extends
+			InvalidArgumentException {
+
+		private static final long serialVersionUID = 201104031313L;
+
+		public InvalidInputFileException(String message) {
+			super("Invalid input file: " + message);
+		}
+
+	}
+
+	public static class InvalidAlignmentFileException extends
+			InvalidInputFileException {
+
+		private static final long serialVersionUID = 201104031313L;
+
+		public InvalidAlignmentFileException(String fileName) {
+			super("Alignment: " + fileName);
+		}
+		
+		public InvalidAlignmentFileException(File file) {
+			super("Alignment: " + file.getAbsolutePath());
+		}
+
+	}
+
+	public static class UnexistentAlignmentFileException extends
+			InvalidAlignmentFileException {
+
+		private static final long serialVersionUID = 201104031313L;
+
+		public UnexistentAlignmentFileException(File file) {
+			super("File does not exist: " + file.getAbsolutePath());
+		}
+
+	}
+
+	public static class InvalidTreeFileException extends
+			InvalidInputFileException {
+
+		private static final long serialVersionUID = 201104031313L;
+
+		public InvalidTreeFileException(String message) {
+			super("Input tree: " + message);
+		}
+		
+		public InvalidTreeFileException(File file) {
+			super("Input tree: " + file.getAbsolutePath());
+		}
+
+	}
+
+	public static class UnexistentTreeFileException extends
+			InvalidTreeFileException {
+
+		private static final long serialVersionUID = 201104031313L;
+
+		public UnexistentTreeFileException(File file) {
+			super("File does not exist: " + file.getAbsolutePath());
+		}
+		
+		public UnexistentTreeFileException(String file) {
+			super("File does not exist: " + file);
+		}
+
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/ModelTest.java b/src/main/java/es/uvigo/darwin/jmodeltest/ModelTest.java
new file mode 100644
index 0000000..20d4c2d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/ModelTest.java
@@ -0,0 +1,1841 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest;
+
+import java.awt.GraphicsEnvironment;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.PushbackReader;
+import java.io.StringReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Properties;
+import java.util.Vector;
+
+import mpi.MPI;
+import mpi.MPIException;
+import pal.tree.Tree;
+import pal.tree.TreeParseException;
+import es.uvigo.darwin.jmodeltest.exe.RunConsense;
+import es.uvigo.darwin.jmodeltest.exe.RunPhyml;
+import es.uvigo.darwin.jmodeltest.exe.RunPhymlHybrid;
+import es.uvigo.darwin.jmodeltest.exe.RunPhymlMPJ;
+import es.uvigo.darwin.jmodeltest.exe.RunPhymlThread;
+import es.uvigo.darwin.jmodeltest.gui.XManager;
+import es.uvigo.darwin.jmodeltest.io.AlignmentReader;
+import es.uvigo.darwin.jmodeltest.io.HtmlReporter;
+import es.uvigo.darwin.jmodeltest.io.TextInputStream;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.observer.ConsoleProgressObserver;
+import es.uvigo.darwin.jmodeltest.selection.AIC;
+import es.uvigo.darwin.jmodeltest.selection.AICc;
+import es.uvigo.darwin.jmodeltest.selection.BIC;
+import es.uvigo.darwin.jmodeltest.selection.DT;
+import es.uvigo.darwin.jmodeltest.selection.HLRT;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+import es.uvigo.darwin.jmodeltest.tree.TreeSummary;
+import es.uvigo.darwin.jmodeltest.tree.TreeUtilities;
+import es.uvigo.darwin.jmodeltest.utilities.Simulation;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+/**
+ * ModelTest.java
+ * 
+ * Description: Main class for selecting models of nucleotide substitition
+ * 
+ * @author Diego Darriba, University of Vigo / University of A Coruna, Spain
+ *         ddarriba at udc.es
+ * @author David Posada, University of Vigo, Spain dposada at uvigo.es |
+ *         darwin.uvigo.es
+ * @version 2.1 (May 2012)
+ */
+public class ModelTest {
+
+	private ApplicationOptions options = ApplicationOptions.getInstance();
+
+	/** The MPJ rank of the process. It is only useful if MPJ is running. */
+	public static int MPJ_ME;
+	/** The MPJ size of the communicator. It is only useful if MPJ is running. */
+	public static int MPJ_SIZE;
+	/** The MPJ running state. */
+	public static boolean MPJ_RUN;
+
+	public static final Properties USERDEF_PROPERTIES;
+	
+	// application constant definitions
+	public static final int PRECISION = 4;
+	public static final double INFINITY = 9999;
+	public static final int MAX_NUM_MODELS = 88;
+	public static final int MAX_NAME = 60;
+	public static final String CURRENT_VERSION = "2.1.8 v20151020";
+	public static final String programName = ("jModeltest");
+	public static final String URL = "http://code.google.com/p/jmodeltest2";
+	public static final String WIKI = "http://code.google.com/p/jmodeltest2/wiki/GettingStarted";
+	public static final String DISCUSSION_GROUP = "http://groups.google.com/group/jmodeltest";
+	public static String CONFIG_FILE = "conf/jmodeltest.conf";
+	public static final String UNKNOWN_HOSTNAME = "UNKNOWN";
+
+	private static TextOutputStream MAIN_CONSOLE;
+	private static TextOutputStream PHYML_CONSOLE = null;
+	private static TextOutputStream CURRENT_OUT_STREAM;
+
+	public static String[] arguments;
+
+	private static boolean AICwasCalculated = false;
+	private static boolean AICcwasCalculated = false;
+	private static boolean BICwasCalculated = false;
+	private static boolean DTwasCalculated = false;
+
+	public static Vector<String> testingOrder; // order of the hLRTs
+	public static String averagedTreeString; // model-averaged phylogeny in
+												// Newick format
+	public static enum ExecMode {
+		CONSOLE, GUI
+	};
+	public static ExecMode execMode;
+	
+	private static AIC myAIC;
+	private static AICc myAICc;
+	private static BIC myBIC;
+	private static DT myDT;
+	private static HLRT myHLRT;
+
+	private static RunConsense consensusAIC;
+	private static RunConsense consensusAICc;
+	private static RunConsense consensusBIC;
+	private static RunConsense consensusDT;
+
+	private static Model[] candidateModels;
+	private static Model[] loadedModels;
+	private static Model minAIC, minAICc, minBIC, minDT, minHLRT, minDLRT;
+
+	private static String hostname;
+	public static Hashtable<String, Integer> HOSTS_TABLE;
+
+	// We can work under a GUI or in the command line
+	public static boolean buildGUI = true;
+
+	static {
+		USERDEF_PROPERTIES = new Properties();
+		InetAddress addr;
+		try {
+			addr = InetAddress.getLocalHost();
+			// Get hostname
+			hostname = addr.getHostName();
+		} catch (UnknownHostException e) {
+			hostname = UNKNOWN_HOSTNAME;
+			System.err.println("WARNING: This host is unknown");
+			// WARN AND DO NOTHING
+		}
+	}
+
+	// constructor with GUI
+	public ModelTest() {
+		if (!GraphicsEnvironment.isHeadless()) {
+			options.createLogFile();
+			execMode = ExecMode.GUI;
+			XManager.getInstance();
+			// Check binary
+	    	if (!ModelTestConfiguration.isGlobalPhymlBinary()) {
+				if (!RunPhyml.phymlBinary.exists()) {
+					Utilities
+					.printRed("ERROR: PhyML binary cannot be found: " + RunPhyml.phymlBinary.getAbsolutePath() + "\n");
+				} else if (!RunPhyml.phymlBinary.canExecute()) {
+					Utilities
+					.printRed("ERROR: PhyML binary exists, but it cannot be executed: " + RunPhyml.phymlBinary.getAbsolutePath() + "\n");
+				}
+			}
+		} else {
+			System.err.println("");
+			System.err.println("ERROR: You are trying to run a GUI interface in a headless server.");
+			finalize(-1);
+		}
+	}
+
+	// constructor without GUI
+	public ModelTest(String[] arg) {
+		try {
+			// open mainConsole
+			MAIN_CONSOLE = new TextOutputStream(System.out);
+			execMode = ExecMode.CONSOLE;
+			ParseArguments();
+			
+			// Check binary
+        	if (!ModelTestConfiguration.isGlobalPhymlBinary()) {
+				if (!RunPhyml.phymlBinary.exists()) {
+					System.err.println(" ");
+					System.err.println("ERROR: PhyML binary cannot be found: " + RunPhyml.phymlBinary.getAbsolutePath());
+					finalize(-1);
+				} else if (!RunPhyml.phymlBinary.canExecute()) {
+					System.err.println(" ");
+					System.err.println("ERROR: PhyML binary exists, but it cannot be executed: " + RunPhyml.phymlBinary.getAbsolutePath());
+					finalize(-1);
+				}
+			}
+        	
+			options.createLogFile();
+			options.createCkpFile();
+			if (options.doingSimulations) {
+				Simulation sim = new Simulation(options);
+				sim.run();
+			} else
+				runCommandLine();
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		finalize(0);
+	}
+
+	/****************************
+	 * main ************************************ * Starts the application * * *
+	 ***********************************************************************/
+
+	public static boolean loadCheckpoint (File ckpFile) {
+		try {
+			InputStream file = new FileInputStream(ckpFile);
+			InputStream buffer = new BufferedInputStream(file);
+			ObjectInput input = new ObjectInputStream(buffer);
+			loadedModels = (Model[]) input.readObject();
+			int numModels = 0;
+			for (Model model : loadedModels) {
+				if (model.getLnL() > 0.0) numModels++;
+			}
+			MAIN_CONSOLE.println(" ok!");
+			MAIN_CONSOLE.println("Loaded "+ numModels +" models");
+			ApplicationOptions.getInstance().setNumModels(loadedModels.length);
+			input.close();
+		} catch (ClassNotFoundException ex) {
+			MAIN_CONSOLE.println(" cannot perform input.");
+			return false;
+		} catch (IOException ex) {
+			MAIN_CONSOLE.println(" cannot perform input.");
+			return false;
+		}
+		return true;
+	}
+	
+	public static void main(String[] args) {
+		// initializing MPJ environment (if available)
+		System.err.println("[MPI] Testing MPI environment... (" + hostname
+				+ ")");
+		try {
+			arguments = MPI.Init(args);
+			System.err.println("[MPI] ... OK! [" + hostname + " (" + MPJ_ME
+					+ ")]");
+			MPJ_ME = MPI.COMM_WORLD.Rank();
+			MPJ_SIZE = MPI.COMM_WORLD.Size();
+			MPJ_RUN = true;
+		} catch (MPIException e) {
+			System.err.println("[MPI] Proceed without MPI");
+			MPJ_ME = 0;
+			MPJ_SIZE = 1;
+			MPJ_RUN = false;
+			arguments = args;
+		} catch (Exception e) {
+			System.err.println("[MPI] Proceed without MPI");
+			MPJ_ME = 0;
+			MPJ_SIZE = 1;
+			MPJ_RUN = false;
+			arguments = args;
+		} catch (ExceptionInInitializerError e) {
+			System.err.println("[MPI] Initializer error!");
+			System.err.println(e.getMessage());
+			System.exit(-1);
+			MPJ_ME = 0;
+			MPJ_SIZE = 1;
+			MPJ_RUN = false;
+			arguments = args;
+		} catch (NoClassDefFoundError e) {
+			System.err.println("[MPI] Proceed without MPI");
+			MPJ_ME = 0;
+			MPJ_SIZE = 1;
+			MPJ_RUN = false;
+			arguments = args;
+		}
+
+		if (arguments.length < 1) {
+			buildGUI = true;
+			new ModelTest();
+		} else {
+			buildGUI = false;
+			new ModelTest(arguments);
+		}
+
+		ApplicationOptions.getInstance().getLogFile().delete();
+	}
+
+	/****************************
+	 * runCommandLine ************************** * Organizes all the tasks that
+	 * the program needs to carry out * * *
+	 ***********************************************************************/
+	public void runCommandLine() {
+
+		if (MPJ_ME == 0) {
+			// print header information
+			printHeader(MAIN_CONSOLE);
+
+			// print citation information
+			printCitation(MAIN_CONSOLE);
+
+			// print notice information
+			printNotice(MAIN_CONSOLE);
+
+			// print the command line
+			MAIN_CONSOLE.println(" ");
+			MAIN_CONSOLE.print("Arguments =");
+			for (int i = 0; i < arguments.length; i++)
+				MAIN_CONSOLE.print(" " + arguments[i]);
+
+			try {
+				checkInputFiles();
+			} catch (InvalidArgumentException.InvalidInputFileException e) {
+				MAIN_CONSOLE.println(e.getMessage());
+				finalize(-1);
+			}
+
+			// calculate number of models
+			if (options.getSubstTypeCode() == 0)
+				options.setNumModels(3);
+			else if (options.getSubstTypeCode() == 1)
+				options.setNumModels(5);
+			else if (options.getSubstTypeCode() == 2)
+				options.setNumModels(7);
+			else if (options.getSubstTypeCode() == 3)
+				options.setNumModels(11);
+			else
+				options.setNumModels(203);
+
+			if (options.doF)
+				options.setNumModels(options.getNumModels() * 2);
+
+			if (options.doI && options.doG)
+				options.setNumModels(options.getNumModels() * 4);
+			else if (options.doI || options.doG)
+				options.setNumModels(options.getNumModels() * 2);
+			options.setCandidateModels();
+		}
+		// build set of models
+
+		// calculate likelihoods with phyml in the command line
+		RunPhyml runPhyml;
+		if (MPJ_RUN) {
+			if (options.threadScheduling && options.getNumberOfThreads() > 0) {
+				runPhyml = new RunPhymlHybrid(MPJ_ME, MPJ_SIZE,
+						new ConsoleProgressObserver(options), options,
+						getCandidateModels(), options.getNumberOfThreads());
+			} else {
+				runPhyml = new RunPhymlMPJ(
+						new ConsoleProgressObserver(options), options,
+						getCandidateModels());
+			}
+		} else {
+			runPhyml = new RunPhymlThread(new ConsoleProgressObserver(options),
+					options, getCandidateModels());
+		}
+		runPhyml.execute();
+
+		if (MPJ_ME == 0) {
+
+			List<Model> bestModels = new ArrayList<Model>();
+			// do AIC if selected
+			if (options.doAIC) {
+				myAIC = new AIC(options.writePAUPblock, options.doImportances,
+						options.doModelAveraging, options.confidenceInterval);
+				myAIC.compute();
+				minAIC = myAIC.getMinModel();
+				AICwasCalculated = true;
+				bestModels.add(minAIC);
+			}
+
+			// do AICc if selected
+			if (options.doAICc) {
+				myAICc = new AICc(options.writePAUPblock,
+						options.doImportances, options.doModelAveraging,
+						options.confidenceInterval);
+				myAICc.compute();
+				minAICc = myAICc.getMinModel();
+				AICcwasCalculated = true;
+				if (!bestModels.contains(minAICc)) {
+					bestModels.add(minAICc);
+				}
+			}
+
+			// do BIC if selected
+			if (options.doBIC) {
+				myBIC = new BIC(options.writePAUPblock, options.doImportances,
+						options.doModelAveraging, options.confidenceInterval);
+				myBIC.compute();
+				minBIC = myBIC.getMinModel();
+				BICwasCalculated = true;
+				if (!bestModels.contains(minBIC)) {
+					bestModels.add(minBIC);
+				}
+			}
+
+			// do DT if selected
+			if (options.doDT) {
+				myDT = new DT(options.writePAUPblock, options.doImportances,
+						options.doModelAveraging, options.confidenceInterval);
+				myDT.compute();
+				minDT = myDT.getMinModel();
+				DTwasCalculated = true;
+			}
+
+			if (options.isAmbiguous() && options.isForceCheckULnL()) {
+				runPhyml.executeIgnoreGaps(bestModels.toArray(new Model[0]));
+			}
+
+			if (options.doAIC) {
+				myAIC.print(MAIN_CONSOLE);
+				if (options.doAveragedPhylogeny) {
+					consensusAIC = new RunConsense(myAIC,
+							options.consensusType, options.confidenceInterval);
+				}
+			}
+			if (options.doAICc) {
+				myAICc.print(MAIN_CONSOLE);
+				if (options.doAveragedPhylogeny) {
+					consensusAICc = new RunConsense(myAICc,
+							options.consensusType, options.confidenceInterval);
+				}
+			}
+			if (options.doBIC) {
+				myBIC.print(MAIN_CONSOLE);
+				if (options.doAveragedPhylogeny) {
+					consensusBIC = new RunConsense(myBIC,
+							options.consensusType, options.confidenceInterval);
+				}
+			}
+			if (options.doDT) {
+				myDT.print(MAIN_CONSOLE);
+				if (options.doAveragedPhylogeny) {
+					consensusDT = new RunConsense(myDT, options.consensusType,
+							options.confidenceInterval);
+				}
+			}
+			// do hLRT if selected
+			if (options.doHLRT) {
+				myHLRT = new HLRT(options);
+				myHLRT.compute(!options.backwardHLRTSelection,
+						options.confidenceLevelHLRT, options.writePAUPblock);
+			}
+
+			// do dLRT if selected
+			if (options.doDLRT) {
+				myHLRT = new HLRT(options);
+				myHLRT.computeDynamical(!options.backwardHLRTSelection,
+						options.confidenceLevelHLRT, options.writePAUPblock);
+			}
+
+			Tree bestAIC = myAIC != null ? myAIC.getMinModel().getTree() : null;
+			Tree bestAICc = myAICc != null ? myAICc.getMinModel().getTree()
+					: null;
+			Tree bestBIC = myBIC != null ? myBIC.getMinModel().getTree() : null;
+			Tree bestDT = myDT != null ? myDT.getMinModel().getTree() : null;
+
+			MAIN_CONSOLE.println(" ");
+			MAIN_CONSOLE.println(" ");
+			MAIN_CONSOLE.println(" ");
+			MAIN_CONSOLE
+					.println("---------------------------------------------------------------");
+			MAIN_CONSOLE
+					.println("*                                                             *");
+			MAIN_CONSOLE
+					.println("*                    SELECTION SUMMARY                        *");
+			MAIN_CONSOLE
+					.println("*                                                             *");
+			MAIN_CONSOLE
+					.println("---------------------------------------------------------------");
+			MAIN_CONSOLE.println("");
+
+			TreeSummary treeSummary = new TreeSummary(bestAIC, bestAICc,
+					bestBIC, bestDT, candidateModels);
+
+			treeSummary.print(MAIN_CONSOLE);
+
+			MAIN_CONSOLE.println(" ");
+			MAIN_CONSOLE.println(" ");
+			MAIN_CONSOLE.println(" ");
+			MAIN_CONSOLE.println("::Best Models::");
+			MAIN_CONSOLE.println(" ");
+			if (myAIC == null && myAICc == null && myBIC == null
+					&& myDT == null) {
+				MAIN_CONSOLE.println("No information criterion was selected.");
+			}
+			MAIN_CONSOLE
+					.println("\tModel \t\tf(a) \tf(c) \tf(g) \tf(t) \tkappa \ttitv "
+							+ "\tRa\tRb\tRc\tRd\tRe\tRf\tpInv \tgamma");
+			MAIN_CONSOLE
+					.println("----------------------------------------------------------------------------------------------------------------------------------------");
+
+			boolean icValid = true;
+			if (myAIC != null) {
+				Model minModel = myAIC.getMinModel();
+				MAIN_CONSOLE.println("AIC \t" + getModelRow(minModel));
+				icValid &= myAIC.isValid();
+				// MAIN_CONSOLE.println("average \t" +
+				// getModelAverageRow(myAIC));
+			}
+			if (myBIC != null) {
+				Model minModel = myBIC.getMinModel();
+				MAIN_CONSOLE.println("BIC \t" + getModelRow(minModel));
+				icValid &= myBIC.isValid();
+				// MAIN_CONSOLE.println("average \t" +
+				// getModelAverageRow(myBIC));
+			}
+			if (myAICc != null) {
+				Model minModel = myAICc.getMinModel();
+				MAIN_CONSOLE.println("AICc \t" + getModelRow(minModel));
+				icValid &= myAICc.isValid();
+				// MAIN_CONSOLE.println("average \t" +
+				// getModelAverageRow(myAICc));
+			}
+			if (myDT != null) {
+				Model minModel = myDT.getMinModel();
+				MAIN_CONSOLE.println("DT \t" + getModelRow(minModel));
+				icValid &= myDT.isValid();
+				// MAIN_CONSOLE.println("average \t" +
+				// getModelAverageRow(myDT));
+
+				MAIN_CONSOLE.println(" ");
+				MAIN_CONSOLE.println("Program is done.");
+
+			}
+			if (!icValid) {
+				MAIN_CONSOLE.println("* There might not be information enough to achieve reliable results. Please inspect the results carefully.");
+			}
+			
+			if (ModelTestConfiguration.isHtmlLogEnabled()) {
+				HtmlReporter.buildReport(options,
+						ModelTest.getCandidateModels(), null, treeSummary);
+			}
+		} // end root
+
+	} // end of runCommandLine
+
+	private String getModelRow(Model model) {
+		StringBuilder sb = new StringBuilder();
+		sb.append(model.getName() + "\t");
+		if (model.getName().length() < 8)
+			sb.append("\t");
+		sb.append(Utilities.format(model.getfA(), 4, 2, false) + "\t"
+				+ Utilities.format(model.getfC(), 4, 2, false) + "\t"
+				+ Utilities.format(model.getfG(), 4, 2, false) + "\t"
+				+ Utilities.format(model.getfT(), 4, 2, false) + "\t"
+				+ Utilities.format(model.getKappa(), 4, 2, false) + "\t"
+				+ Utilities.format(model.getTitv(), 4, 2, false) + "\t"
+				+ Utilities.format(model.getRa(), 7, 3, false) + " "
+				+ Utilities.format(model.getRb(), 7, 3, false) + " "
+				+ Utilities.format(model.getRc(), 7, 3, false) + " "
+				+ Utilities.format(model.getRd(), 7, 3, false) + " "
+				+ Utilities.format(model.getRe(), 7, 3, false) + " "
+				+ Utilities.format(model.getRf(), 7, 3, false) + " ");
+		if (model.ispI()) {
+			sb.append(Utilities.format(model.getPinv(), 7, 2, false));
+		} else {
+			sb.append("N/A");
+		}
+		sb.append("\t");
+		if (model.ispG()) {
+			sb.append(Utilities.format(model.getShape(), 7, 2, false));
+		} else {
+			sb.append("N/A");
+		}
+		return sb.toString();
+	}
+
+	@SuppressWarnings("unused")
+	private String getModelAverageRow(InformationCriterion ic) {
+		StringBuilder sb = new StringBuilder();
+		sb.append(Utilities.format(ic.getAfA(), 4, 2, false) + "\t");
+		sb.append(Utilities.format(ic.getAfC(), 4, 2, false) + "\t");
+		sb.append(Utilities.format(ic.getAfG(), 4, 2, false) + "\t");
+		sb.append(Utilities.format(ic.getAfT(), 4, 2, false) + "\t");
+		sb.append(Utilities.format(ic.getAkappa(), 4, 2, false) + "\t");
+		sb.append(Utilities.format(ic.getAtitv(), 4, 2, false) + "\t");
+		sb.append(Utilities.format(ic.getaRa(), 7, 3, false) + "\t");
+		sb.append(Utilities.format(ic.getaRb(), 7, 3, false) + "\t");
+		sb.append(Utilities.format(ic.getaRc(), 7, 3, false) + "\t");
+		sb.append(Utilities.format(ic.getaRd(), 7, 3, false) + "\t");
+		sb.append(Utilities.format(ic.getaRe(), 7, 3, false) + "\t");
+		sb.append(Utilities.format(ic.getaRf(), 7, 3, false) + "\t");
+		sb.append(Utilities.format(ic.getApinvI(), 7, 4, false) + "\t");
+		sb.append(Utilities.format(ic.getApinvIG(), 7, 4, false) + "\t");
+		sb.append(Utilities.format(ic.getAshapeG(), 7, 3, false) + "\t");
+		sb.append(Utilities.format(ic.getAshapeIG(), 7, 3, false) + "\t");
+		return sb.toString();
+	}
+
+	/****************************
+	 * ParseArguments **************************** * Parses the command line for
+	 * jModeltest * *
+	 ************************************************************************/
+
+	public void ParseArguments() {
+		int i, j;
+		String arg = "";
+		String error = "\nCOMMAND LINE ERROR: ";
+		File ckpFile = null;
+		boolean isInputFile = false;
+		boolean isIcForHcSet = false;
+		boolean getPhylip = false;
+		try {
+			i = 0;
+			while (i < arguments.length) {
+				if (!arguments[i].startsWith("-")) {
+					System.err
+							.println(error
+									+ "Arguments must start with \"-\". The ofending argument was: "
+									+ arguments[i] + ".");
+					System.err.print("      Arguments: ");
+					for (String argument : arguments) {
+						System.err.print(argument + " ");
+					}
+					System.err.println("");
+
+					CommandLineError();
+					System.exit(1);
+				}
+
+				arg = arguments[i++];
+
+				if (arg.equals("-d")) {
+					if (i < arguments.length) {
+						options.setInputFile(new File(arguments[i++]));
+						isInputFile = true;
+					} else {
+						System.err.println(error
+								+ "-d option requires an input filename.");
+						CommandLineError();
+					}
+				}
+
+				else if (arg.equals("-o")) {
+					String outFile = arguments[i++];
+					try {
+						MAIN_CONSOLE = new TextOutputStream(new PrintStream(
+								outFile));
+					} catch (FileNotFoundException e1) {
+						System.err
+								.println("An error has ocurred while trying to open the output file \""
+										+ outFile + "\" for writing");
+						e1.printStackTrace();
+						System.exit(-1);
+					}
+				} else if (arg.equals("-s")) {
+					if (i < arguments.length) {
+						String type = arguments[i++];
+						try {
+							int number = Integer.parseInt(type);
+							switch (number) {
+							case 3:
+								options.setSubstTypeCode(0);
+								break;
+							case 5:
+								options.setSubstTypeCode(1);
+								break;
+							case 7:
+								options.setSubstTypeCode(2);
+								break;
+							case 11:
+								options.setSubstTypeCode(3);
+								break;
+							case 203:
+								options.setSubstTypeCode(4);
+								break;
+							default:
+								System.err
+										.println(error
+												+ "-s substitution types have to be 3,5,7,11 only.");
+								CommandLineError();
+							}
+						} catch (NumberFormatException e) {
+							System.err
+									.println(error
+											+ "-s option requires a number for the substitution types: 3,5,7,11.");
+							CommandLineError();
+						}
+					} else {
+						System.err
+								.println(error
+										+ "-s option requires a number for the substitution types: 3,5,7,11.");
+						CommandLineError();
+					}
+				}
+
+				else if (arg.equals("-ckp")) {
+					if (i < arguments.length) {
+						ckpFile = new File(arguments[i++]);
+					} else {
+						System.err.println(error
+								+ "-ckp option requires a checkpoint filename.");
+						CommandLineError();
+					}
+				}
+				else if (arg.equals("-f")) {
+					options.doF = true;
+				}
+
+				else if (arg.equals("-i")) {
+					options.doI = true;
+				}
+
+				else if (arg.equals("-g")) {
+					if (i < arguments.length) {
+						try {
+							options.doG = true;
+							String type = arguments[i++];
+							options.numGammaCat = Integer.parseInt(type);
+						} catch (NumberFormatException e) {
+							System.err
+									.println(error
+											+ "-g option requires a number of gamma categories.");
+							CommandLineError();
+						}
+					} else {
+						System.err
+								.println(error
+										+ "-g option requires a number of gamma categories.");
+						CommandLineError();
+					}
+				}
+
+				else if (arg.equals("-G")) {
+					if (i < arguments.length) {
+						try {
+							Double threshold = Double
+									.parseDouble(arguments[i++]);
+							options.setGuidedSearchThreshold(threshold);
+						} catch (NumberFormatException e) {
+							System.err.println(error
+									+ "-G option requires a threshold.");
+							CommandLineError();
+						}
+					} else {
+						System.err.println(error
+								+ "-G option requires a threshold.");
+						CommandLineError();
+					}
+				}
+
+				else if (arg.equals("-H")) {
+					if (i < arguments.length) {
+						String criterion = arguments[i++];
+						if (criterion.equals("AIC")) {
+							options.setHeuristicInformationCriterion(InformationCriterion.IC_AIC);
+						} else if (criterion.equals("BIC")) {
+							options.setHeuristicInformationCriterion(InformationCriterion.IC_BIC);
+						} else if (criterion.equals("AICc")) {
+							options.setHeuristicInformationCriterion(InformationCriterion.IC_AICc);
+						} else {
+							System.err
+									.println(error
+											+ "-H argument is invalid (AIC, BIC, AICc).");
+							CommandLineError();
+						}
+						isIcForHcSet = true;
+					} else {
+						System.err
+								.println(error
+										+ "-H option requires an argument (AIC, BIC, AICc).");
+						CommandLineError();
+					}
+				} else if (arg.equals("-t")) {
+					if (i < arguments.length) {
+						String type = arguments[i++];
+
+						if (type.equalsIgnoreCase("fixed")) {
+							options.fixedTopology = true;
+							options.optimizeMLTopology = false;
+							options.userTopologyExists = false;
+						} else if (type.equalsIgnoreCase("BIONJ")) {
+							options.fixedTopology = false;
+							options.optimizeMLTopology = false;
+							options.userTopologyExists = false;
+						} else if (type.equalsIgnoreCase("ML")) {
+							options.fixedTopology = false;
+							options.optimizeMLTopology = true;
+							options.userTopologyExists = false;
+						} else {
+							System.err
+									.println(error
+											+ "-t option requires a type of base tree for likelihod calculations: "
+											+ "\"fixed\", \"BIONJ\" or \"ML\" only");
+							CommandLineError();
+						}
+					} else {
+						System.err
+								.println(error
+										+ "-t option requires a type of base tree for likelihod calculations: "
+										+ "fixed, BIONJ or ML");
+						CommandLineError();
+					}
+				} else if (arg.equals("-getPhylip")) {
+					getPhylip = true;
+				}
+
+				else if (arg.equals("-u")) {
+					if (i < arguments.length) {
+						options.setInputTreeFile(new File(arguments[i++]));
+						options.fixedTopology = false;
+						options.optimizeMLTopology = false;
+						options.userTopologyExists = true;
+					} else {
+						System.err
+								.println(error
+										+ "-u option requires an file name for the tree file");
+						CommandLineError();
+					}
+				}
+
+				else if (arg.equals("-n")) {
+					if (i < arguments.length) {
+						options.setExecutionName(arguments[i++]);
+					} else {
+						System.err
+								.println(error
+										+ "-n option requires a name for the execution");
+						CommandLineError();
+					}
+				}
+				
+				else if (arg.equals("-S")) {
+					if (i < arguments.length) {
+						String type = arguments[i++];
+
+						if (type.equalsIgnoreCase("NNI")) {
+							options.treeSearchOperations = ApplicationOptions.TreeSearch.NNI;
+						} else if (type.equalsIgnoreCase("SPR")) {
+							options.treeSearchOperations = ApplicationOptions.TreeSearch.SPR;
+						} else if (type.equalsIgnoreCase("BEST")) {
+							options.treeSearchOperations = ApplicationOptions.TreeSearch.BEST;
+						} else {
+							System.err
+									.println(error
+											+ "-S option requires a type of tree topology search operation: "
+											+ "\"NNI\", \"SPR\" or \"BEST\" only");
+							CommandLineError();
+						}
+					} else {
+						System.err
+								.println(error
+										+ "-S option requires a type of tree topology search operation: "
+										+ "\"NNI\", \"SPR\", \"BEST\"");
+						CommandLineError();
+					}
+				}
+
+				else if (arg.equals("-AIC")) {
+					options.doAIC = true;
+				}
+
+				else if (arg.equals("-AICc")) {
+					options.doAICc = true;
+				}
+
+				else if (arg.equals("-BIC")) {
+					options.doBIC = true;
+				}
+
+				else if (arg.equals("-DT")) {
+					options.doDT = true;
+				}
+
+				else if (arg.equals("-uLnL")) {
+					options.setForceCheckULnL(true);
+				}
+
+				else if (arg.equals("-p")) {
+					options.doImportances = true;
+				}
+
+				else if (arg.equals("-v")) {
+					options.doImportances = true;
+					options.doModelAveraging = true;
+				}
+
+				else if (arg.equals("-w")) {
+					options.writePAUPblock = true;
+				}
+
+				else if (arg.equals("-c")) {
+					if (i < arguments.length) {
+						try {
+							String type = arguments[i++];
+							options.confidenceInterval = Double
+									.parseDouble(type);
+						} catch (NumberFormatException e) {
+							System.err
+									.println(error
+											+ "-c option requires a number (0-1) for the model selection confidence interval.");
+							CommandLineError();
+						}
+					} else {
+						System.err
+								.println(error
+										+ "-c option requires a number (0-1) for the model selection confidence interval.");
+						CommandLineError();
+					}
+				}
+
+				else if (arg.equals("-help")) {
+					PrintUsage();
+				}
+
+				else if (arg.equals("-hLRT")) {
+					options.doHLRT = true;
+				}
+
+				else if (arg.equals("-O")) {
+					if (i < arguments.length) {
+						String type = arguments[i++];
+						char[] array = type.toCharArray();
+						Arrays.sort(array);
+
+						String validString = "";
+
+						if (type.length() == 5) {
+							validString = "fgptv";
+						} else if (type.length() == 6) {
+							validString = "fgptvw";
+						} else if (type.length() == 7) {
+							validString = "fgptvwx";
+						} else {
+							System.err
+									.println(error
+											+ "-O option requires a 5, 6 or 7 specific letter string with the order of tests (default is ftvwxgp)"
+											+ "\n            f=freq, t=titvi, v=2ti4tv(subst=3)/2ti(subst>3), w=2tv, x=4tv, g=gamma, p=pinv"
+											+ "\n            this argument is used only if -hLRT argument is set"
+											+ "\n            'f','t','v','g','p' are mandatory in any order. 'w' is optional, and 'x' requires 'w' to be present"
+											+ "\n            thus, length should be 5, 6 *including 'w') or 7 (including both 'w' and 'x')"
+											+ "\n            e.g., -hLRT -O gpfvwxt"
+											);
+							CommandLineError();
+						}
+
+						char[] valid = validString.toCharArray();
+						if (!Arrays.equals(array, valid)) {
+							System.err
+							.println(String.valueOf(array) + " " + String.valueOf(valid));
+							System.err
+							.println(error
+									+ "-O option requires a 5, 6 or 7 specific letter string with the order of tests (default is ftvwxgp)"
+									+ "\n            f=freq, t=titvi, v=2ti4tv(subst=3)/2ti(subst>3), w=2tv, x=4tv, g=gamma, p=pinv"
+									+ "\n            this argument is used only if -hLRT argument is set"
+									+ "\n            'f','t','v','g','p' are mandatory in any order. 'w' is optional, and 'x' requires 'w' to be present"
+									+ "\n            thus, length should be 5, 6 *including 'w') or 7 (including both 'w' and 'x')"
+									+ "\n            e.g., -hLRT -O gpfvwxt"
+									);
+							CommandLineError();
+						} else {
+							testingOrder = new Vector<String>();
+							for (j = 0; j < type.length(); j++) {
+								if (type.charAt(j) == 'f')
+									testingOrder.addElement("freq");
+								else if (type.charAt(j) == 't')
+									testingOrder.addElement("titv");
+								else if (type.charAt(j) == 'v') {
+									if (options.getSubstTypeCode() == 0)
+										testingOrder.addElement("2ti4tv");
+									else if (options.getSubstTypeCode() >= 1)
+										testingOrder.addElement("2ti");
+								} else if (type.charAt(j) == 'w') {
+									if (options.getSubstTypeCode() >= 1)
+										testingOrder.addElement("2tv");
+								} else if (type.charAt(j) == 'x') {
+									if (options.getSubstTypeCode() > 1)
+										testingOrder.addElement("4tv");
+								} else if (type.charAt(j) == 'g')
+									testingOrder.addElement("gamma");
+								else if (type.charAt(j) == 'p')
+									testingOrder.addElement("pinv");
+							}
+						}
+					}
+				}
+
+				else if (arg.equals("-dLRT")) {
+					options.doDLRT = true;
+				}
+
+				else if (arg.equals("-r")) {
+					options.backwardHLRTSelection = true;
+				}
+
+				else if (arg.equals("-h")) {
+					if (i < arguments.length) {
+						try {
+							String type = arguments[i++];
+							options.confidenceLevelHLRT = Double
+									.parseDouble(type);
+						} catch (NumberFormatException e) {
+							System.err
+									.println(error
+											+ "-h option requires a number (0-1) for the hLRT confidence interval.");
+							CommandLineError();
+						}
+					} else {
+						System.err
+								.println(error
+										+ "-h option requires a number (0-1) for the hLRT confidence interval.");
+						CommandLineError();
+					}
+				}
+
+				else if (arg.equals("-a")) {
+					options.doAveragedPhylogeny = true;
+				}
+
+				else if (arg.equals("-z")) {
+					options.consensusType = "strict";
+				}
+
+				else if (arg.equals("-sims")) {
+					if (i < arguments.length) {
+						options.simulationsName = arguments[i++];
+						options.doingSimulations = true;
+					} else {
+						System.err
+								.println(error
+										+ "-sims option requires a name for the simulations files");
+						CommandLineError();
+					}
+
+				} else if (arg.equals("-machinesfile")) {
+					if (i < arguments.length) {
+
+						File machinesFile = new File(arguments[i++]);
+						if (!(machinesFile.exists() && machinesFile.canRead())) {
+							if (MPJ_ME == 0) {
+								System.err
+										.println(error
+												+ "Machines file does not exists or it is not readable");
+							}
+							CommandLineError();
+						}
+
+						boolean hostsError = false;
+						try {
+							TextInputStream machinesInputStream = new TextInputStream(
+									machinesFile.getAbsolutePath());
+							String line;
+
+							HOSTS_TABLE = new Hashtable<String, Integer>();
+							while ((line = machinesInputStream.readLine()) != null) {
+								String hostProcs[] = line.split(":");
+								if (hostProcs.length == 2) {
+									try {
+
+										int numberOfThreads = Integer
+												.parseInt(hostProcs[1]);
+
+										HOSTS_TABLE.put(hostProcs[0],
+												new Integer(numberOfThreads));
+
+									} catch (NumberFormatException e) {
+										hostsError = true;
+										break;
+										// Warn and continue with 1 processor
+									}
+								} else {
+									hostsError = true;
+								}
+
+								if (hostsError) {
+									if (MPJ_ME == 0) {
+										System.err.println("");
+										System.err
+												.println("WARNING: Machines File format is wrong.");
+										System.err
+												.println("         Each line should have the following format:");
+										System.err
+												.println("         HOSTNAME:NUMBER_OF_PROCESORS");
+										System.err
+												.println("Using a single thread");
+										System.err.println("");
+									}
+									HOSTS_TABLE = null;
+									options.setNumberOfThreads(1);
+								}
+							}
+							options.setMachinesFile(machinesFile);
+
+						} catch (FileNotFoundException e) {
+							System.err
+									.println(error
+											+ "Machines file does not exists or it is not readable");
+							CommandLineError();
+						}
+					} else {
+						System.err.println(error
+								+ "-machinesfile option requires a filename");
+						CommandLineError();
+					}
+				} else if (arg.equals("-tr")) {
+					if (HOSTS_TABLE != null) {
+						String type = arguments[i++];
+						System.err
+								.println("WARNING: Machines File has been specified. -tr "
+										+ type + " argument will be ignored.");
+					} else {
+						if (i < arguments.length) {
+							try {
+								String type = arguments[i++];
+								options.setNumberOfThreads(Integer
+										.parseInt(type));
+								options.threadScheduling = true;
+							} catch (NumberFormatException e) {
+								System.err
+										.println(error
+												+ "-tr option requires the number of processors to compute.");
+								CommandLineError();
+							}
+						} else {
+							System.err
+									.println(error
+											+ "-tr option requires the number of processors to compute.");
+							CommandLineError();
+						}
+					}
+
+				} else if (arg.equals("--set-local-config")) {
+					if (i < arguments.length) {
+						String localConfigFile = arguments[i++];
+						File testFile = new File(localConfigFile);
+						if (!(testFile.exists() && testFile.canRead())) {
+							System.err.println(error
+									+ "Config file " + localConfigFile +" does not exist or cannot be read.");
+							CommandLineError();
+						}
+						ModelTest.CONFIG_FILE = testFile.getAbsolutePath();
+					} else {
+						System.err.println(error
+								+ "--set-local-config option requires a config file.");
+						CommandLineError();
+					}
+				}  else if (arg.equals("--set-property")) {
+					if (i < arguments.length) {
+						String propertyDef = arguments[i++];
+						if (propertyDef.indexOf("=") == -1) {
+							System.err.println(error
+									+ "--set-property option requires a property definition with the following format:");
+							System.err.println("                    --set-property <property_name>=<property_value>");
+							System.err.println("              e.g., --set-property log-dir=myHome/myLogDir");
+							CommandLineError();
+						}
+						String propertyName = propertyDef.split("=")[0].trim();
+						String propertyValue = propertyDef.split("=")[1].trim();
+						USERDEF_PROPERTIES.setProperty(propertyName, propertyValue);
+					} else {
+						System.err.println(error
+								+ "--set-property option requires a property definition.");
+						System.err.println(error
+								+ "e.g., --set-property log-dir=myHome/myLogDir");
+						CommandLineError();
+					}
+				}
+				else {
+					System.err.println(error + "the argument \" " + arg
+							+ "\" is unknown. Check its syntax.");
+					CommandLineError();
+				}
+			} // while
+			if (!isInputFile) {
+				System.err.println(error
+						+ "Input File is required (-d argument)");
+				CommandLineError();
+			}
+			if (getPhylip) {
+				MAIN_CONSOLE.print("\n\nReading data file \"" + options.getInputFile().getName()
+						+ "\"...");
+
+				if (options.getInputFile().exists()) {
+
+					try {
+						File outputFile = new File(options.getInputFile().getAbsolutePath() + ".phy");
+						ModelTestService.readAlignment(options.getInputFile(),
+								outputFile, false);
+						MAIN_CONSOLE.println(" OK.");
+						MAIN_CONSOLE.println("Result written into " + outputFile.getPath());
+						MAIN_CONSOLE.println("");
+					} catch (Exception e)// file cannot be read correctly
+					{
+						System.err.println("\nThe specified file \""
+								+ options.getInputFile().getAbsolutePath()
+								+ "\" cannot be read as an alignment");
+						MAIN_CONSOLE.println(" failed.\n" + e.getMessage());
+						throw new InvalidArgumentException.InvalidAlignmentFileException(
+								options.getInputFile());
+					}
+				} else // file does not exist
+				{
+					System.err.println("\nThe specified file \""
+							+ options.getInputFile().getAbsolutePath() + "\" cannot be found");
+					throw new InvalidArgumentException.UnexistentAlignmentFileException(
+							options.getInputFile());
+				}
+				finalize(0);
+			}
+			
+			if (ckpFile != null) {
+				if (!loadCheckpoint(ckpFile)) {
+					System.err.println("\nThe specified checkpoint file \""
+							+ options.getInputFile().getAbsolutePath()
+							+ "\" cannot be read");
+					finalize(0);
+				}
+			}
+			
+			if (testingOrder != null && !options.doHLRT) {
+				System.err.println("\nWARNING: Hypothesis testing order has been set, but hierarchical Likelihood Ratio Test was not selected with '-hLRT' parameter");
+				System.err.println("         Thus, this option has no effect\n");
+			}
+			
+			if (isIcForHcSet && options.getSubstTypeCode() != 4) {
+				System.err.println("\nWARNING: Information Criterion for hierarchical clustering has been specified, but hierarchical clustering applies only for 203 substitution schemes");
+				System.err.println("         Thus, this option has no effect\n");
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+		// add default IC
+		options.doBIC |= !(options.doAIC || options.doAICc || options.doDT);
+	}
+
+	static public void CommandLineError() {
+		System.err.println("\nPlease run with -help argument for info about the usage\n");
+		System.exit(1);
+	}
+	
+	/****************************
+	 * PrintUsage **************************** * Prints command line usage * *
+	 ************************************************************************/
+	static public void PrintUsage() {
+		if (MPJ_ME == 0) {
+			System.err.println("\njModelTest command usage");
+			System.err.println(
+			    "java -jar jModelTest.jar -d sequenceFileName"
+			+ "\n                        [-getPhylip]"
+			+ "\n                        [-ckp checkpointFileName.ckp]"
+			+ "\n                        [-n executionName]"
+			+ "\n                        [-t fixed|BIONJ|ML] [-u userTreeFileName] [-o outputFileName]"
+			+ "\n                        [-S NNI|SPR|BEST]"
+			+ "\n                        [-AIC] [-AICc] [-BIC] [-DT] [-c confidenceInterval]"
+			+ "\n                        [-s 3|5|7|11|203]"
+			+ "\n                        [-f] [-i] [-g numberOfCategories]"
+			+ "\n                        [-uLNL]"
+			+ "\n                        [-dLRT] [-h confidenceInterval] [-hLRT] [-O {ftvwxgp}]"
+			+ "\n                        [-a] [-z] [-p] [-v] [-w]"
+			+ "\n                        [-tr numberOfThreads] [-machinesfile machinesFileName]"
+			);
+			String usage = 
+					  "\n     -a"
+					+ "\n         estimate model-averaged phylogeny for each active criterion (e.g., -a) (default is false)"
+					+ "\n\n     -AIC"
+					+ "\n         calculate the Akaike Information Criterion (e.g., -AIC) (default is false)"
+					+ "\n\n     -AICc"
+					+ "\n         calculate the corrected Akaike Information Criterion (e.g., -AICc) (default is false)"
+					+ "\n\n     -BIC"
+					+ "\n         calculate the Bayesian Information Criterion (e.g., -BIC) (default is false)"
+					+ "\n\n     -DT"
+					+ "\n         calculate the decision theory criterion (e.g., -DT) (default is false)"
+					+ "\n\n     -c confidenceInterval"
+					+ "\n         confidence interval (e.g., -c 90) (default is 100)"
+					+ "\n\n     -ckp checkpointFileName"
+					+ "\n         Loads a checkpointing file"
+					+ "\n\n     -d sequenceFileName"
+					+ "\n         input data file (e.g., -d data.phy)"
+					+ "\n\n     -dLRT"
+					+ "\n         do dynamical likelihood ratio tests (e.g., -dLRT)(default is false)"
+					+ "\n\n     -f"
+					+ "\n         include models with unequals base frecuencies (e.g., -f) (default is false)"
+					+ "\n\n     -g numberOfCategories"
+					+ "\n         include models with rate variation among sites and number of categories (e.g., -g 8) (default is false & 4 categories)"
+					+ "\n\n     -G threshold"
+					+ "\n         heuristic search. Requires a threshold > 0 (e.g., -G 0.1)"
+					+ "\n\n     -getPhylip"
+					+ "\n         converts the input file into phylip format"
+					+ "\n\n     -h confidenceInterval"
+					+ "\n         confidence level for the hLRTs (e.g., -a0.002) (default is 0.01)"
+					+ "\n\n     -H informationCriterion"
+					+ "\n         information criterion for clustering search (AIC, AICc, BIC). (default is BIC)"
+					+ "\n         this argument applies only for 203 substitution schemes (e.g., -s 203 -H AIC)"
+					+ "\n\n     -help"
+					+ "\n         displays this help message"
+					+ "\n\n     -hLRT"
+					+ "\n         do hierarchical likelihood ratio tests (default is false)"
+					+ "\n         hypothesis testing order can be specified with -O argument"
+					+ "\n\n     -i"
+					+ "\n         include models with a proportion invariable sites (e.g., -i) (default is false)"
+					+ "\n\n     -machinesfile manchinesFileName"
+					+ "\n         gets the processors per host from a machines file"
+					+ "\n\n     -n executionName"
+					+ "\n         execution name for appending to the log filenames (default: current time yyyyMMddhhmmss)"
+					+ "\n\n     -o outputFileName"
+					+ "\n         set output file (e.g., -o jmodeltest.out)"
+					+ "\n\n     -O hypothesisOrder"
+					+ "\n         hypothesis order for the hLRTs (e.g., -hLRT -O gpftv) (default is ftvwxgp)"
+					+ "\n            f=freq, t=titvi, v=2ti4tv(subst=3)/2ti(subst>3), w=2tv, x=4tv, g=gamma, p=pinv"
+					+ "\n            this argument is used only if -hLRT argument is set"
+					+ "\n            'f','t','v','g','p' are mandatory in any order. 'w' is optional, and 'x' requires 'w' to be present"
+					+ "\n            thus, length should be 5, 6 *including 'w') or 7 (including both 'w' and 'x')"
+					+ "\n            e.g., -hLRT -O gpfvwxt"
+					+ "\n\n     -p"
+					+ "\n         calculate parameter importances (e.g., -p) (default is false)"
+					+ "\n\n     -r"
+					+ "\n         backward selection for the hLRT (e.g., -r) (default is forward)"
+					+ "\n\n     -s numberOfSubstitutionSchemes"
+					+ "\n         number of substitution schemes (e.g., -s 11) (it has to be 3,5,7,11,203; default is 3)"
+					+ "\n\n     --set-local-config localConfigurationFile"
+					+ "\n         set a local configuration file in replacement of conf/jmodeltest.conf"
+					+ "\n\n     --set-property propertyName=propertyValue"
+					+ "\n         set a new value for a property contained in the configuration file (conf/jmodeltest.conf)"
+					+ "\n\n     -S NNI|SPR|BEST"
+					+ "\n         tree topology search operation option (NNI (fast), SPR (a bit slower), BEST (best of NNI and SPR)) (default is BEST)"
+					+ "\n\n     -t fixed|BIONJ|ML"
+					+ "\n             base tree for likelihood calculations (e.g., -t BIONJ)"
+					+ "\n             fixed  (common BIONJ-JC topology)"
+					+ "\n             BIONJ  (Neighbor-Joining topology)"
+					+ "\n             ML     (Maximum Likelihood topology) (default)"
+					+ "\n\n     -tr numberOfThreads"
+					+ "\n         number of threads to execute (default is "
+					+ Runtime.getRuntime().availableProcessors()
+					+ ")"
+					+ "\n\n     -u treeFileName"
+					+ "\n         user tree for likelihood calculations  (e.g., -u data.tre)"
+					+ "\n\n     -uLnL"
+					+ "\n         calculate delta AIC,AICc,BIC against unconstrained likelihood (e.g., -uLnL)"
+					+ "\n\n        (default is false if the input alignment has gaps or ambiguous characters)"
+					+ "\n\n     -v"
+					+ "\n         do model averaging and parameter importances (e.g., -v) (default is false)"
+					+ "\n\n     -w"
+					+ "\n         write PAUP block (e.g., -w) (default is false)"
+					+ "\n\n     -z"
+					+ "\n         strict consensus type for model-averaged phylogeny (e.g., -z) (default is majority rule)"
+					+ "\n\n Command line: java -jar jModeltest.jar -d sequenceFileName [arguments]"
+					+ "\n\n Example: java -jar jModeltest.jar -d sequenceFileName -i -f -g 4 -BIC -AIC -AICc -DT -v -a -w";
+			System.err.println(usage);
+			System.err.println(" ");
+		}
+		System.exit(0);
+	}
+
+	/****************************
+	 * printHeader ****************************** * Prints header information at
+	 * start * * *
+	 ***********************************************************************/
+
+	static public void printHeader(TextOutputStream stream) {
+		// we can set styles using the editor pane
+		// I am using doc to stream ....
+		stream.print("-------------------------- ");
+		stream.print("jModeltest " + CURRENT_VERSION);
+		stream.println(" --------------------------");
+		stream.println("(c) 2011-onwards D. Darriba, G.L. Taboada, R. Doallo and D. Posada,");
+		stream.println("(1) Department of Biochemistry, Genetics and Immunology");
+		stream.println("    University of Vigo, 36310 Vigo, Spain.");
+		stream.println("(2) Department of Electronics and Systems");
+		stream.println("    University of A Coruna, 15071 A Coruna, Spain.");
+		stream.println("e-mail: ddarriba at udc.es, dposada at uvigo.es");
+		stream.println("--------------------------------------------------------------------------------");
+		stream.println(" ");
+		java.util.Date current_time = new java.util.Date();
+		stream.println(current_time.toString());
+		stream.println(System.getProperty("os.name") + " "
+				+ System.getProperty("os.version") + ", arch: "
+				+ System.getProperty("os.arch") + ", bits: "
+				+ System.getProperty("sun.arch.data.model") + ", numcores: "
+				+ Runtime.getRuntime().availableProcessors());
+		stream.println(" ");
+	}
+
+	/****************************
+	 * printNotice ****************************** * Prints notice information at
+	 * start up * * *
+	 ***********************************************************************/
+
+	static public void printNotice(TextOutputStream stream) {
+		// stream.println("\n******************************* NOTICE ************************************");
+		stream.println("jModelTest " + CURRENT_VERSION);
+		stream.println("Copyright (C) 2011 D. Darriba, G.L. Taboada, R. Doallo and D. Posada");
+		stream.println("This program comes with ABSOLUTELY NO WARRANTY");
+		stream.println("This is free software, and you are welcome to redistribute it under certain conditions");
+		stream.println(" ");
+		stream.println("Notice: This program may contain errors. Please inspect results carefully.");
+		stream.println(" ");
+		// stream.println("***************************************************************************\n");
+
+	}
+
+	/****************************
+	 * printCitation ****************************** * Prints citation
+	 * information at start up * * *
+	 ***********************************************************************/
+
+	static public void printCitation(TextOutputStream stream) {
+		// stream.println("\n******************************* CITATION *********************************");
+		stream.println("--------------------------------------------------------------------------------");
+		stream.println("Citation: Darriba D, Taboada GL, Doallo R and Posada D. 2012.");
+		stream.println("          \"jModelTest 2: more models, new heuristics and parallel computing\".");
+		stream.println("          Nature Methods 9(8), 772.");
+		stream.println("--------------------------------------------------------------------------------");
+		stream.println(" ");
+		// stream.println("***************************************************************************\n");
+
+	}
+
+	/****************************
+	 * writePaupBlockk *************************** * Prints a block of PAUP
+	 * commands for the best model * *
+	 ************************************************************************/
+	static public void WritePaupBlock(TextOutputStream stream,
+			String criterion, Model model) {
+		try {
+			stream.println("\n--\nPAUP* Commands Block:");
+			stream.println(" If you want to load the selected model and associated estimates in PAUP*,");
+			stream.println(" attach the next block of commands after the data in your PAUP file:");
+			stream.print("\n[!\nLikelihood settings from best-fit model (");
+			stream.printf("%s", model.getName());
+			stream.print(") selected by ");
+			stream.printf("%s", criterion);
+			stream.print("\nwith ");
+			stream.printf("%s", programName);
+			stream.print(" ");
+			stream.printf("%s", CURRENT_VERSION);
+			stream.print(" on ");
+			java.util.Date current_time = new java.util.Date();
+			stream.print(current_time.toString());
+			stream.println("]");
+
+			stream.print("\nBEGIN PAUP;");
+			stream.print("\nLset");
+
+			/* base frequencies */
+			stream.print(" base=");
+			if (model.ispF()) {
+				stream.print("(");
+				stream.printf("%.4f ", model.getfA());
+				stream.printf("%.4f ", model.getfC());
+				stream.printf("%.4f ", model.getfG());
+				/* stream.printf("%.4f",model.fT); */
+				stream.print(")");
+			} else
+				stream.print("equal");
+
+			/* substitution rates */
+			if (!model.ispT() && !model.ispR())
+				stream.print(" nst=1");
+			else if (model.ispT()) {
+				stream.print(" nst=2 tratio=");
+				stream.printf("%.4f", model.getTitv());
+			} else if (model.ispR()) {
+				stream.print(" nst=6  rmat=(");
+				stream.printf("%.4f ", model.getRa());
+				stream.printf("%.4f ", model.getRb());
+				stream.printf("%.4f ", model.getRc());
+				stream.printf("%.4f ", model.getRd());
+				stream.printf("%.4f)", model.getRe());
+				/* stream.print("1.0000)"); */
+			}
+
+			/* site rate variation */
+			stream.print(" rates=");
+			if (model.ispG()) {
+				stream.print("gamma shape=");
+				stream.printf("%.4f", model.getShape());
+				stream.print(" ncat=");
+				stream.printf("%d", model.getNumGammaCat());
+			} else
+				stream.print("equal");
+
+			/* invariable sites */
+			stream.print(" pinvar=");
+			if (model.ispI())
+				stream.printf("%.4f", model.getPinv());
+			else
+				stream.print("0");
+
+			stream.print(";\nEND;");
+			stream.print("\n--\n");
+		}
+
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	private void checkInputFiles() {
+		// open data file
+		File inputFile = options.getInputFile();
+		MAIN_CONSOLE.print("\n\nReading data file \"" + inputFile.getName()
+				+ "\"...");
+
+		if (inputFile.exists()) {
+
+			try {
+				
+				String alnString = ModelTestService.readAlignment(inputFile,
+						options.getAlignmentFile());
+				
+				PushbackReader pr = new PushbackReader(
+						new StringReader(alnString)
+						);
+				options.setAlignment(AlignmentReader.createAlignment(
+						new PrintWriter(System.err), pr, true)); // file
+				
+				MAIN_CONSOLE.println(" OK.");
+				MAIN_CONSOLE.println("  number of sequences: "
+						+ options.getNumTaxa());
+				MAIN_CONSOLE.println("  number of sites: "
+						+ options.getNumSites());
+			} catch (Exception e)// file cannot be read correctly
+			{
+				System.err.println("\nThe specified file \""
+						+ inputFile.getAbsolutePath()
+						+ "\" cannot be read as an alignment");
+				MAIN_CONSOLE.println(" failed.\n" + e.getMessage());
+				throw new InvalidArgumentException.InvalidAlignmentFileException(
+						inputFile);
+			}
+		} else // file does not exist
+		{
+			System.err.println("\nThe specified file \""
+					+ inputFile.getAbsolutePath() + "\" cannot be found");
+			MAIN_CONSOLE.println(" failed.\n");
+			throw new InvalidArgumentException.UnexistentAlignmentFileException(
+					inputFile);
+		}
+
+		// open tree file if necessary
+		if (options.userTopologyExists) {
+			File treefile = options.getInputTreeFile();
+			MAIN_CONSOLE.print("Reading tree file \"" + treefile.getName()
+					+ "\"...");
+
+			// read the tree in
+			Tree tree = null;
+			try {
+				tree = TreeUtilities.readTree(treefile.getAbsolutePath());
+			} catch (IOException e) {
+				System.err.println("\nThe specified tree file \""
+						+ treefile.getName() + "\" cannot be found");
+				MAIN_CONSOLE.println(" failed.\n");
+				throw new InvalidArgumentException.UnexistentTreeFileException(
+						treefile.getAbsolutePath());
+			} catch (TreeParseException e) {
+				System.err.println("\nCannot parse tree file \""
+						+ treefile.getName() + "\"");
+				MAIN_CONSOLE.println(" failed.\n");
+				throw new InvalidArgumentException.InvalidTreeFileException(
+						treefile.getAbsolutePath());
+			}
+			if (tree != null) {
+				options.setUserTree(TreeUtilities.toNewick(tree, true, false,
+						false));
+				TextOutputStream out = new TextOutputStream(options
+						.getTreeFile().getAbsolutePath());
+				out.print(options.getUserTree());
+				out.close();
+				MAIN_CONSOLE.println(" OK.");
+			} else // tree is not valid
+			{
+				System.err.println("\nUnexpected error parsing \""
+						+ treefile.getName() + "\"");
+				MAIN_CONSOLE.println(" failed.\n");
+				throw new InvalidArgumentException.InvalidTreeFileException(
+						treefile.getAbsolutePath());
+			}
+
+		}
+	}
+
+	public static TextOutputStream setMainConsole(TextOutputStream mainConsole) {
+		ModelTest.MAIN_CONSOLE = mainConsole;
+		return mainConsole;
+	}
+
+	public static TextOutputStream getMainConsole() {
+		return MAIN_CONSOLE;
+	}
+
+	public static TextOutputStream setPhymlConsole(TextOutputStream phymlConsole) {
+		ModelTest.PHYML_CONSOLE = phymlConsole;
+		return phymlConsole;
+	}
+
+	public static TextOutputStream getPhymlConsole() {
+		return PHYML_CONSOLE;
+	}
+	
+	public static TextOutputStream getCurrentOutStream() {
+		return CURRENT_OUT_STREAM;
+	}
+
+	public static void setCurrentOutStream(TextOutputStream currentOutStream) {
+		CURRENT_OUT_STREAM = currentOutStream;
+	}
+
+	public static AIC getMyAIC() {
+		if (!AICwasCalculated)
+			throw new WeakStateException.UninitializedCriterionException("AIC");
+		return myAIC;
+	}
+
+	public static void setMyAIC(AIC myAIC) {
+		ModelTest.myAIC = myAIC;
+		ModelTest.minAIC = myAIC != null ? myAIC.getMinModel() : null;
+		AICwasCalculated = (myAIC != null);
+	}
+
+	public static boolean testAIC() {
+		return AICwasCalculated;
+	}
+
+	public static AICc getMyAICc() {
+		if (!AICcwasCalculated)
+			throw new WeakStateException.UninitializedCriterionException("AICc");
+		return myAICc;
+	}
+
+	public static void setMyAICc(AICc myAICc) {
+		ModelTest.myAICc = myAICc;
+		ModelTest.minAICc = myAICc != null ? myAICc.getMinModel() : null;
+		AICcwasCalculated = (myAICc != null);
+	}
+
+	public static boolean testAICc() {
+		return AICcwasCalculated;
+	}
+
+	public static BIC getMyBIC() {
+		if (!BICwasCalculated)
+			throw new WeakStateException.UninitializedCriterionException("BIC");
+		return myBIC;
+	}
+
+	public static void setMyBIC(BIC myBIC) {
+		ModelTest.myBIC = myBIC;
+		ModelTest.minBIC = myBIC != null ? myBIC.getMinModel() : null;
+		BICwasCalculated = (myBIC != null);
+	}
+
+	public static boolean testBIC() {
+		return BICwasCalculated;
+	}
+
+	public static DT getMyDT() {
+		if (!DTwasCalculated)
+			throw new WeakStateException.UninitializedCriterionException("DT");
+		return myDT;
+	}
+
+	public static void setMyDT(DT myDT) {
+		ModelTest.myDT = myDT;
+		ModelTest.minDT = myDT != null ? myDT.getMinModel() : null;
+		DTwasCalculated = (myDT != null);
+	}
+
+	public static boolean testDT() {
+		return DTwasCalculated;
+	}
+
+	public static RunConsense getConsensusAIC() {
+		return consensusAIC;
+	}
+
+	public static RunConsense getConsensusAICc() {
+		return consensusAICc;
+	}
+
+	public static RunConsense getConsensusBIC() {
+		return consensusBIC;
+	}
+
+	public static RunConsense getConsensusDT() {
+		return consensusDT;
+	}
+
+	public static void setConsensusAIC(RunConsense pConsensusAIC) {
+		consensusAIC = pConsensusAIC;
+	}
+
+	public static void setConsensusAICc(RunConsense pConsensusAICc) {
+		consensusAICc = pConsensusAICc;
+	}
+
+	public static void setConsensusBIC(RunConsense pConsensusBIC) {
+		consensusBIC = pConsensusBIC;
+	}
+
+	public static void setConsensusDT(RunConsense pConsensusDT) {
+		consensusDT = pConsensusDT;
+	}
+
+	/**
+	 * Finalizes the MPJ runtime environment. When an error occurs, it aborts
+	 * the execution of every other processes.
+	 * 
+	 * @param status
+	 *            the finalization status
+	 */
+	public static void finalize(int status) {
+
+		if (status != 0) {
+			if (MPJ_RUN) {
+				MPI.COMM_WORLD.Abort(status);
+			}
+		}
+
+		if (MPJ_RUN) {
+			MPI.Finalize();
+		}
+
+		System.exit(status);
+
+	}
+
+	/**
+	 * @param minDLRT
+	 *            the minDLRT to set
+	 */
+	public static void setMinDLRT(Model minDLRT) {
+		ModelTest.minDLRT = minDLRT;
+	}
+
+	/**
+	 * @return the minDLRT
+	 */
+	public static Model getMinDLRT() {
+		return minDLRT;
+	}
+
+	/**
+	 * @param minHLRT
+	 *            the minHLRT to set
+	 */
+	public static void setMinHLRT(Model minHLRT) {
+		ModelTest.minHLRT = minHLRT;
+	}
+
+	/**
+	 * @return the minHLRT
+	 */
+	public static Model getMinHLRT() {
+		return minHLRT;
+	}
+
+	/**
+	 * @return the minDT
+	 */
+	public static Model getMinDT() {
+		return minDT;
+	}
+
+	/**
+	 * @return the minBIC
+	 */
+	public static Model getMinBIC() {
+		return minBIC;
+	}
+
+	/**
+	 * @return the minAICc
+	 */
+	public static Model getMinAICc() {
+		return minAICc;
+	}
+
+	/**
+	 * @return the minAIC
+	 */
+	public static Model getMinAIC() {
+		return minAIC;
+	}
+
+	/**
+	 * @param candidateModels
+	 *            the candidateModels to set
+	 */
+	public static void setCandidateModels(Model[] candidateModels) {
+		ApplicationOptions.getInstance().setNumModels(candidateModels.length);
+		ModelTest.candidateModels = candidateModels;
+	}
+
+	/**
+	 * @return the loadedModels
+	 */
+	public static Model[] getLoadedModels() {
+		return loadedModels;
+	}
+	
+	/**
+	 * @return the candidateModels
+	 */
+	public static Model[] getCandidateModels() {
+		return candidateModels;
+	}
+
+	/**
+	 * @return a single candidate model
+	 */
+	public static Model getCandidateModel(int index) {
+		return candidateModels[index];
+	}
+
+	public static String getHostname() {
+		return hostname;
+	}
+
+	public static void purgeModels() {
+		List<Model> modelList = new ArrayList<Model>();
+		for (Model model : candidateModels) {
+			if (model.getLnL() > 0) {
+				modelList.add(model);
+			}
+		}
+		candidateModels = modelList.toArray(new Model[0]);
+		ApplicationOptions.getInstance().setNumModels(candidateModels.length);
+	}
+
+	public class NullPrinter extends OutputStream {
+
+		@Override
+		public void write(int arg0) throws IOException {
+			// DO NOTHING
+
+		}
+
+	}
+
+} // class ModelTest
+
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/ModelTestConfiguration.java b/src/main/java/es/uvigo/darwin/jmodeltest/ModelTestConfiguration.java
new file mode 100644
index 0000000..ac88975
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/ModelTestConfiguration.java
@@ -0,0 +1,188 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public abstract class ModelTestConfiguration {
+
+	private static String convertPathToAbsolute(String path) {
+		Map<String, String> envMap = System.getenv();
+    	String pattern = "\\$\\{([A-Za-z0-9]+)\\}";
+    	Pattern expr = Pattern.compile(pattern);
+    	Matcher matcher = expr.matcher(path);
+    	while (matcher.find()) {
+    	    String envValue = envMap.get(matcher.group(1).toUpperCase());
+    	    if (envValue == null) {
+    	        envValue = "";
+    	    } else {
+    	        envValue = envValue.replace("\\", "\\\\");
+    	    }
+    	    Pattern subexpr = Pattern.compile(Pattern.quote(matcher.group(0)));
+    	    path = subexpr.matcher(path).replaceAll(envValue);
+    	}
+    	
+		if (Utilities.isWindows()) {
+			// change wrong path separators
+			path.replace('/', '\\');
+		} else {
+			File fPath = new File(path);
+			if (!fPath.isAbsolute()) {
+				path = PATH + path;
+			}
+		}
+		return path;
+	}
+	
+	 /** The application APPLICATION_PROPERTIES. */
+    private static final Properties APPLICATION_PROPERTIES;
+    
+    public static final boolean DEFAULT_GLOBAL_PHYML = false;
+    
+    private static String JAR_PATH;
+    public static String PATH;
+    public static String DEFAULT_EXE_DIR;
+    public static String DEFAULT_LOG_DIR;
+    
+    public static final String HTML_LOG = "html-logging";
+    public static final String PHYML_LOG = "phyml-logging";
+    public static final String CKP_LOG = "checkpointing";
+    public static final String LOG_DIR = "log-dir";
+    public static final String EXE_DIR = "exe-dir";
+    public static final String GLOBAL_PHYML_EXE = "global-phyml-exe";
+    public static final String G_THREADS = "gamma-threads";
+    public static final String I_THREADS = "inv-threads";
+    public static final String U_THREADS = "uniform-threads";
+    
+    static {
+        APPLICATION_PROPERTIES = new Properties();
+        
+        try {
+        	try {
+        		File f = new File(ModelTest.class.getProtectionDomain().getCodeSource().getLocation().toURI());
+        		JAR_PATH = f.getAbsolutePath();
+        		PATH = JAR_PATH.replaceFirst(new File(JAR_PATH).getName(),"");
+        		DEFAULT_EXE_DIR = PATH + "exe" + File.separator + "phyml";
+        		DEFAULT_LOG_DIR = PATH + "log";
+			} catch (URISyntaxException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+        	FileInputStream prop = new FileInputStream(convertPathToAbsolute(ModelTest.CONFIG_FILE));
+            APPLICATION_PROPERTIES.load(prop);
+            /* load also user definitions */
+            for (Object key : ModelTest.USERDEF_PROPERTIES.keySet()) {
+            	String strKey = (String) key;
+            	if (strKey.equals(LOG_DIR) || strKey.equals(EXE_DIR)) {
+            		File fDir = new File(ModelTest.USERDEF_PROPERTIES.getProperty(strKey));
+            		if (!fDir.exists()) {
+            			System.err.println("\nCOMMAND LINE ERROR: Unexistent directory " + fDir.getAbsolutePath());
+            			ModelTest.CommandLineError();
+            		} else if (!(fDir.isDirectory() && fDir.canRead()) || (strKey.equals(LOG_DIR) && !fDir.canWrite())) {
+            			System.err.println("\nCOMMAND LINE ERROR: Argument " + fDir.getAbsolutePath() 
+            					+ " is not a directory or you have not the required permissions on it");
+            			ModelTest.CommandLineError();
+        			}
+            		APPLICATION_PROPERTIES.setProperty(strKey, fDir.getAbsolutePath());
+            	} else {
+            		APPLICATION_PROPERTIES.setProperty(strKey, ModelTest.USERDEF_PROPERTIES.getProperty(strKey));
+            	}
+            }
+            
+        	if (!existsKey(LOG_DIR)) {
+        		APPLICATION_PROPERTIES.setProperty(HTML_LOG, "disabled");
+        		APPLICATION_PROPERTIES.setProperty(PHYML_LOG, "disabled");
+        		APPLICATION_PROPERTIES.setProperty(CKP_LOG, "disabled");
+        	}
+        	
+        } catch (IOException e) {
+            System.err.println("Configuration file ("+ convertPathToAbsolute(ModelTest.CONFIG_FILE) +") cannot be resolved");
+            System.exit(-1);
+        }
+    }
+    
+    public static boolean existsKey(String key) {
+	return !(getProperty(key).equals("n/a"));
+    }
+
+    public static String getProperty(String key) {
+    	return APPLICATION_PROPERTIES.getProperty(key, "n/a");
+    }
+    
+    public static String getExeDir() {
+    	String exeDir;
+		if (existsKey(EXE_DIR)) {
+			exeDir = getProperty(EXE_DIR);
+		} else {
+			exeDir = DEFAULT_EXE_DIR;
+		}
+		return convertPathToAbsolute(exeDir);
+	}
+    
+    public static void disableCkpLog() {
+    	APPLICATION_PROPERTIES.setProperty(CKP_LOG, "disabled");
+    }
+    
+    public static void disablePhymlLog() {
+    	APPLICATION_PROPERTIES.setProperty(PHYML_LOG, "disabled");
+    }
+    
+    public static void disableHtmlLog() {
+    	APPLICATION_PROPERTIES.setProperty(HTML_LOG, "disabled");
+    }
+    
+    public static boolean isGlobalPhymlBinary() {
+    	String propValue = getProperty(GLOBAL_PHYML_EXE); 
+    	return (existsKey(propValue) && getProperty(GLOBAL_PHYML_EXE).equalsIgnoreCase("true"));
+    }
+    
+    public static boolean isHtmlLogEnabled() {
+    	return getProperty(HTML_LOG).equalsIgnoreCase("enabled");
+    }
+    
+    public static boolean isPhymlLogEnabled() {
+    	return getProperty(PHYML_LOG).equalsIgnoreCase("enabled");
+    }
+    
+    public static boolean isCkpEnabled() {
+    	return getProperty(CKP_LOG).equalsIgnoreCase("enabled");
+    }
+    
+    public static String getLogDir() {
+    	String logDir = getProperty(LOG_DIR);
+    	if (logDir == null) {
+    		logDir = DEFAULT_LOG_DIR;
+    	}
+    	
+    	return convertPathToAbsolute(logDir);
+    }
+    
+    public static Properties getProperties() {
+    	return APPLICATION_PROPERTIES;
+    }
+    
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/ModelTestService.java b/src/main/java/es/uvigo/darwin/jmodeltest/ModelTestService.java
new file mode 100644
index 0000000..f824602
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/ModelTestService.java
@@ -0,0 +1,171 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest;
+
+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 java.io.PrintStream;
+
+import parser.ParseException;
+import converter.Converter;
+import converter.DefaultFactory;
+import converter.Factory;
+import es.uvigo.darwin.jmodeltest.exception.AlignmentParseException;
+import es.uvigo.darwin.jmodeltest.io.NullPrintStream;
+import es.uvigo.darwin.jmodeltest.selection.AIC;
+import es.uvigo.darwin.jmodeltest.selection.AICc;
+import es.uvigo.darwin.jmodeltest.selection.BIC;
+import es.uvigo.darwin.jmodeltest.selection.DT;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class ModelTestService {
+
+	/**
+     * Read alignment into a temporary file.
+     * 
+     * @param inputFile the file to be read
+     * @param outputFile the file to write in
+     * 
+     * @throws AlignmentParseException the alignment parse exception.
+     * @throws FileNotFoundException Signals that the input filename does not exist.
+     * @throws IOException Signals that an I/O exception has occured.
+     */
+	public static String readAlignment(File inputFile, File outputFile)
+            throws AlignmentParseException, FileNotFoundException, IOException {
+		return readAlignment(inputFile, outputFile, true);
+	}
+	
+	/**
+     * Read alignment.
+     * 
+     * @param inputFile the file to be read
+     * @param outputFile the file to write in
+     * 
+     * @throws AlignmentParseException the alignment parse exception.
+     * @throws FileNotFoundException Signals that the input filename does not exist.
+     * @throws IOException Signals that an I/O exception has occured.
+     */
+    public static String readAlignment(File inputFile, File outputFile, boolean deleteOnExit)
+            throws AlignmentParseException, FileNotFoundException, IOException {
+
+        StringBuilder text = new StringBuilder();
+
+        BufferedReader br = new BufferedReader(
+        		new FileReader(inputFile.getAbsolutePath()));
+        String s;
+        while ((s = br.readLine()) != null) {
+            text.append(s).append("\r\n");
+        }
+        br.close();
+
+
+        //Get options
+        String in = text.toString();
+        String inO = "";
+        String inP = "";
+        String inF = "";
+        boolean autodetect = true;
+        boolean collapse = false;
+        boolean gaps = false;
+        boolean missing = false;
+        int limit = 0;
+        String out = "";
+        String outO = "Linux";
+        switch (Utilities.findCurrentOS()) {
+        case Utilities.OS_WINDOWS:
+            outO = "Windows";
+	        break;
+        case Utilities.OS_OSX:
+        case Utilities.OS_LINUX:
+            outO = "Linux";
+            break;
+        }
+        String outP = "PhyML";
+        String outF = "PHYLIP";
+        boolean lower = false;
+        boolean numbers = false;
+        boolean sequential = false;
+        boolean match = false;
+
+        //Get converter and convert MSA
+        Factory factory = new DefaultFactory();
+        Converter converter;
+
+		PrintStream outPS = System.err;
+		System.setErr(new PrintStream(new NullPrintStream()));
+        try {
+            converter = factory.getConverter(inO, inP, inF, autodetect,
+                    collapse, gaps, missing, limit,
+                    outO, outP, outF, lower, numbers, sequential, match, "ModelTestService");
+            out = converter.convert(in);
+        } catch (UnsupportedOperationException ex) {
+            throw new AlignmentParseException("There's some error in your data: " + ex.getMessage());
+        } catch (ParseException ex) {
+            throw new AlignmentParseException("There's some error in your data: " + ex.getMessage());
+        }
+        System.setErr(outPS);
+        
+        if (outputFile.exists()) {
+        	outputFile.delete();
+        }
+        outputFile.createNewFile();
+        if (deleteOnExit) {
+        	outputFile.deleteOnExit();
+        }
+        	
+        FileWriter fw = new FileWriter(outputFile);
+        fw.write(out);
+        fw.close();
+        
+        return out;
+    }
+    
+	public InformationCriterion doIC(int ic, boolean writePAUPblock, boolean doImportances,
+			boolean doModelAveraging, double confidenceInterval) {
+		InformationCriterion criterion;
+		switch (ic) {
+		case InformationCriterion.IC_AIC:
+			criterion = new AIC(writePAUPblock, doImportances,
+					doModelAveraging, confidenceInterval);
+			break;
+		case InformationCriterion.IC_AICc:
+			criterion = new AICc(writePAUPblock, doImportances,
+					doModelAveraging, confidenceInterval);
+			break;
+		case InformationCriterion.IC_BIC:
+			criterion = new BIC(writePAUPblock, doImportances,
+					doModelAveraging, confidenceInterval);
+			break;
+		case InformationCriterion.IC_DT:
+			criterion = new DT(writePAUPblock, doImportances, doModelAveraging,
+					confidenceInterval);
+			break;
+		default:
+			throw new InvalidArgumentException.UnexistentCriterionException(ic);
+		}
+		criterion.compute();
+		
+		return criterion;
+	}
+	
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/WeakStateException.java b/src/main/java/es/uvigo/darwin/jmodeltest/WeakStateException.java
new file mode 100644
index 0000000..399575f
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/WeakStateException.java
@@ -0,0 +1,37 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest;
+
+public class WeakStateException extends RuntimeException {
+
+	private static final long serialVersionUID = 201104031313L;
+
+	public WeakStateException(String message) {
+		super(message);
+	}
+	
+	public static class UninitializedCriterionException extends WeakStateException {
+	
+		private static final long serialVersionUID = 201104031313L;
+		
+		public UninitializedCriterionException(String criterion) {
+			super("Attempting to get an uninitialized criterion: " + criterion); 
+			}
+
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exception/AlignmentParseException.java b/src/main/java/es/uvigo/darwin/jmodeltest/exception/AlignmentParseException.java
new file mode 100755
index 0000000..41914e8
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exception/AlignmentParseException.java
@@ -0,0 +1,46 @@
+/*
+Copyright (C) 2009  Diego Darriba
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.exception;
+
+/**
+ * The Class AlignmentParseException.
+ * 
+ * @author Diego Darriba
+ */
+public class AlignmentParseException extends CheckedException {
+
+    private static final String MESSAGE = "Alignment parse exception";
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 20090728L;
+
+    /**
+     * Instantiates a new alignment format exception.
+     */
+    public AlignmentParseException() {
+        super(MESSAGE);
+    }
+
+    /**
+     * Instantiates a new alignment format exception.
+     * 
+     * @param description the description
+     */
+    public AlignmentParseException(String description) {
+        super(MESSAGE + ": " + description);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exception/CheckedException.java b/src/main/java/es/uvigo/darwin/jmodeltest/exception/CheckedException.java
new file mode 100755
index 0000000..50e7020
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exception/CheckedException.java
@@ -0,0 +1,42 @@
+/*
+Copyright (C) 2009  Diego Darriba
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.exception;
+
+/**
+ *
+ * @author Diego Darriba
+ */
+public class CheckedException extends Exception {
+
+    /** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 20100525L;
+
+	/**
+	 * Instantiates a new prot test internal exception.
+	 */
+	public CheckedException() {}
+	
+	/**
+	 * Instantiates a new prot test internal exception.
+	 * 
+	 * @param description the description
+	 */
+	public CheckedException(String description) {
+		super(description);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exception/InputFileException.java b/src/main/java/es/uvigo/darwin/jmodeltest/exception/InputFileException.java
new file mode 100644
index 0000000..4b7419c
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exception/InputFileException.java
@@ -0,0 +1,24 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.exception;
+
+public class InputFileException extends Exception {
+
+	private static final long serialVersionUID = 4030123395227777873L;
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exception/InternalException.java b/src/main/java/es/uvigo/darwin/jmodeltest/exception/InternalException.java
new file mode 100755
index 0000000..cef9583
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exception/InternalException.java
@@ -0,0 +1,44 @@
+/*
+Copyright (C) 2009  Diego Darriba
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.exception;
+
+/**
+ * The Class ProtTestInternalException.
+ * 
+ * @author Diego Darriba López
+ */
+public class InternalException extends RuntimeException {
+
+	/** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 20090728L;
+
+	/**
+	 * Instantiates a new prot test internal exception.
+	 */
+	public InternalException() {}
+	
+	/**
+	 * Instantiates a new prot test internal exception.
+	 * 
+	 * @param description the description
+	 */
+	public InternalException(String description) {
+		super(description);
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/Distributor.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/Distributor.java
new file mode 100644
index 0000000..0a837d5
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/Distributor.java
@@ -0,0 +1,231 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Observable;
+
+import javax.management.RuntimeErrorException;
+
+import mpi.MPI;
+import mpi.Request;
+import mpi.Status;
+import es.uvigo.darwin.jmodeltest.exception.InternalException;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class Distributor extends Observable implements Runnable {
+
+	/** MPJ Tag for requesting a new model. */
+	public static final int TAG_SEND_REQUEST = 1;
+
+	/** MPJ Tag for sending a new model. */
+	public static final int TAG_SEND_MODEL = 2;
+
+	private List<Model> models;
+	private RunPhymlMPJ caller;
+	/** MPJ Rank of the processor. */
+	private int mpjMe;
+
+	/** MPJ Size of the communicator. */
+	private int mpjSize;
+
+	/**
+	 * The number of models per processor. It will be necessary by the root
+	 * process to do the non-uniform gathering
+	 */
+	private int[] itemsPerProc;
+
+	/**
+	 * The array of displacements after the distribution. It will be necessary
+	 * by the root process to do the non-uniform gathering
+	 */
+	private int[] displs;
+
+	public Distributor(List<Model> models, RunPhymlMPJ caller, int mpjMe,
+			int mpjSize) {
+		this.mpjMe = mpjMe;
+		this.mpjSize = mpjSize;
+		this.models = models;
+		this.caller = caller;
+		this.itemsPerProc = new int[mpjSize];
+		this.displs = new int[mpjSize];
+
+		Collections.sort(this.models, new ModelComparator());
+	}
+
+	public void distribute(List<Model> models) throws InterruptedException {
+		int index = 0;
+		for (Model model : models) {
+			// check root processor
+			//
+			// This strategy is an easy way to avoid the problem of
+			// thread-safety in MPJ-Express. It works correctly, but
+			// it also causes to introduce coupling between this class
+			// and RunPhymlMPJ having to define two volatile attributes:
+			// rootModelRequest and rootModel.
+			if (caller.rootModelRequest || mpjSize == 1) {
+				while (!caller.rootModelRequest) {
+					try {
+						Thread.sleep(200);
+					} catch (InterruptedException e) {
+						throw new InternalException(
+								"Thread interrupted");
+					}
+				}
+				if (caller.rootModel != null) {
+					// finalized model optimization
+					notifyObservers(ProgressInfo.SINGLE_OPTIMIZATION_COMPLETED,
+							index, caller.rootModel,
+							Utilities.displayRuntime(caller.rootModel
+									.getComputationTime()));
+				}
+				notifyObservers(ProgressInfo.SINGLE_OPTIMIZATION_INIT, index,
+						model, null);
+
+				caller.rootModel = model;
+				caller.rootModelRequest = false;
+				itemsPerProc[mpjMe]++;
+			} else {
+				Model[] computedModel = new Model[1];
+				// getModel request
+				Request modelRequest = MPI.COMM_WORLD.Irecv(computedModel, 0,
+						1, MPI.OBJECT, MPI.ANY_SOURCE, TAG_SEND_REQUEST);
+				// prepare model
+				Model[] modelToSend = new Model[1];
+				modelToSend[0] = model;
+				// wait for request
+				Status requestStatus = modelRequest.Wait();
+				if (computedModel[0] != null) {
+					// finalized model optimization
+					int recvIndex = models.indexOf(computedModel[0]);
+					notifyObservers(ProgressInfo.SINGLE_OPTIMIZATION_COMPLETED,
+							index, computedModel[0],
+							Utilities.displayRuntime(computedModel[0]
+									.getComputationTime()));
+					models.set(recvIndex, computedModel[0]);
+				}
+				// send model
+				Request modelSend = MPI.COMM_WORLD.Isend(modelToSend, 0, 1,
+						MPI.OBJECT, requestStatus.source, TAG_SEND_MODEL);
+				notifyObservers(ProgressInfo.SINGLE_OPTIMIZATION_INIT, index,
+						model, null);
+				// update structures
+				itemsPerProc[requestStatus.source]++;
+				// wait for send
+				modelSend.Wait();
+			}
+			index++;
+		}
+		displs[0] = 0;
+		for (int i = 1; i < mpjSize; i++)
+			displs[i] = displs[i - 1] + itemsPerProc[i - 1];
+
+		// finalize
+		for (int i = 1; i < mpjSize; i++) {
+			Model[] computedModel = new Model[1];
+			// getModel request
+			Request modelRequest = MPI.COMM_WORLD.Irecv(computedModel, 0, 1,
+					MPI.OBJECT, MPI.ANY_SOURCE, TAG_SEND_REQUEST);
+			Model[] modelToSend = { null };
+			// wait for request
+			Status requestStatus = modelRequest.Wait();
+			if (computedModel[0] != null) {
+				int recvIndex = models.indexOf(computedModel[0]);
+				notifyObservers(ProgressInfo.SINGLE_OPTIMIZATION_COMPLETED,
+						index, computedModel[0],
+						Utilities.displayRuntime(computedModel[0]
+								.getComputationTime()));
+				models.set(recvIndex, computedModel[0]);
+			}
+			// send null model
+			Request modelSend = MPI.COMM_WORLD.Isend(modelToSend, 0, 1,
+					MPI.OBJECT, requestStatus.source, TAG_SEND_MODEL);
+
+			modelSend.Wait();
+		}
+		// check root
+		while (!caller.rootModelRequest) {
+			try {
+				Thread.sleep(200);
+			} catch (InterruptedException e) {
+				throw e;
+			}
+		}
+		if (caller.rootModel != null) {
+			notifyObservers(ProgressInfo.SINGLE_OPTIMIZATION_COMPLETED, index,
+					caller.rootModel, Utilities.displayRuntime(caller.rootModel
+							.getComputationTime()));
+		}
+		caller.rootModel = null;
+		caller.rootModelRequest = false;
+	}
+
+	public int[] getItemsPerProc() {
+		return itemsPerProc;
+	}
+
+	public int[] getDispls() {
+		return displs;
+	}
+
+	@Override
+	public void run() {
+		try {
+			distribute(models);
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+			throw new RuntimeErrorException(new Error(e));
+		}
+	}
+
+	private class ModelComparator implements Comparator<Model> {
+
+		/*
+		 * (non-Javadoc)
+		 * 
+		 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+		 */
+		public int compare(Model model1, Model model2) {
+			int value = 0;
+			if (model1 != null && model2 != null)
+				value = getWeight(model2) - getWeight(model1);
+			return value;
+		}
+
+		private int getWeight(Model model) {
+			int weight = 0;
+			if (model.ispG())
+				weight += 4;
+			if (model.ispI())
+				weight += 2;
+			if (model.ispF())
+				weight += 1;
+			return weight;
+		}
+	}
+
+	private void notifyObservers(int type, int value, Model model,
+			String message) {
+		setChanged();
+		notifyObservers(new ProgressInfo(type, value, model, message));
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/GuidedSearchManager.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/GuidedSearchManager.java
new file mode 100644
index 0000000..6215bd8
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/GuidedSearchManager.java
@@ -0,0 +1,274 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.model.ModelConstants;
+
+public class GuidedSearchManager {
+
+	private static final int RATE_PAIRS = 15;
+	private static final int RATES = 6;
+	private static final double MIN_GAMMA_FILTER = 50.0;
+	private static final double MAX_INV_FILTER = 0.1;
+	private static final double MIN_GAMMA_INV_FILTER = 0.5;
+
+	private static double GVALUE = 0;
+	private static double Y0 = 4;
+	private static double X1 = 150;
+
+	private double guidedSearchThreshold;
+	private Model gtrModel;
+	private boolean doFilterFrequencies;
+	private boolean doFilterRateMatrix;
+	private boolean doFilterRateVariation;
+	private boolean invFilter = false;
+	private boolean gammaFilter = false;
+	private boolean gammaInvFilter = false;
+	private boolean freqsFilter = false;	
+	private boolean ratesFilter[] = new boolean[RATE_PAIRS];
+
+
+	static {
+		
+	}
+
+	public GuidedSearchManager(double guidedSearchThreshold, Model gtrModel,
+			boolean filterFrequencies, boolean filterRateMatrix,
+			boolean filterRateVariation) {
+
+		this.guidedSearchThreshold = guidedSearchThreshold;
+		this.gtrModel = gtrModel;
+		this.doFilterFrequencies = filterFrequencies;
+		this.doFilterRateMatrix = filterRateMatrix;
+		this.doFilterRateVariation = filterRateVariation;
+
+		ModelTest.getMainConsole().println("[Heuristic search] Set up model filter...");
+		gtrModel.print(ModelTest.getMainConsole());
+		
+		setUpFilter(this.guidedSearchThreshold, this.gtrModel);
+
+	}
+
+	public Model[] filterModels(Model[] models) {
+
+		ArrayList<Model> modelsArray = new ArrayList<Model>();
+		for (Model model : models) {
+			boolean included = true;
+
+			int rateIndex = 0;
+			for (int i=0; i<5; i++) {
+				for (int j=i+1; j<6; j++) {
+					if (checkRates(model.getPartition(), i, j)
+							&& ratesFilter[rateIndex]) {
+						included = false;
+					}
+					rateIndex++;
+				}
+			}
+
+			if (!model.ispF()) {
+				included &= !freqsFilter;
+			}
+			
+			if (model.ispI()) {
+				if (model.ispG()) {
+					included &= !gammaInvFilter;
+				} else {
+					included &= !invFilter;
+				}
+			} else if (model.ispG()) {
+				included &= !gammaFilter;
+			}
+
+			if (included) {
+				modelsArray.add(model);
+			}
+		}
+
+		if (modelsArray.size() < models.length) {
+			ModelTest.getMainConsole().println("[Heuristic search] Candidate models set reduced to " + modelsArray.size() + " models");
+		} else {
+			ModelTest.getMainConsole().println("[Heuristic search] Candidate models set is not reduced (" + modelsArray.size() + " models)");
+		}
+		
+		return modelsArray.toArray(new Model[0]);
+	}
+	
+	public static String[] getPartitions(String partition, int k) {
+
+		ArrayList<String> partitionsArray = new ArrayList<String>();	
+		if (k>0 && k<6) {
+			boolean equalRates[] = new boolean[] { 
+					checkRates(partition,0,1), checkRates(partition,0,2), checkRates(partition,0,3),
+					checkRates(partition,0,4), checkRates(partition,0,5), checkRates(partition,1,2),
+					checkRates(partition,1,3), checkRates(partition,1,4), checkRates(partition,1,5),
+					checkRates(partition,2,3), checkRates(partition,2,4), checkRates(partition,2,5),
+					checkRates(partition,3,4), checkRates(partition,3,5), checkRates(partition,4,5)};
+			
+			for (String curPartition : ModelConstants.fullModelSet.get(k)) {
+				boolean included = true;
+	
+				int rateIndex = 0;
+				for (int i=0; i<5; i++) {
+					for (int j=i+1; j<6; j++) {
+						if (equalRates[rateIndex] && !checkRates(curPartition, i, j)) {
+							included = false;
+							break;
+						}
+						rateIndex++;
+					}
+				}
+	
+				if (included) {
+					partitionsArray.add(curPartition);
+				}
+			}
+		} else {
+			return new String[]{"012345"};
+		}
+
+		return partitionsArray.toArray(new String[0]);
+	}
+	
+	public static Model[] getModelsSubset(Model[] models, String partition, int k) {
+
+		ArrayList<Model> modelsArray = new ArrayList<Model>();
+		for (String curPartition : getPartitions(partition, k)) {
+			for (Model model : models) {
+				if (model.getPartition().equals(curPartition)) {
+					modelsArray.add(model);
+				}
+			}
+		}
+		if (k < 6) {
+			ModelTest.getMainConsole().println("[Clustering search] Obtain next step models from partition " + partition + "...");
+		}
+		ModelTest.getMainConsole().println("[Clustering search] Step " + (7-k) + "/6: " + modelsArray.size() + " models.");
+		
+		return modelsArray.toArray(new Model[0]);
+	}
+
+	private static boolean checkRates(String partition, int p0, int p1) {
+		return partition.charAt(p0) == partition.charAt(p1);
+	}
+	
+	private void setUpFilter(double guidedSearchThreshold,
+			Model gtrModel) {
+
+		double threshold = adjustThreshold(guidedSearchThreshold,
+				gtrModel.getLnL());
+
+		double mean = (gtrModel.getRa() + gtrModel.getRb() + gtrModel.getRc()
+				+ gtrModel.getRd() + gtrModel.getRe() + gtrModel.getRf())
+				/ RATES;
+		double variance = ((gtrModel.getRa() * gtrModel.getRa()
+				+ gtrModel.getRb() * gtrModel.getRb() + gtrModel.getRc()
+				* gtrModel.getRc() + gtrModel.getRd() * gtrModel.getRd()
+				+ gtrModel.getRe() * gtrModel.getRe() + gtrModel.getRf()
+				* gtrModel.getRf()) / RATES)
+				- mean * mean;
+		boolean hasVar = variance > 1;
+		// if (variance > 1) {
+		double normalizedRates[] = new double[] {
+				(gtrModel.getRa() - mean) / variance,
+				(gtrModel.getRb() - mean) / variance,
+				(gtrModel.getRc() - mean) / variance,
+				(gtrModel.getRd() - mean) / variance,
+				(gtrModel.getRe() - mean) / variance,
+				(gtrModel.getRf() - mean) / variance };
+
+		double rate[] = new double[RATE_PAIRS];
+		int ratePairIndex = 0;
+		for (int i = 0; i < (RATES - 1); i++) {
+			for (int j = i + 1; j < RATES; j++) {
+				rate[ratePairIndex] = computeRates(normalizedRates[i],
+						normalizedRates[j]);
+				ratePairIndex++;
+			}
+		}
+
+		if (doFilterFrequencies) {
+			if (computeFreqs(new double[] { gtrModel.getfA(),
+						gtrModel.getfC(), gtrModel.getfG(), gtrModel.getfT() }) < (1 - threshold)) {
+				ModelTest.getMainConsole().println("[Heuristic search] Filtering models with equal frequencies");
+				freqsFilter = true;
+			} else {
+				freqsFilter = false;
+			}
+		} else {
+			freqsFilter = false;
+		}
+
+		if (doFilterRateMatrix) {
+			boolean doRatesFilter = false;
+			for (int k = 0; k < RATE_PAIRS; k++) {
+				ratesFilter[k] = (rate[k] > threshold && hasVar);
+				doRatesFilter |= ratesFilter[k];
+			}
+			if (doRatesFilter) {
+				ModelTest.getMainConsole().println("[Heuristic search] Filtering models with certain equal rates");
+			}
+		}
+
+		gammaFilter = doFilterRateVariation
+				&& gtrModel.getShape() > MIN_GAMMA_FILTER;
+		invFilter = doFilterRateVariation
+				&& (gtrModel.getPinv() < MAX_INV_FILTER && gtrModel.getShape() > MIN_GAMMA_INV_FILTER);
+		gammaInvFilter = doFilterRateVariation
+				&& (gtrModel.getShape() > MIN_GAMMA_FILTER && gtrModel
+						.getPinv() < MAX_INV_FILTER);
+		if (invFilter) {
+			ModelTest.getMainConsole().println("[Heuristic search] Filtering +I models");
+		}
+		if (gammaFilter) {
+			ModelTest.getMainConsole().println("[Heuristic search] Filtering +G models");
+		}
+		if (gammaInvFilter) {
+			ModelTest.getMainConsole().println("[Heuristic search] Filtering +I+G models");
+		}
+	}
+
+	private static double computeRates(double rate1, double rate2) {
+		// return Math.abs(Math.min(rate1, rate2) / (rate1+rate2));
+		return Math.abs(rate1 - rate2);
+	}
+
+	private static double computeFreqs(double[] freqs) {
+		Arrays.sort(freqs);
+		return Math.abs(freqs[0] / freqs[3]);
+	}
+
+	private static double adjustThreshold(double threshold, double lk) {
+		if (lk > (X1 * 1000))
+			return threshold;
+		return adjustThresholdLog(threshold, lk);
+	}
+
+	private static double adjustThresholdLog(double threshold, double lk) {
+		double value = ((1 - Y0) * Math.log(GVALUE + lk / 1000 + 1) + Y0
+				* Math.log(GVALUE + X1 + 1) - Math.log(GVALUE + 1))
+				/ (Math.log(GVALUE + X1 + 1) - Math.log(GVALUE + 1));
+		return threshold * value;
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/MultipleDistributor.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/MultipleDistributor.java
new file mode 100644
index 0000000..a6cd081
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/MultipleDistributor.java
@@ -0,0 +1,316 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Observable;
+
+import javax.management.RuntimeErrorException;
+
+import mpi.MPI;
+import mpi.Request;
+import mpi.Status;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.ModelTestConfiguration;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.model.ModelComparator;
+import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
+
+public class MultipleDistributor extends Observable implements Runnable {
+
+	public static final int BIG = 999;
+	public static final int DEFAULT_PROCESSORS_IG = 4;
+	public static final int DEFAULT_PROCESSORS_I = 2;
+	public static final int DEFAULT_PROCESSORS_UNIFORM = 1;
+	public static int PROCESSORS_IG;
+	public static int PROCESSORS_I;
+	public static int PROCESSORS_UNIFORM;
+
+	/** MPJ Tag for requesting a new model. */
+	public static final int TAG_SEND_REQUEST = 1;
+
+	/** MPJ Tag for sending a new model. */
+	public static final int TAG_SEND_MODEL = 2;
+
+	public static final int TAG_EXIST_MORE_MODELS = 3;
+
+	private List<Model> modelsToSend;
+	private RunPhymlHybrid caller;
+
+	private static boolean assumeHyperThreading;
+	private static boolean homogeneousDistribution;
+
+	/** MPJ Rank of the processor. */
+	private int mpjMe;
+
+	/** MPJ Size of the communicator. */
+	private int mpjSize;
+
+	private static int numberOfHosts;
+	private static int totalNumberOfThreads = 0;
+	private static int minProcs = BIG;
+	private static int maxProcs = 0;
+	private static float avgProcs;
+
+	/**
+	 * The number of models per processor. It will be necessary by the root
+	 * process to do the non-uniform gathering
+	 */
+	private int[] itemsPerProc;
+
+	/**
+	 * The array of displacements after the distribution. It will be necessary
+	 * by the root process to do the non-uniform gathering
+	 */
+	private int[] displs;
+
+	static {
+		String gammaThreadsStr = ModelTestConfiguration
+				.getProperty(ModelTestConfiguration.G_THREADS);
+		String invThreadsStr = ModelTestConfiguration
+				.getProperty(ModelTestConfiguration.I_THREADS);
+		String uniformThreadsStr = ModelTestConfiguration
+				.getProperty(ModelTestConfiguration.U_THREADS);
+		try {
+			PROCESSORS_IG = Integer
+					.parseInt(gammaThreadsStr != null ? gammaThreadsStr
+							: String.valueOf(DEFAULT_PROCESSORS_IG));
+			PROCESSORS_I = Integer
+					.parseInt(invThreadsStr != null ? invThreadsStr : String
+							.valueOf(DEFAULT_PROCESSORS_I));
+			PROCESSORS_UNIFORM = Integer
+					.parseInt(uniformThreadsStr != null ? uniformThreadsStr
+							: String.valueOf(DEFAULT_PROCESSORS_UNIFORM));
+		} catch (NumberFormatException e) {
+			PROCESSORS_IG = DEFAULT_PROCESSORS_IG;
+			PROCESSORS_I = DEFAULT_PROCESSORS_I;
+			PROCESSORS_UNIFORM = DEFAULT_PROCESSORS_UNIFORM;
+		}
+	}
+
+	public MultipleDistributor(List<Model> models, RunPhymlHybrid caller,
+			int mpjMe, int mpjSize) {
+		this.mpjMe = mpjMe;
+		this.mpjSize = mpjSize;
+		this.modelsToSend = new ArrayList<Model>(models);
+		this.caller = caller;
+		this.itemsPerProc = new int[mpjSize];
+		this.displs = new int[mpjSize];
+
+		if (ModelTest.HOSTS_TABLE != null) {
+			numberOfHosts = ModelTest.HOSTS_TABLE.size();
+			Enumeration<Integer> procsPerHost = ModelTest.HOSTS_TABLE
+					.elements();
+			while (procsPerHost.hasMoreElements()) {
+				int procs = procsPerHost.nextElement();
+				totalNumberOfThreads += procs;
+				if (procs < minProcs)
+					minProcs = procs;
+				if (procs > maxProcs)
+					maxProcs = procs;
+			}
+			homogeneousDistribution = (minProcs == maxProcs);
+			assumeHyperThreading = (maxProcs > 8);
+			avgProcs = totalNumberOfThreads / numberOfHosts;
+		} else {
+			homogeneousDistribution = true;
+			assumeHyperThreading = false;
+			avgProcs = 1;
+		}
+
+		Collections.sort(this.modelsToSend, new ModelComparator());
+	}
+
+	public void distribute(List<Model> models) throws InterruptedException {
+		itemsPerProc = new int[mpjSize];
+		Status requestStatus = null;
+		displs = new int[mpjSize];
+		int[] freePEs = new int[2];
+		boolean sended = true;
+
+		Request modelRequest = null;
+		while (!modelsToSend.isEmpty()) {
+			// check root processor
+			//
+			// This strategy is an easy way to avoid the problem of
+			// thread-safety
+			// in MPJ-Express. It works correctly, but it also causes to
+			// introduce
+			// coupling between this class and
+			// ImprovedDynamicDistributionStrategy,
+			// having to define two public attributes: rootModelRequest and
+			// rootModel.
+			//
+			if (caller.rootModelRequest && caller.availablePEs > 0) {
+				// if (caller.rootModel != null) {
+				// caller.setCheckpoint(modelSet);
+				// }
+				Model rootModel = getNextModel(caller.availablePEs,
+						caller.maxPEs);
+				if (rootModel != null) {
+					caller.rootModel = rootModel;
+					caller.rootModelRequest = false;
+					itemsPerProc[mpjMe]++;
+				}
+			} else {
+				// getModel request
+				if (sended) {
+					modelRequest = MPI.COMM_WORLD.Irecv(freePEs, 0, 2, MPI.INT,
+							MPI.ANY_SOURCE, TAG_SEND_REQUEST);
+					// wait for request
+					sended = false;
+				}
+				requestStatus = modelRequest.Test();
+				if (requestStatus != null) {
+					Request notifySend = MPI.COMM_WORLD.Isend(
+							new boolean[] { true }, 0, 1, MPI.BOOLEAN,
+							requestStatus.source, TAG_EXIST_MORE_MODELS);
+
+					// prepare model
+					Model[] modelToSend = new Model[1];
+
+					notifySend.Wait();
+
+					modelToSend[0] = getNextModel(freePEs[0], freePEs[1]);
+					Request modelSend = MPI.COMM_WORLD.Isend(modelToSend, 0, 1,
+							MPI.OBJECT, requestStatus.source, TAG_SEND_MODEL);
+
+					if (modelToSend[0] != null) {
+						// update structures
+						itemsPerProc[requestStatus.source]++;
+					}
+
+					// wait for send
+					modelSend.Wait();
+					sended = true;
+
+					requestStatus = null;
+
+				}
+				try {
+					Thread.sleep(200);
+				} catch (InterruptedException e) {
+					e.printStackTrace();
+					// throw new
+					// ProtTestInternalException("Thread interrupted");
+				}
+
+			}
+		}
+
+		displs[0] = 0;
+		for (int i = 1; i < mpjSize; i++) {
+			displs[i] = displs[i - 1] + itemsPerProc[i - 1];
+		}
+
+		// finalize
+		// check root
+		while (!caller.rootModelRequest) {
+			try {
+				Thread.sleep(200);
+			} catch (InterruptedException e) {
+				e.printStackTrace();
+				// throw new ProtTestInternalException("Thread interrupted");
+			}
+		}
+		caller.rootModel = null;
+		caller.rootModelRequest = false;
+
+		for (int i = 1; i < mpjSize; i++) {
+			// getModel request
+			modelRequest = MPI.COMM_WORLD.Irecv(freePEs, 0, 2, MPI.INT,
+					MPI.ANY_SOURCE, TAG_SEND_REQUEST);
+			// wait for request
+			requestStatus = modelRequest.Wait();
+			// send null model
+			Request notifySend = MPI.COMM_WORLD.Isend(new boolean[] { false },
+					0, 1, MPI.BOOLEAN, requestStatus.source,
+					TAG_EXIST_MORE_MODELS);
+			notifySend.Wait();
+
+		}
+	}
+
+	public int[] getItemsPerProc() {
+		return itemsPerProc;
+	}
+
+	public int[] getDispls() {
+		return displs;
+	}
+
+	@Override
+	public void run() {
+		try {
+			distribute(modelsToSend);
+		} catch (InterruptedException e) {
+			e.printStackTrace();
+			throw new RuntimeErrorException(new Error(e));
+		}
+	}
+
+	private Model getNextModel(int numPEs, int maxAvailableThreads) {
+		Model nextModel = null;
+		for (Model model : modelsToSend) {
+			if (getPEs(model, maxAvailableThreads) <= numPEs) {
+				// try to exclude +G models
+				if (homogeneousDistribution || maxAvailableThreads >= avgProcs) {
+					nextModel = model;
+					break;
+				}
+			}
+		}
+		if (nextModel == null && !homogeneousDistribution
+				&& maxAvailableThreads < avgProcs && !modelsToSend.isEmpty()) {
+			// find another one
+			for (Model model : modelsToSend) {
+				if (getPEs(model, maxAvailableThreads) <= numPEs) {
+					nextModel = model;
+					break;
+				}
+			}
+		}
+		modelsToSend.remove(nextModel);
+		return nextModel;
+	}
+
+	public static int getPEs(Model model, int maxAvailableThreads) {
+		int numberOfThreads;
+		if (model.ispG()) {
+			numberOfThreads = PROCESSORS_IG;
+		} else if (model.ispI()) {
+			numberOfThreads = PROCESSORS_I;
+		} else {
+			numberOfThreads = PROCESSORS_UNIFORM;
+		}
+		if (assumeHyperThreading && maxAvailableThreads > 8) {
+			numberOfThreads *= 2;
+		}
+		return Math.min(maxAvailableThreads, numberOfThreads);
+	}
+
+	@SuppressWarnings("unused")
+	private void notifyObservers(int type, int value, Model model,
+			String message) {
+		setChanged();
+		notifyObservers(new ProgressInfo(type, value, model, message));
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/PhymlParallelModel.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/PhymlParallelModel.java
new file mode 100644
index 0000000..ff1be3c
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/PhymlParallelModel.java
@@ -0,0 +1,118 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
+
+public class PhymlParallelModel extends Observable implements Observer {
+
+	    /** The runtime **/
+	    private Runtime runtime = Runtime.getRuntime();
+	    /** The size of parallel tasks **/
+	    private int maxNumberOfTasks;
+	    /** The list of model estimators **/
+	    private List<PhymlSingleModel> estimatorList;
+	    /** The pool of threads **/
+	    private ExecutorService threadPool;
+	    /** Collection of callable objects (tasks) **/
+	    private Collection<Callable<Object>> c = new ArrayList<Callable<Object>>();
+
+	    /**
+	     * Instantiates a new PhymlParallelModel with no models to optimize. 
+	     * The size of the thread pool is equal to the number of available cores in the machine.
+	     * 
+	     * @param alignment the common alignment of the models
+	     */
+	    public PhymlParallelModel() {
+
+	        this(-1);
+
+	    }
+
+	    /**
+	     * Instantiates a new PhymlParallelModel with no models to optimize and
+	     * a fixed size of the thread pool
+	     *
+	     * @param availableThreads the size of the thread pool 
+	     * @param alignment the common alignment of the models
+	     */
+	    public PhymlParallelModel(int availableThreads) {
+
+	        if (availableThreads < 0) {
+	            availableThreads = runtime.availableProcessors();
+	        }
+	        this.maxNumberOfTasks = availableThreads;
+	        this.estimatorList = new ArrayList<PhymlSingleModel>(maxNumberOfTasks);
+	        this.threadPool = Executors.newFixedThreadPool(maxNumberOfTasks);
+	    }
+
+
+	    /**
+	     * Executes the model optimization
+	     * 
+	     * @param estimator the model estimator to execute
+	     * 
+	     * @return if succesfully added the task
+	     */
+	    public boolean execute(PhymlSingleModel estimator) {
+	        estimator.addObserver(this);
+
+	        boolean added = estimatorList.add(estimator);
+	        c.add(Executors.callable(estimator));
+
+			threadPool.execute(estimator);
+
+	        return added;
+	    }
+
+	    protected void notifyObservers(int type, int value, Model model,
+				String message) {
+			setChanged();
+			notifyObservers(new ProgressInfo(type, value, model, message));
+		}
+
+		@Override
+		public void update(Observable o, Object arg) {
+			setChanged();
+			notifyObservers(arg);
+		}
+
+	    /**
+	     * Checks if exist more tasks in the task queue
+	     * 
+	     * @return true, if exist more tasks to execute
+	     */
+	    public boolean hasMoreTasks() {
+	        for (PhymlSingleModel estimator : estimatorList) {
+	            if (estimator.getModel().getTree() == null) {
+	                return true;
+	            }
+	        }
+	        return false;
+	    }
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/PhymlSingleModel.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/PhymlSingleModel.java
new file mode 100644
index 0000000..610afc4
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/PhymlSingleModel.java
@@ -0,0 +1,542 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.util.Observable;
+
+import javax.sql.rowset.spi.SyncResolver;
+
+import pal.tree.TreeParseException;
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.ModelTestConfiguration;
+import es.uvigo.darwin.jmodeltest.io.TextInputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class PhymlSingleModel extends Observable implements Runnable {
+
+	private int verbose = 0;
+
+	private String phymlStatFileName;
+	private String phymlTreeFileName;
+
+	private Model model;
+	private long startTime, endTime;
+	private String commandLine;
+	private int index;
+	private boolean justGetJCTree = false;
+	private boolean ignoreGaps = false;
+	private boolean interrupted = false;
+	private ApplicationOptions options;
+	private int numberOfThreads = -1;
+	
+	public Model getModel() {
+		return model;
+	}
+
+	public PhymlSingleModel(Model model, int index, boolean justGetJCTree,
+			boolean ignoreGaps, ApplicationOptions options) {
+		this.options = options;
+		this.model = model;
+		this.index = index;
+		this.justGetJCTree = justGetJCTree;
+		this.ignoreGaps = ignoreGaps;
+		
+		this.phymlStatFileName = options.getAlignmentFile().getAbsolutePath()
+				+ RunPhyml.PHYML_STATS_SUFFIX + model.getName() + ".txt";
+		this.phymlTreeFileName = options.getAlignmentFile().getAbsolutePath()
+				+ RunPhyml.PHYML_TREE_SUFFIX + model.getName() + ".txt";
+	}
+
+	public PhymlSingleModel(Model model, int index, boolean justGetJCTree,
+			ApplicationOptions options, int numberOfThreads) {
+		this(model, index, justGetJCTree, false, options);
+		this.numberOfThreads = numberOfThreads;
+	}
+
+	public boolean compute() {
+		notifyObservers(ProgressInfo.SINGLE_OPTIMIZATION_INIT, index,
+				model, null);
+		if (model.getLnL() < 1e-5 || ignoreGaps) {
+			// run phyml
+			startTime = System.currentTimeMillis();
+
+			commandLine = writePhyml3CommandLine(model, justGetJCTree, options,
+					ignoreGaps, numberOfThreads);
+			executeCommandLine();
+			
+			if (!interrupted) {
+				parsePhyml3Files(model);
+			}
+
+			endTime = System.currentTimeMillis();
+
+			model.setComputationTime(endTime - startTime);
+		}
+		// completed
+		if (!interrupted) {
+			int value = 0;
+			if (ignoreGaps) {
+				value = ProgressInfo.VALUE_IGAPS_OPTIMIZATION;
+			} else {
+				value = ProgressInfo.VALUE_REGULAR_OPTIMIZATION;
+			}
+			notifyObservers(ProgressInfo.SINGLE_OPTIMIZATION_COMPLETED,
+					value, model,
+					Utilities.calculateRuntime(startTime, endTime));
+
+		}
+		return !interrupted;
+	}
+
+	@Override
+	public void run() {
+		compute();
+	}
+
+	/************************
+	 * writePhym3lCommandLine 
+	 ************************
+	 * Builds up the command
+	 * line for Phyml3
+	 ************************/
+	public static String writePhyml3CommandLine(Model currentModel,
+			boolean justGetJCtree, ApplicationOptions options,
+			boolean ignoreGaps, int numberOfThreads) {
+
+		StringBuilder sb = new StringBuilder();
+
+		// input file
+		sb.append(" -i ").append(options.getAlignmentFile().getAbsolutePath());
+
+		// data type is nucleotide
+		sb.append(" -d nt");
+
+		// number of data sets
+		sb.append(" -n 1");
+
+		// no bootrstrap or aLRT
+		sb.append(" -b 0");
+
+		if (ignoreGaps) {
+			sb.append(" --no_gap");
+		}
+		// set execution id
+		sb.append(" --run_id ").append(currentModel.getName());
+
+		// set custom model
+		sb.append(" -m ").append(currentModel.getPartition());
+
+		// optimize base frequencies if needed
+		if (currentModel.ispF())
+			sb.append(" -f m"); // changed from -f e DP200509
+		else
+			sb.append(" -f 0.25,0.25,0.25,0.25");
+
+		// optimize pinvar if needed
+		if (currentModel.ispI())
+			sb.append(" -v e");
+
+		// optimize alpha if needed
+		if (currentModel.ispG()) {
+			sb.append(" -c ").append(options.numGammaCat);
+			sb.append(" -a e");
+		} else
+			sb.append(" -c 1");
+
+		// threaded version
+		if (numberOfThreads > 0) {
+			sb.append(" --num_threads ").append(numberOfThreads);
+		}
+
+		// avoid memory warning
+		sb.append(" --no_memory_check");
+
+		/*
+		 * params=tlr: tree topology (t), branch length (l) and substitution
+		 * rate parameters (r) are optimised. params = tlr or tl: optimize tree
+		 * topology and branch lengths params = lr or l: tree topology fixed;
+		 * optimize branch lengths; params = r or none: both tree topology and
+		 * branch lengths are fixed.
+		 */
+		if (justGetJCtree) {
+			// tree topology is fixed.
+			sb.append(" -o lr");
+		} else if (options.userTopologyExists || options.fixedTopology) {
+			// use a single tree for all models
+			sb.append(" -u ").append(options.getTreeFile().getAbsolutePath());
+			sb.append(" -o lr"); // tree topology fixed; optimize branch lengths
+		} else if (!options.optimizeMLTopology)
+		{
+			// use BIONJ tree for each model
+			sb.append(" -o lr"); // tree topology fixed; optimize branch lengths
+		} else {
+			sb.append(" -o tlr"); // optimize tree topology and branch lengthss
+
+			// search strategy
+			switch (options.treeSearchOperations) {
+			case SPR:
+				sb.append(" -s SPR");
+				break;
+			case BEST:
+				sb.append(" -s BEST");
+				break;
+			default:
+				sb.append(" -s NNI");
+			}
+		}
+
+		return sb.toString();
+	}
+
+	/***************************
+	 * executeCommandLine ************************ * Executes a set of command
+	 * line in the system * * *
+	 ***********************************************************************/
+
+	private void executeCommandLine() {
+		String[] executable = new String[1];
+		try {
+			if (!ModelTestConfiguration.isGlobalPhymlBinary()) {
+				if (!RunPhyml.phymlBinary.exists()) {
+					notifyObservers(
+							ProgressInfo.ERROR_BINARY_NOEXISTS, index, model, RunPhyml.phymlBinary.getAbsolutePath());
+				} else if (!RunPhyml.phymlBinary.canExecute()) {
+					notifyObservers(
+							ProgressInfo.ERROR_BINARY_NOEXECUTE, index, model, RunPhyml.phymlBinary.getAbsolutePath());
+					
+				}
+			}
+			executable[0] = RunPhyml.phymlBinaryStr;
+			
+			String[] tokenizedCommandLine = commandLine.split(" ");
+			String[] cmd = Utilities.specialConcatStringArrays(executable,
+					tokenizedCommandLine);
+
+			// get process and execute command line
+			Runtime rt = Runtime.getRuntime();
+			Process proc = rt.exec(cmd, null, RunPhyml.PHYML_PATH.equals("") ? null
+					: new File(RunPhyml.PHYML_PATH));
+			ProcessManager.getInstance().registerProcess(proc);
+
+			// any error message?
+			StreamGobbler errorGobbler = new StreamGobbler(
+					proc.getErrorStream(), "ERROR", System.err, ModelTest.getPhymlConsole());
+			// any output?
+			FileOutputStream logFile = new FileOutputStream(
+					options.getLogFile(), true);
+			StreamGobbler outputGobbler = new StreamGobbler(
+					proc.getInputStream(), "PHYML", logFile, ModelTest.getPhymlConsole());
+
+			// kick them off
+			errorGobbler.start();
+			outputGobbler.start();
+
+			// any error???
+			int exitVal = proc.waitFor();
+			ProcessManager.getInstance().removeProcess(proc);
+
+			if (verbose > 1)
+				System.out.println("ExitValue: " + exitVal);
+
+			// print command line to phmyl logfile
+			PrintWriter printout = new PrintWriter(logFile);
+			printout.println(" ");
+			printout.println("Command line used for process "+ outputGobbler.getRunId() +":");
+			String uCommand = commandLine.replace(options.getAlignmentFile().getAbsolutePath(), 
+					options.getInputFile().getAbsolutePath());
+			if (options.userTopologyExists) {
+				uCommand = uCommand.replace(options.getTreeFile().getAbsolutePath(), 
+						options.getInputTreeFile().getAbsolutePath());
+			}
+			printout.println("    " + RunPhyml.phymlBinary.getAbsolutePath() + " "
+					+ uCommand);
+			printout.println(" ");
+			printout.flush();
+			printout.close();
+			
+			// print to console
+			if (ModelTest.getPhymlConsole() != null) {
+				synchronized (ModelTest.getPhymlConsole()) {
+					ModelTest.getPhymlConsole().println(" ");
+					ModelTest.getPhymlConsole().println("Command line used for process "+ outputGobbler.getRunId() +":");
+					ModelTest.getPhymlConsole().println("    " + RunPhyml.phymlBinary.getAbsolutePath() + " "
+							+ uCommand);
+					ModelTest.getPhymlConsole().println(" ");
+					ModelTest.getPhymlConsole().flush();
+					ModelTest.getPhymlConsole().close();
+				}
+			}
+
+		} catch (InterruptedException e) {
+			notifyObservers(ProgressInfo.INTERRUPTED, index, model, null);
+			interrupted = true;
+		} catch (Throwable t) {
+			notifyObservers(
+					ProgressInfo.ERROR,
+					index,
+					model,
+					"Cannot run the Phyml command line for some reason: "
+							+ t.getMessage());
+			interrupted = true;
+		}
+
+	}
+
+	/***************************
+	 * parsePhyml3Files ************************** * Reads contents of Phyml3
+	 * output files and loads * models parameter estimates * * *
+	 ***********************************************************************/
+
+	private void parsePhyml3Files(Model currentModel) {
+		String line;
+
+		boolean showParsing = false;
+
+		// Get model likelihood
+		// TextInputStream phymlLkFile = new TextInputStream(phymlLkFileName);
+		// currentModel.lnL = (-1.0) * phymlLkFile.readFloat();
+		// phymlLkFile.close();
+
+		// Get model likelihood and parameter estimates
+		try {
+			TextInputStream phymlStatFile = new TextInputStream(
+					phymlStatFileName);
+			if (ignoreGaps) {
+				while ((line = phymlStatFile.readLine()) != null) {
+					if (line.length() > 0) {
+						if (line.startsWith(". Log-likelihood")) {
+							currentModel.setLnLIgnoringGaps((-1.0)
+									* Double.parseDouble(Utilities
+											.lastToken(line)));
+						} else if (line.contains("Unconstrained likelihood")) {
+							double unconstrainedLnL = (-1.0)
+									* Double.parseDouble(Utilities
+											.lastToken(line));
+							currentModel.setUnconstrainedLnL(unconstrainedLnL);
+							if (Math.abs(options.getUnconstrainedLnL()
+									- unconstrainedLnL) > 1e-10) {
+								// uLK has changed!!!
+								// temporary uLK is updated
+								options.setUnconstrainedLnL(unconstrainedLnL);
+							}
+						}
+					}
+				}
+			} else {
+				while ((line = phymlStatFile.readLine()) != null) {
+					if (line.length() > 0) {
+						if (line.startsWith(". Log-likelihood")) {
+							currentModel.setLnL((-1.0)
+									* Double.parseDouble(Utilities
+											.lastToken(line)));
+							if (showParsing)
+								System.err.println("Reading lnL = "
+										+ currentModel.getLnL());
+						} else if (line.startsWith(". Discrete gamma model")) {
+							if (Utilities.lastToken(line).equals("Yes")) {
+								// currentModel.pG = true;
+								line = phymlStatFile.readLine();
+								currentModel.setNumGammaCat(Integer
+										.parseInt(Utilities.lastToken(line)));
+								if (showParsing)
+									System.err.println("Reading numGammaCat = "
+											+ currentModel.getNumGammaCat());
+								line = phymlStatFile.readLine();
+								currentModel
+										.setShape(Double.parseDouble(Utilities
+												.lastToken(line)));
+								if (showParsing)
+									System.err.println("Reading shape = "
+											+ currentModel.getShape());
+							}
+						} else if (line.startsWith(". Nucleotides frequencies")) {
+							// currentModel.pF = true; ??
+							line = phymlStatFile.readLine();
+							while (line.trim().length() == 0)
+								// get rid of any number of returns
+								line = phymlStatFile.readLine();
+							currentModel.setfA(Double.parseDouble(Utilities
+									.lastToken(line)));
+							line = phymlStatFile.readLine();
+							currentModel.setfC(Double.parseDouble(Utilities
+									.lastToken(line)));
+							line = phymlStatFile.readLine();
+							currentModel.setfG(Double.parseDouble(Utilities
+									.lastToken(line)));
+							line = phymlStatFile.readLine();
+							currentModel.setfT(Double.parseDouble(Utilities
+									.lastToken(line)));
+							if (showParsing) {
+								System.err.println("Reading fA = "
+										+ currentModel.getfA());
+								System.err.println("Reading fC = "
+										+ currentModel.getfC());
+								System.err.println("Reading fG = "
+										+ currentModel.getfG());
+								System.err.println("Reading fT = "
+										+ currentModel.getfT());
+							}
+						} else if (line.startsWith(". Proportion of invariant")) {
+							// currentModel.pI = true;
+							currentModel.setPinv(Double.parseDouble(Utilities
+									.lastToken(line)));
+							if (showParsing)
+								System.err.println("Reading pinv = "
+										+ currentModel.getPinv());
+						} else if (line.contains("Unconstrained likelihood")) {
+							double unconstrainedLnL = (-1.0)
+									* Double.parseDouble(Utilities
+											.lastToken(line));
+							if (!options.isAmbiguous()) {
+								currentModel
+										.setUnconstrainedLnL(unconstrainedLnL);
+							} else {
+								currentModel.setUnconstrainedLnL(0.0d);
+							}
+							if (Math.abs(options.getUnconstrainedLnL()) <= 1e-10) {
+								options.setUnconstrainedLnL(unconstrainedLnL);
+							} else {
+								if (Math.abs(options.getUnconstrainedLnL()
+										- unconstrainedLnL) > 1e-10) {
+									// uLK has changed!!!
+									// temporary uLK is updated
+									options.setUnconstrainedLnL(unconstrainedLnL);
+								}
+							}
+							if (showParsing)
+								System.err
+										.println("Reading unconstrained logLK = "
+												+ currentModel
+														.getUnconstrainedLnL());
+						} else if (line
+								.startsWith(". GTR relative rate parameters")) {
+							line = phymlStatFile.readLine();
+							while (line.trim().length() == 0)
+								// get rid of any number of returns
+								line = phymlStatFile.readLine();
+							currentModel.setRa(Double.parseDouble(Utilities
+									.lastToken(line)));
+							line = phymlStatFile.readLine();
+							currentModel.setRb(Double.parseDouble(Utilities
+									.lastToken(line)));
+							line = phymlStatFile.readLine();
+							currentModel.setRc(Double.parseDouble(Utilities
+									.lastToken(line)));
+							line = phymlStatFile.readLine();
+							currentModel.setRd(Double.parseDouble(Utilities
+									.lastToken(line)));
+							line = phymlStatFile.readLine();
+							currentModel.setRe(Double.parseDouble(Utilities
+									.lastToken(line)));
+							line = phymlStatFile.readLine();
+							currentModel.setRf(Double.parseDouble(Utilities
+									.lastToken(line)));
+							if (showParsing) {
+								System.err.println("Reading Ra = "
+										+ currentModel.getRa());
+								System.err.println("Reading Rb = "
+										+ currentModel.getRb());
+								System.err.println("Reading Rc = "
+										+ currentModel.getRc());
+								System.err.println("Reading Rd = "
+										+ currentModel.getRd());
+								System.err.println("Reading Re = "
+										+ currentModel.getRe());
+								System.err.println("Reading Rf = "
+										+ currentModel.getRf());
+							}
+							// with custom models phyml does not provide a
+							// ti/tv, so
+							// we
+							// calculate it from the rate parameters
+							// note this is kappa and we need to transform it to
+							// ti/tv
+							if (currentModel.ispT()) {
+								currentModel.setKappa(currentModel.getRb());
+								currentModel
+										.setTitv(currentModel.getKappa()
+												* (currentModel.getfA()
+														* currentModel.getfG() + currentModel
+														.getfC()
+														* currentModel.getfT())
+												/ ((currentModel.getfA() + currentModel
+														.getfG()) * (currentModel
+														.getfC() + currentModel
+														.getfT())));
+							}
+						}
+					}
+				}
+			}
+			phymlStatFile.close();
+		} catch (FileNotFoundException e) {
+			notifyObservers(ProgressInfo.ERROR, index, model,
+					"Optimization results file does not exist: "
+							+ phymlStatFileName);
+
+		} catch (NullPointerException e) {
+			notifyObservers(
+					ProgressInfo.ERROR,
+					index,
+					model,
+					"Error while parsing result data from "
+							+ currentModel.getName());
+		}
+
+		try {
+			// Get ML tree
+			TextInputStream phymlTreeFile = new TextInputStream(
+					phymlTreeFileName);
+			String treestr = phymlTreeFile.readLine();
+			currentModel.setTreeString(treestr);
+			phymlTreeFile.close();
+		} catch (FileNotFoundException e) {
+			notifyObservers(ProgressInfo.ERROR, index, model, null);
+			System.err.println("Optimized tree file does not exist: "
+					+ phymlTreeFileName);
+
+		} catch (TreeParseException e) {
+			StringBuffer sb = new StringBuffer();
+			sb.append(" Please, check the PhyML log");
+			if (ModelTest.execMode == ModelTest.ExecMode.GUI) {
+				sb.append(" tab,");
+			} else {
+				sb.append(" file at " + options.getLogFile());
+			}
+			sb.append(" or run PhyML alone for getting more information: ");
+			notifyObservers(ProgressInfo.ERROR, index, model, "ML tree for "
+					+ currentModel.getName() + " is invalid." + sb.toString());
+		}
+		Utilities.deleteFile(phymlStatFileName);
+		Utilities.deleteFile(phymlTreeFileName);
+
+	}
+	
+	private void notifyObservers(int type, int value, Model model,
+			String message) {
+		setChanged();
+		notifyObservers(new ProgressInfo(type, value, model, message));
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/ProcessManager.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/ProcessManager.java
new file mode 100644
index 0000000..56c011f
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/ProcessManager.java
@@ -0,0 +1,64 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.List;
+
+public class ProcessManager {
+
+	private static ProcessManager instance;
+	private List<Process> processes;
+
+	private ProcessManager() {
+		processes = new ArrayList<Process>();
+	}
+
+	public synchronized void registerProcess(Process process) {
+		synchronized (processes) {
+			processes.add(process);
+		}
+	}
+
+	public synchronized void removeProcess(Process process) {
+		synchronized (processes) {
+			processes.remove(process);
+		}
+	}
+
+	public synchronized void killAll() {
+		try {
+			synchronized (processes) {
+				for (Process p : processes) {
+					p.destroy();
+					processes.remove(p);
+				}
+			}
+		} catch (ConcurrentModificationException ex) {
+			// Ignore... this sometimes happens
+		}
+	}
+
+	public synchronized static ProcessManager getInstance() {
+		if (instance == null) {
+			instance = new ProcessManager();
+		}
+		return instance;
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunConsense.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunConsense.java
new file mode 100644
index 0000000..0ce334d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunConsense.java
@@ -0,0 +1,320 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.io.PushbackReader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.Vector;
+
+import pal.misc.Identifier;
+import pal.tree.ReadTree;
+import pal.tree.Tree;
+import pal.tree.TreeParseException;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.gui.XManager;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+import es.uvigo.darwin.prottest.consensus.Consensus;
+import es.uvigo.darwin.prottest.facade.TreeFacade;
+import es.uvigo.darwin.prottest.facade.TreeFacadeImpl;
+import es.uvigo.darwin.prottest.tree.WeightedTree;
+import es.uvigo.darwin.prottest.util.FixedBitSet;
+
+public class RunConsense {
+	
+	private TextOutputStream stream;
+	private Consensus consensus;
+	
+//	private String criterion;
+	private String consensusType;
+	private InformationCriterion criterion;
+	private int numModels;
+	private Model[] model;
+	private int[] order;
+	private double confidenceInterval;
+	private Vector<Model> confidenceModels;
+
+	private double[] w;
+	private double[] cumw;
+	private boolean[] isInInterval;
+
+	public static es.uvigo.darwin.jmodeltest.threads.SwingWorker workerConsense;
+
+	// constructor
+	public RunConsense(InformationCriterion tcriterion, String tconsensusType,
+			double minterval) {
+
+		criterion = tcriterion;
+		consensusType = tconsensusType;
+		numModels = tcriterion.getNumModels();
+		model = ModelTest.getCandidateModels();
+		order = new int[numModels];
+		confidenceInterval = minterval;
+		confidenceModels = new Vector<Model>();
+
+		w = new double[numModels];
+		cumw = new double[numModels];
+		isInInterval = new boolean[numModels];
+
+		stream = ModelTest.getMainConsole();
+
+		/**
+		 * This action listener, called by the "Start" button, effectively forks
+		 * the thread that does the work.
+		 * 
+		 * /* Invoking start() on the SwingWorker causes a new Thread to be
+		 * creaconsense that will call construct(), and then finished(). Note
+		 * that finished() is called even if the worker is interrupconsense
+		 * because we catch the InterrupconsenseException in doConsense().
+		 */
+		if (ModelTest.buildGUI)
+			System.out.println("\nComputing model averaged phylogeny ...");
+
+		buildConfidenceInterval();
+		consensus = doConsense();
+		printConsensus();
+
+		if (ModelTest.buildGUI) {
+			XManager.getInstance().getPane().setCaretPosition(
+					XManager.getInstance().getPane().getDocument()
+					.getLength());
+			System.out.println("OK");
+		}
+
+	}
+
+	/**
+	 * This method represents the application code that we'd like to run on a
+	 * separate thread.
+	 */
+	// Object doConsense()
+	private Consensus doConsense() {
+
+		List<WeightedTree> treeList = new ArrayList<WeightedTree>();
+
+		for (Model m : confidenceModels) {
+
+			try {
+				// parse tree
+				String tree = m.getTreeString();
+				StringReader sr = new StringReader(tree);
+				Tree t = new ReadTree(new PushbackReader(sr));
+
+				double weight;
+				// set criterion
+				switch (criterion.getType()) {
+				case InformationCriterion.IC_AIC:
+					weight = m.getAICw();
+					break;
+				case InformationCriterion.IC_AICc:
+					weight = m.getAICcw();
+					break;
+				case InformationCriterion.IC_BIC:
+					weight = m.getBICw();
+					break;
+				case InformationCriterion.IC_DT:
+					weight = m.getDTw();
+					break;
+				default:
+					weight = 0.0d;
+				}
+
+				treeList.add(new WeightedTree(t, weight));
+
+			} catch (TreeParseException e1) {
+				// TODO Auto-generated catch block
+				e1.printStackTrace();
+			}
+		}
+
+		double consensusThreshold;
+		if (consensusType.equals("strict")) {
+			consensusThreshold = 0.99999999d;
+		} else {
+			consensusThreshold = 0.5d;
+		}
+		;
+		Consensus consensus = new Consensus(treeList, consensusThreshold,
+				Consensus.BRANCH_LENGTHS_MEDIAN);
+
+		return consensus;
+	} // doConsense
+
+	/**************
+	 * buildConfidenceInterval ************************
+	 * 
+	 * Builds the confidence interval of selected models and their cumulative
+	 * weight
+	 * 
+	 * The model that just passed the confidence will be or not in the interval
+	 * by chance (see below)
+	 ****************************************************************/
+
+	private void buildConfidenceInterval() {
+		int i;
+		Model tmodel;
+		tmodel = model[0];
+
+		order = criterion.order;
+
+		// set alias
+		for (i = 0; i < numModels; i++) {
+			tmodel = model[order[i]];
+
+			w[i] = criterion.getWeight(tmodel);
+			cumw[i] = criterion.getCumWeight(tmodel);
+			
+		}
+
+		// construct the confidence interval for models
+		if (confidenceInterval == 1.0) {
+			for (i = 0; i < numModels; i++) {
+				tmodel = model[order[i]];
+				isInInterval[i] = true;
+				confidenceModels.add(tmodel);
+			}
+		} else {
+			for (i = 0; i < numModels; i++) {
+				tmodel = model[order[i]];
+
+				// System.out.print("name=" + tmodel.name + " w=" + w[i] +
+				// " cumw=" + cumw[i]);
+
+				if (cumw[i] <= confidenceInterval) {
+					isInInterval[i] = true;
+					confidenceModels.add(tmodel);
+				} else
+					break;
+			}
+
+			// lets decide whether the model that just passed the confidence
+			// interval should be included (suggested by John Huelsenbeck)
+			double probOut = (tmodel.getCumAICw() - confidenceInterval)
+					/ tmodel.getAICw();
+			double probIn = 1.0 - probOut;
+			Random generator = new Random();
+			double randomNumber = generator.nextDouble();
+			if (randomNumber <= probIn) {
+				isInInterval[i] = true;
+				confidenceModels.add(tmodel);
+			} else
+				isInInterval[i] = false;
+		}
+	}
+
+	public double getConfidenceInterval() {
+		return confidenceInterval;
+	}
+	
+	public String getConsensusType() {
+		return consensusType;
+	}
+	
+	public List<Model> getConfidenceModels() {
+		return confidenceModels;
+	}
+	
+	public Tree getConsensus() {
+		return consensus.getConsensusTree();
+	}
+	
+	private void printConsensus() {
+		
+		double consensusThreshold = consensusType.equals("50% majority rule")?0.5:1.0;
+		TreeFacade treeFacade = new TreeFacadeImpl();
+		
+		// print results for best AIC model
+		stream.println(" ");stream.println(" ");stream.println(" ");
+		stream.println("---------------------------------------------------------------");
+		stream.println("*                                                             *");
+		stream.println("*                    MODEL AVERAGED PHYLOGENY                 *");
+		stream.println("*                                                             *");
+		stream.println("---------------------------------------------------------------");
+
+		if (criterion.getType() == InformationCriterion.IC_DT)
+			Utilities
+					.printRed("\nWarning: The DT weights used for this model averaged phylogeny are very gross"
+							+ " and should be used with caution. See the program documentation.\n");
+        stream.println(" ");		
+        stream.println("Selection criterion: . . . . " + criterion);
+        stream.print("Confidence interval: . . . . "); 
+        stream.printf("%4.2f\n", confidenceInterval);
+        stream.println("Consensus type:. . . . . . . " + consensusType);
+        stream.println(" ");
+
+     // print confidence set
+		stream.println(" ");
+		stream.print("Using " + confidenceModels.size() + " models in the ");
+		stream.printf("%4.2f ", confidenceInterval);
+		stream.print("confidence interval = ");
+		for (Model m : confidenceModels) {
+			stream.print(m.getName() + " ");
+		}
+		stream.println(" ");
+		
+        Set<FixedBitSet> keySet = consensus.getCladeSupport().keySet();
+        List<FixedBitSet> splitsInConsensus = new ArrayList<FixedBitSet>();
+        List<FixedBitSet> splitsOutFromConsensus = new ArrayList<FixedBitSet>();
+
+        for (FixedBitSet fbs : keySet) {
+            if (fbs.cardinality() > 1) {
+                double psupport = (1.0 * consensus.getCladeSupport().get(fbs)) / 1.0;
+                if (psupport < consensusThreshold) {
+                    splitsOutFromConsensus.add(fbs);
+                } else {
+                    splitsInConsensus.add(fbs);
+                }
+            }
+        }
+
+        stream.println(" ");
+        stream.println("Species in order:");
+        stream.println(" ");
+
+        int numTaxa = consensus.getIdGroup().getIdCount();
+        for (int i = 0; i < numTaxa; i++) {
+            Identifier id = consensus.getIdGroup().getIdentifier(i);
+            stream.println("    " + (i + 1) + ". " + id.getName());
+        }
+ 
+        stream.println(" ");
+        stream.println("Bipartitions included in the consensus tree");
+        stream.println(" ");
+
+        stream.println(consensus.getSetsIncluded());
+        stream.println(" ");
+        
+        Tree consensusTree = consensus.getConsensusTree();
+        stream.println(treeFacade.toASCII(consensusTree));
+        stream.println(" ");
+        String newickTree = treeFacade.toNewick(consensusTree, true, true, true);
+        stream.println(newickTree);
+        stream.println(" ");
+        stream.println("Note: this tree is unrooted. Branch lengths are the expected number of "
+        		+ "substitutions per site. Labels next to parentheses represent phylogenetic "
+        		+ "uncertainty due to model selection (see documentation)");
+	}
+
+} // class RunConsense
+
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhyml.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhyml.java
new file mode 100644
index 0000000..52d43b7
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhyml.java
@@ -0,0 +1,387 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.ModelTestConfiguration;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.model.ModelComparator;
+import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+/**
+ * RunPhyml.java
+ * 
+ * Description: Makes phyml calculate likelihood scores for competing models
+ * 
+ * @author Diego Darriba, University of Vigo / University of A Coruna, Spain
+ *         ddarriba at udc.es
+ * @author David Posada, University of Vigo, Spain dposada at uvigo.es |
+ *         darwin.uvigo.es
+ * @version 2.1 (May 2012)
+ */
+public abstract class RunPhyml extends Observable implements Observer {
+
+	// Set of variables for tuning the guided search algorithm
+	private static final boolean filterFrequencies = true;
+	private static final boolean filterRateMatrix = true;
+	private static final boolean filterRateVariation = true;
+
+	protected ApplicationOptions options;
+	protected Model[] models;
+	protected Model gtrModel = null;
+
+	public static final String PHYML_VERSION = "3.0";
+
+	public static String PHYML_TREE_SUFFIX = "_phyml_tree_";
+	public static String PHYML_STATS_SUFFIX = "_phyml_stats_";
+
+	public static File phymlBinary;
+	public static String phymlBinaryStr;
+	private static String CURRENT_DIRECTORY = ModelTestConfiguration.PATH;
+	private static boolean PHYML_GLOBAL = false;
+	public static String PHYML_PATH = CURRENT_DIRECTORY + "exe/phyml/";
+
+	
+	protected Observer progress;
+
+	static {
+		if (PHYML_GLOBAL) {
+			PHYML_PATH = "";
+		} else {
+			String path = ModelTestConfiguration.getExeDir();
+			if (!path.startsWith(File.separator)) {
+				PHYML_PATH = CURRENT_DIRECTORY + File.separator + path;
+			} else {
+				PHYML_PATH = path;
+			}
+			if (!PHYML_PATH.endsWith(File.separator)) {
+				PHYML_PATH += File.separator;
+			}
+		}
+		if (PHYML_GLOBAL) {
+			phymlBinaryStr = "phyml";
+		} else {
+			phymlBinary = new File(PHYML_PATH + "phyml");
+			if (phymlBinary.exists() && phymlBinary.canExecute()) {
+				phymlBinaryStr = phymlBinary.getAbsolutePath();
+			} else {
+				phymlBinaryStr = PHYML_PATH + Utilities.getBinaryVersion();
+			}
+			/* Check if binary exists */
+			phymlBinary = new File(phymlBinaryStr);
+		}
+	}
+	public RunPhyml(Observer progress, ApplicationOptions options,
+			Model[] models) {
+		if (models != null)
+			this.models = new Model[models.length];
+		else
+			this.models = new Model[0];
+		for (int i = 0; i < this.models.length; i++)
+			this.models[i] = models[i];
+		this.options = options;
+		this.progress = progress;
+		this.addObserver(progress);
+		Arrays.sort(this.models, new ModelComparator());
+	}
+
+	public void execute() {
+		// remove stuff from exe directories before starting
+		deleteFiles();
+		printSettings(ModelTest.getMainConsole());
+
+		// locate GTR model
+		String searchFor;
+		int gtrParams;
+		if (options.doI && options.doG) {
+			searchFor="GTR+I+G";
+			gtrParams = 10;
+		} else if(options.doI) {
+			searchFor="GTR+I";
+			gtrParams = 9;
+		} else if(options.doG) {
+			searchFor="GTR+G";
+			gtrParams = 9;
+		} else {
+			searchFor="GTR";
+			gtrParams = 8;
+		}
+		for (int i = (models.length - 1); i >= 0; i--) {
+			if (models[i].getName().startsWith(searchFor)) {
+				gtrModel = models[i];
+				break;
+			}
+		}
+		if (gtrModel == null) {
+			gtrModel = new Model(0, searchFor, "012345", gtrParams, false, false, false, true, options.doI, options.doG, 2, 4);
+		}
+		// estimate a NJ-JC tree if needed
+		if (options.fixedTopology) {
+			Model jcModel = null;
+			for (Model model : models) {
+				if (model.getName().equals("JC")) {
+					jcModel = model;
+					break;
+				}
+			}
+
+			if (jcModel != null) {
+				notifyObservers(ProgressInfo.BASE_TREE_INIT, 0, jcModel, null);
+
+				PhymlSingleModel jcModelPhyml = new PhymlSingleModel(jcModel,
+						0, true, false, options);
+				jcModelPhyml.addObserver(this);
+				jcModelPhyml.run();
+
+				// create JCtree file
+				TextOutputStream JCtreeFile = new TextOutputStream(options
+						.getTreeFile().getAbsolutePath(), false);
+				JCtreeFile.print(jcModel.getTreeString() + "\n");
+				JCtreeFile.close();
+
+				notifyObservers(ProgressInfo.BASE_TREE_COMPUTED, 0, jcModel,
+						null);
+			}
+
+		}
+
+		if (options.isGuidedSearch()) {
+
+			if (gtrModel != null) {
+				// compute GTR model
+				notifyObservers(ProgressInfo.GTR_OPTIMIZATION_INIT, models.length, gtrModel, null);
+				PhymlSingleModel gtrPhymlModel = new PhymlSingleModel(
+						gtrModel, 0, false, false, options);
+				gtrPhymlModel.run();
+				notifyObservers(ProgressInfo.GTR_OPTIMIZATION_COMPLETED, models.length, gtrModel, null);
+				
+				GuidedSearchManager gsm = new GuidedSearchManager(
+						options.getGuidedSearchThreshold(), gtrModel,
+						filterFrequencies, filterRateMatrix,
+						filterRateVariation);
+	
+				models = gsm.filterModels(models);
+				ModelTest.setCandidateModels(models);
+			} else {
+				notifyObservers(ProgressInfo.GTR_NOT_FOUND, models.length, models[0], null);
+			}
+		}
+
+		// compute likelihood scores for all models
+
+		notifyObservers(ProgressInfo.OPTIMIZATION_INIT, 0, models[0], null);
+
+		doPhyml();
+
+	}
+
+	public void executeIgnoreGaps(Model[] models) {
+		notifyObservers(ProgressInfo.REOPTIMIZATION_INIT, models.length, models[0], null);
+		parallelExecute(models, true);
+		notifyObservers(ProgressInfo.REOPTIMIZATION_COMPLETED, models.length, null, null);
+	}
+	
+	protected boolean parallelExecute(Model models[], boolean ignoreGaps) {
+		
+		ExecutorService threadPool = Executors.newFixedThreadPool(options
+				.getNumberOfThreads());
+		Collection<Callable<Object>> c = new ArrayList<Callable<Object>>();
+		int current = 0;
+		for (Model model : models) {
+			if (model != null) {
+				PhymlSingleModel psm = new PhymlSingleModel(model, current, false,
+						ignoreGaps, options);
+				psm.addObserver(this);
+				c.add(Executors.callable(psm));
+	
+				current++;
+			}
+		}
+
+		Collection<Future<Object>> futures = null;
+		try {
+			futures = threadPool.invokeAll(c);
+		} catch (InterruptedException e) {
+			notifyObservers(ProgressInfo.INTERRUPTED, 0, null, null);
+		}
+
+		if (futures != null) {
+			for (Future<Object> f : futures) {
+				try {
+					f.get();
+				} catch (InterruptedException ex) {
+					notifyObservers(ProgressInfo.INTERRUPTED, 0, null, null);
+					ex.printStackTrace();
+					return false;
+				} catch (ExecutionException ex) {
+					// Internal exception while computing model.
+					// Let's continue with errors
+					ex.printStackTrace();
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+	
+	/***************************
+	 * printSettings ***************************** * Prints the settings for the
+	 * likelihood calculation * * *
+	 ***********************************************************************/
+
+	protected void printSettings(TextOutputStream stream) {
+
+		stream.println(" ");
+		stream.println(" ");
+		stream.println("---------------------------------------------------------------");
+		stream.println("*                                                             *");
+		stream.println("*        COMPUTATION OF LIKELIHOOD SCORES WITH PHYML          *");
+		stream.println("*                                                             *");
+		stream.println("---------------------------------------------------------------");
+		stream.println(" ");
+		stream.println("::Settings::");
+		stream.println(" ");
+		stream.println(" Phyml version = " + PHYML_VERSION);
+		stream.println(" Phyml binary = " + phymlBinary.getName());
+		stream.println(" Phyml path = " + phymlBinary.getAbsolutePath()
+				.substring(0, phymlBinary.getAbsolutePath().lastIndexOf(File.separator)) + File.separator);
+		stream.println(" Candidate models = " + models.length);
+		stream.print("   number of substitution schemes = ");
+
+		if (options.getSubstTypeCode() == 0)
+			stream.println("3");
+		else if (options.getSubstTypeCode() == 1)
+			stream.println("5");
+		else if (options.getSubstTypeCode() == 2)
+			stream.println("7");
+		else
+			stream.println("11");
+
+		if (options.doF)
+			stream.println("   including models with equal/unequal base frequencies (+F)");
+		else
+			stream.println("   including only models with equal base frequencies");
+
+		if (options.doI)
+			stream.println("   including models with/without a proportion of invariable sites (+I)");
+		else
+			stream.println("   including only models without a proportion of invariable sites");
+
+		if (options.doG)
+			stream.println("   including models with/without rate variation among sites (+G)"
+					+ " (nCat = " + options.numGammaCat + ")");
+		else
+			stream.println("   including only models without rate variation among sites");
+
+		stream.print(" Optimized free parameters (K) =");
+		stream.print(" substitution parameters");
+		if (options.countBLasParameters)
+			stream.print(" + " + options.getNumBranches() + " branch lengths");
+		if (options.optimizeMLTopology)
+			stream.print(" + topology");
+		stream.println(" ");
+
+		stream.print(" Base tree for likelihood calculations = ");
+		if (options.userTopologyExists) {
+			stream.println("fixed user tree topology.");
+			stream.println(" ");
+			stream.print("User tree " + "("
+					+ options.getInputTreeFile().getName() + ") = ");
+			stream.println(options.getUserTree());
+			stream.println(" ");
+		} else if (options.fixedTopology) {
+			stream.println("fixed BIONJ-JC tree topology");
+		} else if (options.optimizeMLTopology) {
+			stream.println("ML tree");
+		} else {
+			stream.println("BIONJ tree");
+		}
+
+		if (options.optimizeMLTopology) {
+			stream.print(" Tree topology search operation = ");
+			switch (options.treeSearchOperations) {
+			case NNI:
+				stream.println("NNI");
+				break;
+			case SPR:
+				stream.println("SPR");
+				break;
+			case BEST:
+				stream.println("BEST");
+				break;
+			}
+		}
+		if (options.isClusteringSearch()) {
+			stream.println(" Using hill-climbing hierarchical clustering");
+		}
+		
+		if (options.isGuidedSearch()) {
+			stream.println(" Using heuristic model filtering ");
+		}
+		stream.println(" ");
+	}
+
+	protected abstract Object doPhyml();
+
+	/***********************************************************************
+	 * interruptThread
+	 * 
+	 * Interrupts the calculation of likelihood scores
+	 ***********************************************************************/
+	public void interruptThread() {
+		notifyObservers(ProgressInfo.OPTIMIZATION_COMPLETED_INTERRUPTED, 0,
+				null, null);
+		// workerPhyml.interrupt();
+		// IS_INTERRUPTED = true;
+	}
+
+	private void deleteFiles() {
+		/* phymlFolder */
+		//if (options.getLogFile() != null)
+			options.getLogFile().delete();
+	}
+
+	protected void notifyObservers(int type, int value, Model model,
+			String message) {
+		setChanged();
+		notifyObservers(new ProgressInfo(type, value, model, message));
+	}
+
+	@Override
+	public void update(Observable o, Object arg) {
+		setChanged();
+		notifyObservers(arg);
+	}
+
+} // class RunPhyml
+
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlClustering.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlClustering.java
new file mode 100644
index 0000000..be021f8
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlClustering.java
@@ -0,0 +1,137 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
+import es.uvigo.darwin.jmodeltest.selection.AIC;
+import es.uvigo.darwin.jmodeltest.selection.AICc;
+import es.uvigo.darwin.jmodeltest.selection.BIC;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+
+public class RunPhymlClustering extends RunPhyml {
+
+	private ExecutorService threadPool;
+	private int currentStage;
+	private int numModelsInStage;
+
+	public RunPhymlClustering(Observer progress, ApplicationOptions options,
+			Model[] models) {
+		super(progress, options, models);
+
+		this.threadPool = Executors.newFixedThreadPool(options
+				.getNumberOfThreads());
+	}
+
+	/**
+	 * Execute Model optimization in up to 6 steps
+	 */
+	protected Object doPhyml() {
+
+		List<Model> evaluatedModels = new ArrayList<Model>();
+	
+		evaluatedModels.add(gtrModel);
+		Model globalBestModel = gtrModel;
+		if (gtrModel == null) {
+			globalBestModel = models[models.length-1];
+		}
+		double bestScore = Double.MAX_VALUE;
+		double globalBestScore = Double.MAX_VALUE;
+		for (int groups=6; groups>0; groups--) {
+			String partition = globalBestModel==null?"012345":globalBestModel.getPartition();
+			Model[] currentModels = GuidedSearchManager.getModelsSubset(models, partition, groups);
+
+			currentStage = 7-groups;
+			numModelsInStage = currentModels.length;
+			
+			if (currentModels.length > 0) {
+				// Optimize the current models
+				Model bestModel = currentModels[0];
+				for (Model model : currentModels) {
+					PhymlSingleModel phymlModel = new PhymlSingleModel(
+							model, 0, false, false, options);
+					phymlModel.addObserver(this);
+					phymlModel.run();
+					double currentScore = Double.MAX_VALUE - 1.0;
+					switch (options.getHeuristicInformationCriterion()) {
+					case InformationCriterion.IC_AIC:
+						currentScore = AIC.computeAic(model, options);
+						break;
+					case InformationCriterion.IC_BIC:
+						currentScore = BIC.computeBic(model, options);
+						break;
+					case InformationCriterion.IC_AICc:
+						currentScore = AICc.computeAicc(model, options);
+						break;
+					}
+					if (currentScore < bestScore) {
+						bestModel = model;
+						bestScore = currentScore;
+					}
+				}
+			
+				// Check LnL
+				if (globalBestModel.getLnL()>0 && bestScore > globalBestScore) {
+					// End of algorithm
+					break;
+				} else {
+					globalBestModel = bestModel;
+					globalBestScore = bestScore;
+				}
+			}
+		}
+		ModelTest.purgeModels();
+		System.out.println("Global best model: " + globalBestModel.getName());
+		
+//		notifyObservers(ProgressInfo.OPTIMIZATION_COMPLETED_OK, models.length,
+//				null, null);
+		
+		return "All Done";
+	} // doPhyml
+
+	public void interruptThread() {
+		super.interruptThread();
+		ProcessManager.getInstance().killAll();
+		threadPool.shutdownNow();// shutdown();
+	}
+
+	@Override
+	public void update(Observable o, Object arg) {
+		if (arg != null) {
+			ProgressInfo info = (ProgressInfo) arg;
+			if (info.getType() == ProgressInfo.ERROR || 
+					info.getType() == ProgressInfo.ERROR_BINARY_NOEXECUTE || 
+					info.getType() == ProgressInfo.ERROR_BINARY_NOEXISTS) {
+				interruptThread();
+			} else {
+				info.setHeuristicStage(currentStage);
+				info.setNumModelsInStage(numModelsInStage);
+			}
+		}
+		super.update(o, arg);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlHybrid.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlHybrid.java
new file mode 100644
index 0000000..b9d8fde
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlHybrid.java
@@ -0,0 +1,301 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+
+import mpi.MPI;
+import mpi.Request;
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
+
+public class RunPhymlHybrid extends RunPhyml {
+
+	private List<Model> myModels;
+
+	// Synchronization package variables.
+	// Thread safe under current operation. Keep in mind.
+	volatile Model rootModel = null;
+	volatile boolean rootModelRequest = false;
+
+	int mpjMe, mpjSize;
+	int maxPEs;
+	/** The number of available PEs. */
+	int availablePEs;
+	private PhymlParallelModel pme;
+	private Model[] computedModels;
+	private MultipleDistributor distributor;
+	int[] itemsPerProc;
+	int[] displs;
+
+	public RunPhymlHybrid(Observer progress, ApplicationOptions options,
+			Model[] models) {
+		super(progress, options, models);
+		// this.deleteObserver(progress);
+		myModels = new ArrayList<Model>();
+
+	}
+
+	public RunPhymlHybrid(int mpjMe, int mpjSize, Observer progress,
+			ApplicationOptions options, Model[] models, int numberOfThreads) {
+		super(progress, options, models);
+		// this.deleteObserver(progress);
+		myModels = new ArrayList<Model>();
+
+		this.mpjMe = mpjMe;
+		this.mpjSize = mpjSize;
+
+		itemsPerProc = new int[mpjSize];
+		displs = new int[mpjSize];
+
+		maxPEs = numberOfThreads;
+		availablePEs = maxPEs;
+		pme = new PhymlParallelModel(maxPEs);
+		pme.addObserver(this);
+
+	}
+
+	public void distribute() {
+
+		List<Model> modelList = Arrays.asList(models);
+		distributor = new MultipleDistributor(modelList, this,
+				ModelTest.MPJ_ME, ModelTest.MPJ_SIZE);
+		distributor.addObserver(progress);
+		
+		notifyObservers(ProgressInfo.OPTIMIZATION_INIT, 0,
+				models[0], null);
+		
+		Thread distributorThread = new Thread(distributor);
+		distributorThread.start();
+		request();
+		
+		modelList = Arrays.asList(computedModels);
+		for (Model model : models) {
+			model.update(modelList.get(modelList.indexOf(model)));
+		}
+
+		notifyObservers(ProgressInfo.OPTIMIZATION_COMPLETED_OK, models.length,
+				null, null);
+
+	}
+
+	public void request() {
+
+//		List<PhymlSingleModel> phymlEstimatorList = new ArrayList<PhymlSingleModel>();
+
+		Model[] lastComputedModel = new Model[1];
+		while (true) {
+			// send request to root
+			Model[] modelToReceive = null;
+			Model model = null;
+			if (ModelTest.MPJ_ME > 0) {
+				int[] sendMessage = { availablePEs, maxPEs };
+				Request modelRequest = MPI.COMM_WORLD.Isend(sendMessage, 0, 2,
+						MPI.INT, 0, MultipleDistributor.TAG_SEND_REQUEST);
+				// prepare reception
+				modelToReceive = new Model[1];
+				boolean[] notification = new boolean[1];
+				// wait for request
+				modelRequest.Wait();
+
+				Request notifyRecv = MPI.COMM_WORLD.Irecv(notification, 0, 1,
+						MPI.BOOLEAN, 0,
+						MultipleDistributor.TAG_EXIST_MORE_MODELS);
+				notifyRecv.Wait();
+
+				if (notification[0]) {
+					// receive model
+					Request modelReceive = MPI.COMM_WORLD.Irecv(modelToReceive,
+							0, 1, MPI.OBJECT, 0,
+							MultipleDistributor.TAG_SEND_MODEL);
+					modelReceive.Wait();
+					model = modelToReceive[0];
+				} else {
+					break;
+				}
+			} else {
+				// This strategy is an easy way to avoid the problem of
+				// thread-safety in MPJ-Express. It works correctly, but
+				// it also causes to introduce coupling between this class
+				// and Distributor having to define two volatile attributes:
+				// rootModelRequest and rootModel.
+				rootModelRequest = true;
+				while (rootModelRequest) {
+					try {
+						Thread.sleep(200);
+					} catch (InterruptedException e) {
+						throw new RuntimeException("Thread interrupted");
+					}
+				}
+				model = rootModel;
+				if (model == null)
+					break;
+			}
+			if (model != null) {
+				// compute
+				myModels.add(model);
+				availablePEs -= MultipleDistributor.getPEs(model, maxPEs);
+				PhymlSingleModel runenv = new PhymlSingleModel(model, 0, false,
+						options, MultipleDistributor.getPEs(model, maxPEs));
+				pme.execute(runenv);
+				while (availablePEs <= 0) {
+					try {
+						Thread.sleep(200);
+					} catch (InterruptedException e) {
+						throw new RuntimeException("Thread interrupted");
+					}
+				}
+
+				/*
+				// runenv.addObserver(this);
+				if (!runenv.compute())
+					throw new RuntimeException("Optimization error");
+
+				phymlEstimatorList.add(runenv);
+				*/
+				lastComputedModel[0] = runenv.getModel();
+			}
+		}
+
+		// endTime = System.currentTimeMillis();
+
+		while (pme.hasMoreTasks()) {
+			try {
+				Thread.sleep(400);
+			} catch (InterruptedException e) {
+				throw new RuntimeException("Thread interrupted");
+			}
+		}
+
+		if (mpjMe > 0) {
+			gather();
+		} else {
+			computedModels = gather();
+		}
+		
+	}
+
+	protected Object doPhyml() {
+		return null;
+	} // doPhyml
+
+	/**
+	 * Gathers the models of all processors into the root one. This method
+	 * should be called by every processor after computing likelihood value of
+	 * whole model set.
+	 * 
+	 * This method will return an empty array of models for every non-root
+	 * processor
+	 * 
+	 * @return the array of gathered models
+	 */
+	private Model[] gather() {
+
+		int numberOfModels = models != null?models.length:1;
+		Model[] allModels = new Model[numberOfModels];
+		
+		if (distributor != null) {
+			itemsPerProc = distributor.getItemsPerProc();
+			displs = distributor.getDispls();
+		}
+
+		MPI.COMM_WORLD.Bcast(itemsPerProc, 0, mpjSize, MPI.INT, 0);
+		
+		// gathering optimized models
+		MPI.COMM_WORLD.Gatherv(myModels.toArray(new Model[0]), 0,
+				myModels.size(), MPI.OBJECT, allModels, 0, itemsPerProc,
+				displs, MPI.OBJECT, 0);
+
+		return allModels;
+	}
+
+	public void execute() {
+
+		if (ModelTest.MPJ_ME == 0) {
+			printSettings(ModelTest.getMainConsole());
+
+			// TODO: Send topology to each processor
+			// estimate a NJ-JC tree if needed
+			if (options.fixedTopology) {
+				notifyObservers(ProgressInfo.BASE_TREE_INIT, 0, models[0], null);
+
+				PhymlSingleModel jcModel = new PhymlSingleModel(models[0], 0,
+						true, false, options);
+				jcModel.run();
+
+				// create JCtree file
+				TextOutputStream JCtreeFile = new TextOutputStream(options
+						.getTreeFile().getAbsolutePath(), false);
+				JCtreeFile.print(models[0].getTreeString() + "\n");
+				JCtreeFile.close();
+
+				options.setUserTree(models[0].getTreeString());
+
+				notifyObservers(ProgressInfo.BASE_TREE_COMPUTED, 0, models[0],
+						null);
+
+			}
+
+			// compute likelihood scores for all models
+			System.out.println("computing likelihood scores for "
+					+ models.length + " models with Phyml " + PHYML_VERSION);
+		}
+
+		// sincronize ApplicationOptions from root
+		ApplicationOptions[] optionsBCast = new ApplicationOptions[1];
+		optionsBCast[0] = options;
+		MPI.COMM_WORLD.Bcast(optionsBCast, 0, 1, MPI.OBJECT, 0);
+		this.options = optionsBCast[0];
+		ApplicationOptions.setInstance(this.options);
+
+		if (ModelTest.MPJ_ME == 0) {
+			distribute();
+		} else {
+			try {
+				this.options.buildWorkFiles();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+
+			request();
+		}
+	}
+
+	@Override
+	public void update(Observable o, Object arg) {
+		if (arg != null) {
+			ProgressInfo info = (ProgressInfo) arg;
+			if (info.getType() == ProgressInfo.SINGLE_OPTIMIZATION_COMPLETED) {
+				availablePEs += MultipleDistributor.getPEs(info.getModel(),
+						maxPEs);
+			}
+		}
+		// Ignore runtime messages
+		setChanged();
+		notifyObservers(arg);
+	}
+} // class RunPhyml
+
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlMPJ.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlMPJ.java
new file mode 100644
index 0000000..5ff016b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlMPJ.java
@@ -0,0 +1,205 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+
+import mpi.MPI;
+import mpi.Request;
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.exception.InternalException;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
+
+/** 
+ * RunPhymlMPJ.java
+ *
+ * Description:		Makes phyml calculate likelihood scores for competing models
+ * @author			Diego Darriba, University of Vigo / University of A Coruna, Spain
+ * 					ddarriba at udc.es
+ * @author			David Posada, University of Vigo, Spain  
+ *					dposada at uvigo.es | darwin.uvigo.es
+ * @version			2.0.2 (Feb 2012)
+ */
+public class RunPhymlMPJ extends RunPhyml {
+
+
+	private List<Model> myModels;
+
+	// Synchronization package variables.
+	// Thread safe under current operation. Keep in mind.
+	volatile Model rootModel = null;
+	volatile boolean rootModelRequest = false;
+
+	public RunPhymlMPJ(Observer progress, ApplicationOptions options,
+			Model[] models) {
+		super(progress, options, models);
+		// this.deleteObserver(progress);
+		myModels = new ArrayList<Model>();
+
+	}
+
+	public void distribute() {
+
+		List<Model> modelList = Arrays.asList(models);
+		Distributor distributor = new Distributor(modelList, this,
+				ModelTest.MPJ_ME, ModelTest.MPJ_SIZE);
+		distributor.addObserver(progress);
+		Thread distributorThread = new Thread(distributor);
+		distributorThread.start();
+		request();
+
+		for (Model model : ModelTest.getCandidateModels()) {
+			model.update(modelList.get(modelList.indexOf(model)));
+		}
+
+		notifyObservers(ProgressInfo.OPTIMIZATION_COMPLETED_OK, models.length,
+				null, null);
+	}
+
+	public void request() {
+
+		List<PhymlSingleModel> phymlEstimatorList = new ArrayList<PhymlSingleModel>();
+
+		Model[] lastComputedModel = new Model[1];
+		while (true) {
+			// send request to root
+			Model[] modelToReceive = null;
+			Model model = null;
+			if (ModelTest.MPJ_ME > 0) {
+				Request modelRequest = MPI.COMM_WORLD.Isend(lastComputedModel,
+						0, 1, MPI.OBJECT, 0, Distributor.TAG_SEND_REQUEST);
+				// prepare reception
+				modelToReceive = new Model[1];
+				// wait for request
+				modelRequest.Wait();
+				// receive model
+				Request modelReceive = MPI.COMM_WORLD.Irecv(modelToReceive, 0,
+						1, MPI.OBJECT, 0, Distributor.TAG_SEND_MODEL);
+				modelReceive.Wait();
+				model = modelToReceive[0];
+			} else {
+				// This strategy is an easy way to avoid the problem of
+				// thread-safety in MPJ-Express. It works correctly, but
+				// it also causes to introduce coupling between this class
+				// and Distributor having to define two volatile attributes:
+				// rootModelRequest and rootModel.
+				rootModelRequest = true;
+				while (rootModelRequest) {
+					try {
+						Thread.sleep(200);
+					} catch (InterruptedException e) {
+						throw new InternalException(
+								"Thread interrupted");
+					}
+				}
+				model = rootModel;
+			}
+			if (model == null)
+				break;
+			else {
+				// compute
+				myModels.add(model);
+				PhymlSingleModel runenv = new PhymlSingleModel(model, 0, false,
+						false, options);
+				runenv.addObserver(this);
+
+				if (!runenv.compute())
+					throw new InternalException("Optimization error");
+
+				phymlEstimatorList.add(runenv);
+				lastComputedModel[0] = runenv.getModel();
+			}
+		}
+
+		// endTime = System.currentTimeMillis();
+	}
+
+	protected Object doPhyml() {
+		return null;
+	} // doPhyml
+
+	public void execute() {
+
+		if (ModelTest.MPJ_ME == 0) {
+			printSettings(ModelTest.getMainConsole());
+
+			// TODO: Send topology to each processor
+			// estimate a NJ-JC tree if needed
+			if (options.fixedTopology) {
+				notifyObservers(ProgressInfo.BASE_TREE_INIT, 0, models[0], null);
+
+				PhymlSingleModel jcModel = new PhymlSingleModel(models[0], 0,
+						true, false, options);
+				jcModel.run();
+
+				// create JCtree file
+				TextOutputStream JCtreeFile = new TextOutputStream(options
+						.getTreeFile().getAbsolutePath(), false);
+				JCtreeFile.print(models[0].getTreeString() + "\n");
+				JCtreeFile.close();
+
+				options.setUserTree(models[0].getTreeString());
+
+				notifyObservers(ProgressInfo.BASE_TREE_COMPUTED, 0, models[0],
+						null);
+
+			}
+
+			// compute likelihood scores for all models
+			System.out.println("computing likelihood scores for " + models.length
+					+ " models with Phyml " + PHYML_VERSION);
+		}
+
+		// sincronize ApplicationOptions from root
+		ApplicationOptions[] optionsBCast = new ApplicationOptions[1];
+		optionsBCast[0] = options;
+		MPI.COMM_WORLD.Bcast(optionsBCast, 0, 1, MPI.OBJECT, 0);
+		this.options = optionsBCast[0];
+		ApplicationOptions.setInstance(this.options);
+
+		if (ModelTest.MPJ_ME == 0) {
+			notifyObservers(ProgressInfo.OPTIMIZATION_INIT, 0,
+					models[0], null);
+			distribute();
+		} else {
+			try {
+				this.options.buildWorkFiles();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+
+			request();
+		}
+	}
+
+	@Override
+	public void update(Observable o, Object arg) {
+		// Ignore runtime messages
+		// setChanged();
+		// notifyObservers(arg);
+	}
+} // class RunPhyml
+
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlThread.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlThread.java
new file mode 100644
index 0000000..909f929
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/RunPhymlThread.java
@@ -0,0 +1,190 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
+import es.uvigo.darwin.jmodeltest.selection.AIC;
+import es.uvigo.darwin.jmodeltest.selection.AICc;
+import es.uvigo.darwin.jmodeltest.selection.BIC;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+
+public class RunPhymlThread extends RunPhyml {
+
+	private ExecutorService threadPool;
+	private int currentStage;
+	private int numModelsInStage;
+	
+	public RunPhymlThread(Observer progress, ApplicationOptions options,
+			Model[] models) {
+		super(progress, options, models);
+
+		this.threadPool = Executors.newFixedThreadPool(options
+				.getNumberOfThreads());
+	}
+
+	/*******************************
+	 * doPhyml ****************************** * run the phyml calculations on a
+	 * separate thread * * *
+	 ***********************************************************************/
+
+	protected Object doPhyml() {
+
+		boolean errorsFound = false;
+		if (options.isClusteringSearch()) {
+			List<Model> evaluatedModels = new ArrayList<Model>();
+			
+			evaluatedModels.add(gtrModel);
+			Model globalBestModel = gtrModel;
+			if (gtrModel == null) {
+				globalBestModel = models[models.length-1];
+			}
+			double globalBestScore = Double.MAX_VALUE;
+			for (int groups=6; groups>0; groups--) {
+				double bestScore = Double.MAX_VALUE;
+				String partition = globalBestModel==null?"012345":globalBestModel.getPartition();
+				Model[] currentModels = GuidedSearchManager.getModelsSubset(models, partition, groups);
+
+				currentStage = 7-groups;
+				numModelsInStage = currentModels.length;
+				
+				if (currentModels.length > 0) {
+					// Optimize the current models
+					Model bestModel = currentModels[0];
+					errorsFound |= !parallelExecute(currentModels, false);
+					
+					for (Model model : currentModels) {
+						double currentScore = Double.MAX_VALUE - 1.0;
+						switch (options.getHeuristicInformationCriterion()) {
+						case InformationCriterion.IC_AIC:
+							currentScore = AIC.computeAic(model, options);
+							break;
+						case InformationCriterion.IC_BIC:
+							currentScore = BIC.computeBic(model, options);
+							break;
+						case InformationCriterion.IC_AICc:
+							currentScore = AICc.computeAicc(model, options);
+							break;
+						}
+						if (currentScore < bestScore) {
+							bestModel = model;
+							bestScore = currentScore;
+						}
+					}
+
+					// Check LnL
+					if (globalBestModel.getLnL()>0 && bestScore > globalBestScore) {
+						// End of algorithm
+						break;
+					} else {
+						globalBestModel = bestModel;
+						globalBestScore = bestScore;
+					}
+				}
+			}
+			ModelTest.purgeModels();
+		} else {
+			errorsFound = !parallelExecute(models, false);
+		}
+		if (errorsFound) {
+			notifyObservers(ProgressInfo.OPTIMIZATION_COMPLETED_INTERRUPTED, models.length,
+				null, null);
+			return "Interrupted";
+		} else {
+			notifyObservers(ProgressInfo.OPTIMIZATION_COMPLETED_OK, models.length,
+					null, null);
+		}
+
+		return "All Done";
+	} // doPhyml
+
+	protected boolean parallelExecute(Model models[], boolean ignoreGaps) {
+		Collection<Callable<Object>> c = new ArrayList<Callable<Object>>();
+		int current = 0;
+		for (Model model : models) {
+			if (model != null) {
+				PhymlSingleModel psm = new PhymlSingleModel(model, current, false,
+						ignoreGaps, options);
+				psm.addObserver(this);
+				c.add(Executors.callable(psm));
+	
+				current++;
+			}
+		}
+
+		Collection<Future<Object>> futures = null;
+		try {
+			futures = threadPool.invokeAll(c);
+		} catch (InterruptedException e) {
+			notifyObservers(ProgressInfo.INTERRUPTED, 0, null, null);
+		}
+
+		if (futures != null) {
+			for (Future<Object> f : futures) {
+				try {
+					f.get();
+				} catch (InterruptedException ex) {
+					notifyObservers(ProgressInfo.INTERRUPTED, 0, null, null);
+					ex.printStackTrace();
+					return false;
+				} catch (ExecutionException ex) {
+					// Internal exception while computing model.
+					// Let's continue with errors
+					ex.printStackTrace();
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+	
+	public void interruptThread() {
+		super.interruptThread();
+		ProcessManager.getInstance().killAll();
+		threadPool.shutdownNow();// shutdown();
+	}
+
+	@Override
+	public void update(Observable o, Object arg) {
+		if (arg != null) {
+			ProgressInfo info = (ProgressInfo) arg;
+			if (info.getType() == ProgressInfo.ERROR || 
+					info.getType() == ProgressInfo.ERROR_BINARY_NOEXECUTE || 
+					info.getType() == ProgressInfo.ERROR_BINARY_NOEXISTS) {
+				interruptThread();
+			} else if (options.isClusteringSearch()) {
+				info.setHeuristicStage(currentStage);
+				info.setNumModelsInStage(numModelsInStage);
+			}
+		}
+		super.update(o, arg);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/exe/StreamGobbler.java b/src/main/java/es/uvigo/darwin/jmodeltest/exe/StreamGobbler.java
new file mode 100644
index 0000000..7a54512
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/exe/StreamGobbler.java
@@ -0,0 +1,103 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.exe;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+class StreamGobbler extends Thread {
+	private InputStream is;
+	private String type;
+	private OutputStream osFile, osConsole;
+	private static int runId = 1;
+	private int localRunId;
+	
+	public int getRunId() {
+		return localRunId;
+	}
+	
+	StreamGobbler(InputStream is, String type, OutputStream fileRedirect,
+			OutputStream consoleRedirect) {
+		this.is = is;
+		this.type = type;
+		this.osFile = fileRedirect;
+		this.osConsole = consoleRedirect;
+		synchronized(is) {
+			this.localRunId = runId++;
+		}
+	}
+
+	public void run() {
+		int i=0;
+		try {
+			PrintWriter pwFile = null;
+			PrintWriter pwConsole = null;
+			if (osFile != null)
+				pwFile = new PrintWriter(osFile);
+			if (osConsole != null)
+				pwConsole = new PrintWriter(osConsole);
+
+			InputStreamReader isr = new InputStreamReader(is);
+			BufferedReader br = new BufferedReader(isr);
+			String line = null;
+			while ((line = br.readLine()) != null) {
+				if (line.contains("patterns found")) {
+					try {
+						int numPatterns = Integer.parseInt(Utilities
+								.firstNumericToken(line));
+						ApplicationOptions options = ApplicationOptions
+								.getInstance();
+						if (Math.abs(options.getNumPatterns()) == 0) {
+							options.setNumPatterns(numPatterns);
+						} else {
+							if (Math.abs(options.getNumPatterns() - numPatterns) > 0) {
+								// number of patterns has changed!!!
+								// temporary number of patterns is updated
+								options.setNumPatterns(numPatterns);
+							}
+						}
+					} catch (NumberFormatException nfe) {
+						// ignore
+					}
+
+				}
+				if (pwFile != null) {
+					synchronized (pwFile) {
+						pwFile.println(type + "("+localRunId+")>" + line);
+						pwFile.flush();
+					}
+				}
+				if (pwConsole != null) {
+						pwConsole.println(type + "("+localRunId+")>" + line);
+						pwConsole.flush();
+				}
+			}
+			if (pwConsole != null)
+				pwConsole.flush();
+		} catch (IOException ioe) {
+			System.err.println("INFO: [StreamGobbler] The stream was closed!");
+		}
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/FrameMain.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/FrameMain.java
new file mode 100644
index 0000000..da1fbcd
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/FrameMain.java
@@ -0,0 +1,1225 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Desktop;
+import java.awt.Dimension;
+import java.awt.FileDialog;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.PushbackReader;
+import java.io.StringReader;
+import java.net.URI;
+
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextPane;
+import javax.swing.KeyStroke;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.plaf.BorderUIResource;
+import javax.swing.text.DefaultCaret;
+
+import pal.tree.Tree;
+import edu.stanford.ejalbert.BrowserLauncher;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.ModelTestConfiguration;
+import es.uvigo.darwin.jmodeltest.ModelTestService;
+import es.uvigo.darwin.jmodeltest.exe.RunPhyml;
+import es.uvigo.darwin.jmodeltest.io.AlignmentReader;
+import es.uvigo.darwin.jmodeltest.io.DocumentOutputStream;
+import es.uvigo.darwin.jmodeltest.io.HtmlReporter;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.tree.TreeSummary;
+import es.uvigo.darwin.jmodeltest.utilities.InitialFocusSetter;
+import es.uvigo.darwin.jmodeltest.utilities.PrintUtilities;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+/* This class sets the main GUI */
+public class FrameMain extends JModelTestFrame {
+
+	private static final int HOTKEY_MODIFIER;
+	private static final long serialVersionUID = 201103171450L;
+	public static final File LOG_DIR = new File(System.getProperty("user.dir")
+			+ File.separator + "log" + File.separator);
+
+	public static JPanel Panel = new JPanel();
+	private JTabbedPane tabbedPane = new JTabbedPane();
+	private JScrollPane scrollPane = new JScrollPane();
+	private JScrollPane phymlScrollPane = new JScrollPane();
+	private JTextPane mainEditorPane = new JTextPane();
+	private JTextArea phymlEditorPane = new JTextArea();
+
+	private JPanel StatusPanel = new JPanel();
+	private JLabel LabelStatusLikelihoods = new JLabel();
+	private JLabel LabelStatusData = new JLabel();
+	private JMenuBar menuBar = new JMenuBar();
+	private JMenu menuFile = new JMenu();
+	private JMenuItem menuFileOpenDataFile = new JMenuItem();
+	private JMenuItem menuFileOpenCkpFile = new JMenuItem();
+	private JSeparator menuFileSeparator1 = new JSeparator();
+	private JMenuItem menuFileQuit = new JMenuItem();
+	private JMenu menuEdit = new JMenu();
+	private JMenuItem menuEditCut = new JMenuItem();
+	private JMenuItem menuEditCopy = new JMenuItem();
+	private JMenuItem menuEditPaste = new JMenuItem();
+	private JMenuItem menuEditSelectAll = new JMenuItem();
+	private JMenuItem menuEditClear = new JMenuItem();
+	private JMenuItem menuResultsHtmlOutput = new JMenuItem();
+	private JSeparator menuEditSeparator1 = new JSeparator();
+	private JMenuItem menuEditSaveConsole = new JMenuItem();
+	private JMenuItem menuEditPrintConsole = new JMenuItem();
+	private JSeparator menuEditSeparator2 = new JSeparator();
+	private JMenuItem menuEditPreferences = new JMenuItem();
+	private JMenu menuAnalysis = new JMenu();
+	private JMenuItem menuAnalysisCalculateLikelihoods = new JMenuItem();
+	private JSeparator menuAnalysisSeparator1 = new JSeparator();
+	private JMenuItem menuAnalysisAIC = new JMenuItem();
+	private JMenuItem menuAnalysisBIC = new JMenuItem();
+	private JMenuItem menuAnalysisDT = new JMenuItem();
+	private JMenuItem menuAnalysishLRT = new JMenuItem();
+	private JSeparator menuAnalysisSeparator2 = new JSeparator();
+	private JMenuItem menuAnalysisAveraging = new JMenuItem();
+	private JMenu menuTools = new JMenu();
+	private JMenuItem menuToolsLRT = new JMenuItem();
+	private JMenu menuHelp = new JMenu();
+	private JMenuItem menuHelpOpen = new JMenuItem();
+	private JMenu menuAbout = new JMenu();
+	private JMenuItem menuAboutModelTest = new JMenuItem();
+	private JMenuItem menuAboutWWW = new JMenuItem();
+	private JMenuItem menuHelpDiscussionGroup = new JMenuItem();
+	private JMenuItem menuAboutCredits = new JMenuItem();
+	private JSeparator menuAboutSeparator = new JSeparator();
+	private JMenu menuResults = new JMenu();
+	private JMenuItem menuResultsShowModelTable = new JMenuItem();
+
+	private JCheckBoxMenuItem menuResultsBLasParameters = new JCheckBoxMenuItem();
+
+	// variables to be acessible from local classes
+	private JMenuItem menuAIC;
+	private JMenuItem menuBIC;
+	private JMenuItem menuDT;
+	private JMenuItem menuhLRT;
+	private JMenuItem menuShowModelTable;
+	private JMenuItem menuAveraging;
+
+	static {
+		if (Utilities.findCurrentOS() == Utilities.OS_OSX) {
+			HOTKEY_MODIFIER = ActionEvent.META_MASK;
+		} else {
+			HOTKEY_MODIFIER = ActionEvent.CTRL_MASK;
+		}
+	}
+
+	public FrameMain() {
+		// LabelStatusLike = LabelStatusLikelihoods;
+
+		menuAIC = menuAnalysisAIC;
+		menuBIC = menuAnalysisBIC;
+		menuDT = menuAnalysisDT;
+		menuhLRT = menuAnalysishLRT;
+		menuShowModelTable = menuResultsShowModelTable;
+		menuAveraging = menuAnalysisAveraging;
+	}
+
+	public void initComponents() throws Exception {
+
+		menuBar.setVisible(true);
+		menuBar.setBackground(XManager.MENU_COLOR);
+		menuBar.setFont(XManager.FONT_MENU);
+
+		// menu File
+		menuFile.setVisible(true);
+		menuFile.setText("File");
+		menuFile.setBackground(XManager.MENU_COLOR);
+		menuFileOpenDataFile
+				.setToolTipText("Load a DNA alignment in sequential or interleaved Phylip format");
+		menuFileOpenDataFile
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(3, 3, 6, 3)));
+		menuFileOpenDataFile.setVisible(true);
+		menuFileOpenDataFile.setText("Load DNA alignment");
+		menuFileOpenDataFile.setAccelerator(KeyStroke.getKeyStroke(
+				KeyEvent.VK_O, HOTKEY_MODIFIER));
+
+		menuFileOpenCkpFile
+				.setToolTipText("Load a checkpoint file from a previous run");
+		menuFileOpenCkpFile
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(3, 3, 6, 3)));
+		menuFileOpenCkpFile.setVisible(true);
+		menuFileOpenCkpFile.setEnabled(false);
+		menuFileOpenCkpFile.setText("Load checkpoint file");
+
+		menuFileSeparator1
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(6, 3, 6, 3)));
+		menuFileSeparator1.setVisible(true);
+		menuFileQuit.setToolTipText("Quit jModelTest");
+		menuFileQuit.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(3, 3, 6, 3)));
+		menuFileQuit.setVisible(true);
+		menuFileQuit.setText("Quit");
+		menuFileQuit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
+				HOTKEY_MODIFIER));
+
+		// menu Edit
+		menuEdit.setVisible(true);
+		menuEdit.setText("Edit");
+		menuEdit.setBackground(XManager.MENU_COLOR);
+		menuEditCut.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(6, 3, 3, 3)));
+		menuEditCut.setVisible(true);
+		menuEditCut.setText("Cut");
+		menuEditCut.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X,
+				HOTKEY_MODIFIER));
+		menuEditCopy.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(3, 3, 3, 3)));
+		menuEditCopy.setVisible(true);
+		menuEditCopy.setText("Copy");
+		menuEditCopy.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C,
+				HOTKEY_MODIFIER));
+		menuEditPaste.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(3, 3, 3, 3)));
+		menuEditPaste.setVisible(true);
+		menuEditPaste.setText("Paste");
+		menuEditPaste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V,
+				HOTKEY_MODIFIER));
+		menuEditSelectAll.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(3, 3, 3, 3)));
+		menuEditSelectAll.setVisible(true);
+		menuEditSelectAll.setText("Select All");
+		menuEditSelectAll.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
+				HOTKEY_MODIFIER));
+		menuEditClear.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(3, 3, 6, 3)));
+		menuEditClear.setVisible(true);
+		menuEditClear.setText("Clear");
+		menuEditClear.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E,
+				HOTKEY_MODIFIER));
+		menuEditSeparator1
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(6, 3, 6, 3)));
+		menuEditSeparator1.setVisible(true);
+		menuEditSaveConsole
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(6, 3, 6, 3)));
+		menuEditSaveConsole.setVisible(true);
+		menuEditSaveConsole.setText("Save console");
+		menuEditSaveConsole.setAccelerator(KeyStroke.getKeyStroke(
+				KeyEvent.VK_S, HOTKEY_MODIFIER));
+		menuEditPrintConsole
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(6, 3, 6, 3)));
+		menuEditPrintConsole.setVisible(true);
+		menuEditPrintConsole.setText("Print console");
+		menuEditPrintConsole.setAccelerator(KeyStroke.getKeyStroke(
+				KeyEvent.VK_P, HOTKEY_MODIFIER));
+		menuEditSeparator2
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(6, 3, 6, 3)));
+		menuEditSeparator2.setVisible(true);
+		menuEditPreferences
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(6, 3, 3, 3)));
+		menuEditPreferences.setVisible(true);
+		menuEditPreferences.setText("Preferences");
+
+		// menu Analysis
+		menuAnalysis.setVisible(true);
+		menuAnalysis.setText("Analysis");
+		menuAnalysis.setBackground(XManager.MENU_COLOR);
+
+		menuAnalysisCalculateLikelihoods
+				.setToolTipText("Compute model likelihoods and parameter estimates using Phyml");
+		menuAnalysisCalculateLikelihoods
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(5, 5, 5, 5)));
+		menuAnalysisCalculateLikelihoods.setVisible(true);
+		menuAnalysisCalculateLikelihoods.setText("Compute likelihood scores");
+		menuAnalysisCalculateLikelihoods.setEnabled(false);
+		menuAnalysisCalculateLikelihoods.setAccelerator(KeyStroke.getKeyStroke(
+				KeyEvent.VK_L, HOTKEY_MODIFIER));
+		menuAnalysisSeparator1.setVisible(true);
+		menuAnalysisAIC.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(5, 5, 5, 5)));
+		menuAnalysisAIC.setText("Do AIC calculations ...");
+		menuAnalysisAIC.setVisible(true);
+		menuAnalysisAIC.setEnabled(false);
+		menuAnalysisAIC.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_I,
+				HOTKEY_MODIFIER));
+		menuAnalysisBIC.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(5, 5, 5, 5)));
+		menuAnalysisBIC.setText("Do BIC calculations ...");
+		menuAnalysisBIC.setVisible(true);
+		menuAnalysisBIC.setEnabled(false);
+		menuAnalysisBIC.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B,
+				HOTKEY_MODIFIER));
+		menuAnalysisDT.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(5, 5, 5, 5)));
+		menuAnalysisDT.setText("Do DT calculations ...");
+		menuAnalysisDT.setVisible(true);
+		menuAnalysisDT.setEnabled(false);
+		menuAnalysisDT.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_D,
+				HOTKEY_MODIFIER));
+		menuAnalysishLRT.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(5, 5, 5, 5)));
+		menuAnalysishLRT.setText("Do hLRT calculations ...");
+		menuAnalysishLRT
+				.setToolTipText("Only available when likelihoods are calculated on the same tree (i.e., models are nested)");
+		menuAnalysishLRT.setVisible(true);
+		menuAnalysishLRT.setEnabled(false);
+		menuAnalysishLRT.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,
+				HOTKEY_MODIFIER));
+
+		menuAnalysisSeparator2.setVisible(true);
+		menuAnalysisAveraging.setVisible(true);
+		menuAnalysisAveraging
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(5, 5, 5, 5)));
+		menuAnalysisAveraging.setText("Model-averaged phylogeny");
+		menuAnalysisAveraging
+				.setToolTipText("Compute a model-averaged phylogeny with the candidate models");
+		menuAnalysisAveraging.setEnabled(false);
+		menuAnalysisAveraging.setAccelerator(KeyStroke.getKeyStroke(
+				KeyEvent.VK_Z, HOTKEY_MODIFIER));
+
+		// menu Results
+		menuResults.setVisible(true);
+		menuResults.setText("Results");
+		menuResults.setBackground(XManager.MENU_COLOR);
+		menuResultsBLasParameters
+				.setToolTipText("Consider branch lengths as parameters");
+		menuResultsBLasParameters
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(3, 3, 6, 3)));
+		menuResultsBLasParameters.setEnabled(true);
+		menuResultsBLasParameters.setVisible(true);
+		menuResultsBLasParameters.setSelected(true);
+		menuResultsBLasParameters.setText("Branch lenghts are parameters");
+		menuResultsShowModelTable
+				.setToolTipText("Show table with model likelihoods and parameter estimates obtained with Phyml");
+		menuResultsShowModelTable
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(5, 5, 5, 5)));
+		menuResultsShowModelTable.setVisible(true);
+		menuResultsShowModelTable.setText("Show results table");
+		menuResultsShowModelTable.setEnabled(false);
+		menuResultsShowModelTable.setAccelerator(KeyStroke.getKeyStroke(
+				KeyEvent.VK_M, HOTKEY_MODIFIER));
+		menuResultsHtmlOutput
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(6, 3, 6, 3)));
+		menuResultsHtmlOutput.setVisible(true);
+		menuResultsHtmlOutput.setText("Build HTML log");
+		menuResultsHtmlOutput.setEnabled(false);
+		menuResultsHtmlOutput.setAccelerator(KeyStroke.getKeyStroke(
+				KeyEvent.VK_H, HOTKEY_MODIFIER));
+
+		// menu Tools
+		menuTools.setVisible(true);
+		menuTools.setText("Tools");
+		menuTools.setBackground(XManager.MENU_COLOR);
+		menuToolsLRT.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(5, 5, 5, 5)));
+		menuToolsLRT.setVisible(true);
+		menuToolsLRT.setText("LRT calculator");
+		menuToolsLRT.setEnabled(true);
+		menuToolsLRT.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_T,
+				HOTKEY_MODIFIER));
+
+		// menu Help
+		menuHelp.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(5, 5, 5, 5)));
+		menuHelp.setVisible(true);
+		menuHelp.setText("Help");
+		menuHelp.setBackground(XManager.MENU_COLOR);
+		menuHelpOpen.setVisible(true);
+		menuHelpOpen.setText("Open documentation");
+		menuHelpOpen.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(5, 5, 5, 5)));
+		menuHelpOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_K,
+				HOTKEY_MODIFIER));
+
+		// menu About
+		menuAbout.setVisible(true);
+		menuAbout.setText("About");
+		menuAbout.setBackground(XManager.MENU_COLOR);
+		menuAboutWWW.setVisible(true);
+		menuAboutWWW.setText("WWW home page");
+		menuAboutWWW.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(5, 5, 5, 5)));
+		menuAboutWWW.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W,
+				HOTKEY_MODIFIER));
+		menuHelpDiscussionGroup.setVisible(true);
+		menuHelpDiscussionGroup.setText("Discussion group");
+		menuHelpDiscussionGroup
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(5, 5, 5, 5)));
+		menuHelpDiscussionGroup.setAccelerator(KeyStroke.getKeyStroke(
+				KeyEvent.VK_G, HOTKEY_MODIFIER));
+		menuAboutCredits.setVisible(true);
+		menuAboutCredits.setText("Credits");
+		menuAboutCredits.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(5, 5, 5, 5)));
+		menuAboutCredits.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_J,
+				HOTKEY_MODIFIER));
+		menuAboutSeparator.setVisible(true);
+		menuAboutModelTest.setVisible(true);
+		menuAboutModelTest.setText("jModelTest");
+		menuAboutModelTest
+				.setBorder(new BorderUIResource.EmptyBorderUIResource(
+						new java.awt.Insets(5, 5, 5, 5)));
+		menuAboutModelTest.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F,
+				HOTKEY_MODIFIER));
+
+		Panel.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(20, 20, 20, 20)));
+		Panel.setLocation(new java.awt.Point(10, -10));
+		Panel.setVisible(true);
+		Panel.setAutoscrolls(true);
+		Panel.setLayout(new BorderLayout());
+		Panel.setBackground(null);
+
+		tabbedPane.setSize(590, 610);
+		tabbedPane.setLocation(20, 10);
+		tabbedPane.setVisible(true);
+
+		scrollPane.setVisible(true);
+		scrollPane.setAutoscrolls(true);
+
+		phymlScrollPane.setVisible(true);
+		phymlScrollPane.setAutoscrolls(true);
+		DefaultCaret caret = (DefaultCaret) phymlEditorPane.getCaret();
+		caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
+
+		mainEditorPane.setMargin(new Insets(5, 5, 5, 5));
+		mainEditorPane.setFont(XManager.FONT_CONSOLE);
+
+		mainEditorPane.setBackground(XManager.PANE_BACK_COLOR);
+		mainEditorPane.setEditable(false);
+		mainEditorPane.setSize(15, 10);
+		mainEditorPane.setAutoscrolls(true);
+		mainEditorPane.setVisible(true);
+
+		phymlEditorPane.setMargin(new Insets(5, 5, 5, 5));
+		phymlEditorPane.setFont(XManager.FONT_CONSOLE);
+
+		phymlEditorPane.setBackground(XManager.PANE_BACK_COLOR);
+		phymlEditorPane.setEditable(false);
+		phymlEditorPane.setSize(15, 10);
+		phymlEditorPane.setAutoscrolls(true);
+		phymlEditorPane.setVisible(true);
+		ModelTest.setPhymlConsole(new TextOutputStream(new PrintStream(
+				new DocumentOutputStream(phymlEditorPane.getDocument()))));
+
+		StatusPanel.setPreferredSize(new java.awt.Dimension(592, 30));
+		StatusPanel.setBorder(new BorderUIResource.EtchedBorderUIResource(1,
+				XManager.INNER_BORDER_COLOR, XManager.OUTER_BORDER_COLOR));
+		StatusPanel.setLocation(new java.awt.Point(20, 630));
+		StatusPanel.setVisible(true);
+		StatusPanel.setLayout(new BorderLayout());
+		StatusPanel.setForeground(java.awt.Color.blue);
+		StatusPanel.setBackground(XManager.STATUS_BACK_COLOR);
+		StatusPanel.setFont(XManager.FONT_STATUS);
+
+		LabelStatusLikelihoods.setSize(new java.awt.Dimension(270, 40));
+		LabelStatusLikelihoods.setVisible(true);
+		LabelStatusLikelihoods.setText("  Likelihood scores not available");
+		LabelStatusLikelihoods
+				.setToolTipText("Status of likelihood scores calculations");
+		LabelStatusLikelihoods.setForeground(XManager.LABEL_FAIL_COLOR);
+		LabelStatusLikelihoods.setFont(XManager.FONT_LABEL);
+		LabelStatusData.setSize(new java.awt.Dimension(150, 40));
+		LabelStatusData.setVisible(true);
+		LabelStatusData.setText("No data file loaded  ");
+		LabelStatusData.setToolTipText("Active current data file");
+		LabelStatusData.setForeground(XManager.LABEL_FAIL_COLOR);
+		LabelStatusData.setHorizontalAlignment(JLabel.RIGHT);
+		LabelStatusData.setFont(XManager.FONT_LABEL);
+
+		menuBar.add(menuFile);
+		menuBar.add(menuEdit);
+		menuBar.add(menuAnalysis);
+		menuBar.add(menuResults);
+		menuBar.add(menuTools);
+		menuBar.add(menuHelp);
+		menuBar.add(menuAbout);
+
+		menuFile.add(menuFileOpenDataFile);
+		menuFile.add(menuFileOpenCkpFile);
+		menuFile.add(menuFileSeparator1);
+		menuFile.add(menuFileQuit);
+
+		menuEdit.add(menuEditCut);
+		menuEdit.add(menuEditCopy);
+		menuEdit.add(menuEditPaste);
+		menuEdit.add(menuEditSelectAll);
+		menuEdit.add(menuEditClear);
+		menuEdit.add(menuEditSeparator1);
+		menuEdit.add(menuEditSaveConsole);
+		menuEdit.add(menuEditPrintConsole);
+		menuEdit.add(menuEditSeparator2);
+		menuEdit.add(menuEditPreferences);
+
+		menuAnalysis.add(menuAnalysisCalculateLikelihoods);
+		menuAnalysis.add(menuAnalysisSeparator1);
+		menuAnalysis.add(menuAnalysisAIC);
+		menuAnalysis.add(menuAnalysisBIC);
+		menuAnalysis.add(menuAnalysisDT);
+		menuAnalysis.add(menuAnalysishLRT);
+		menuAnalysis.add(menuAnalysisSeparator2);
+		menuAnalysis.add(menuAnalysisAveraging);
+
+		// menuResults.add(menuResultsBLasParameters);
+		menuResults.add(menuResultsShowModelTable);
+		menuResults.add(menuResultsHtmlOutput);
+
+		menuHelp.add(menuHelpOpen);
+		menuHelp.add(menuHelpDiscussionGroup);
+
+		menuAbout.add(menuAboutWWW);
+		menuAbout.add(menuAboutCredits);
+		menuAbout.add(menuAboutSeparator);
+		menuAbout.add(menuAboutModelTest);
+
+		menuTools.add(menuToolsLRT);
+
+		tabbedPane.addTab("Main", scrollPane);
+		tabbedPane.addTab("PhyML-log", phymlScrollPane);
+		Panel.add(tabbedPane, BorderLayout.CENTER);
+		Panel.add(StatusPanel, BorderLayout.PAGE_END);
+		scrollPane.getViewport().add(mainEditorPane);
+		phymlScrollPane.getViewport().add(phymlEditorPane);
+		StatusPanel.add(LabelStatusLikelihoods, BorderLayout.LINE_START);
+		StatusPanel.add(LabelStatusData, BorderLayout.LINE_END);
+
+		setLayout(new BorderLayout());
+		getContentPane().add(Panel);
+
+		setLocation(XManager.MAIN_LOCATION);
+		setJMenuBar(menuBar);
+		// getContentPane().setLayout(null);
+		getContentPane().setLayout(new BorderLayout());
+		setTitle("jModelTest " + ModelTest.CURRENT_VERSION);
+		setSize(new java.awt.Dimension(630, 695));
+		setResizable(true);
+
+		// event handling
+		menuFileOpenDataFile
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuFileOpenDataFileActionPerformed(e);
+					}
+				});
+
+		menuFileOpenCkpFile
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuFileOpenCkpFileActionPerformed(e);
+					}
+				});
+
+		menuFileQuit.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuFileQuitActionPerformed(e);
+			}
+		});
+
+		menuEditPreferences
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuEditPreferencesActionPerformed(e);
+					}
+				});
+
+		menuEditCut.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuEditCutActionPerformed(e);
+			}
+		});
+		menuEditCopy.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuEditCopyActionPerformed(e);
+			}
+		});
+		menuEditPaste.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuEditPasteActionPerformed(e);
+			}
+		});
+		menuEditClear.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuEditClearActionPerformed(e);
+			}
+		});
+		menuEditSelectAll
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuEditSelectAllActionPerformed(e);
+					}
+				});
+		menuEditSaveConsole
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuEditSaveConsoleActionPerformed(e);
+					}
+				});
+		menuEditPrintConsole
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuEditPrintConsoleActionPerformed(e);
+					}
+				});
+
+		menuResultsHtmlOutput
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuResultsHtmlOutputActionPerformed(e);
+					}
+				});
+
+		menuResultsShowModelTable
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuResultsShowModelTableActionPerformed(e);
+					}
+				});
+
+		menuAnalysisCalculateLikelihoods
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuAnalysisCalculateLikelihoodsActionPerformed(e);
+					}
+				});
+		menuAnalysisAIC.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuAnalysisAICActionPerformed(e);
+			}
+		});
+		menuAnalysisBIC.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuAnalysisBICActionPerformed(e);
+			}
+		});
+		menuAnalysisDT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuAnalysisDTActionPerformed(e);
+			}
+		});
+		menuAnalysishLRT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuAnalysishLRTActionPerformed(e);
+			}
+		});
+
+		menuAnalysisAveraging
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuAnalysisAveragingActionPerformed(e);
+					}
+				});
+
+		menuToolsLRT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuToolsLRTActionPerformed(e);
+			}
+		});
+
+		menuHelpOpen.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuHelpOpenActionPerformed(e);
+			}
+		});
+
+		menuAboutWWW.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuAboutWWWActionPerformed(e);
+			}
+		});
+
+		menuHelpDiscussionGroup
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuAboutDiscussionGroupActionPerformed(e);
+					}
+				});
+
+		menuAboutCredits.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				menuAboutCreditsActionPerformed(e);
+			}
+		});
+
+		menuAboutModelTest
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						menuAboutModelTestActionPerformed(e);
+					}
+				});
+
+		addWindowListener(new java.awt.event.WindowAdapter() {
+			public void windowClosing(java.awt.event.WindowEvent e) {
+				thisWindowClosing(e);
+			}
+		});
+
+		// END GENERATED CODE
+
+		// we need this to have the panel resizing with the frame
+		setContentPane(Panel);
+
+	}
+
+	private boolean mShown = false;
+
+	public void addNotify() {
+		super.addNotify();
+
+		if (mShown)
+			return;
+
+		// resize frame to account for menubar
+		JMenuBar jMenuBar = getJMenuBar();
+		if (jMenuBar != null) {
+			int jMenuBarHeight = jMenuBar.getPreferredSize().height;
+			Dimension dimension = getSize();
+			dimension.height += jMenuBarHeight;
+			setSize(dimension);
+
+			// move down components in layered pane
+			Component[] components = getLayeredPane().getComponentsInLayer(
+					JLayeredPane.DEFAULT_LAYER.intValue());
+			for (int i = 0; i < components.length; i++) {
+				Point location = components[i].getLocation();
+				location.move(location.x, location.y + jMenuBarHeight);
+				components[i].setLocation(location);
+			}
+		}
+
+		mShown = true;
+	}
+
+	// Close the window when the close box is clicked
+	private void thisWindowClosing(java.awt.event.WindowEvent e) {
+		setVisible(false);
+		dispose();
+		System.exit(0);
+	}
+
+	private void menuFileOpenDataFileActionPerformed(
+			java.awt.event.ActionEvent e) {
+
+		JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));
+		fc.setFileFilter(new FileNameExtensionFilter("Sequence alignment (*.phy, *.fas, *.nex)", "phy", "fas", "nex"));
+		
+		int returnVal = fc.showOpenDialog(this);
+
+		File inputFile = null;
+        if (returnVal == JFileChooser.APPROVE_OPTION) {
+        	inputFile = fc.getSelectedFile();
+        }   
+
+		if (inputFile != null) // menu not canceled
+		{
+			ModelTest.getMainConsole().print(
+					"Reading data file \"" + inputFile.getName() + "\"...");
+
+			if (inputFile.exists()) // file exists
+			{
+				options.setInputFile(inputFile);
+				try {
+					String alnStr = ModelTestService.readAlignment(inputFile,
+							options.getAlignmentFile());
+
+					PushbackReader pr = new PushbackReader(
+							new StringReader(alnStr));
+					options.setAlignment(AlignmentReader
+							.createAlignment(new PrintWriter(System.err), pr, true));
+
+					LabelStatusData.setText(inputFile.getName() + "  ");
+					LabelStatusData.setForeground(new java.awt.Color(102, 102,
+							153));
+					menuAnalysisCalculateLikelihoods.setEnabled(true);
+					enableMenuShowModelTable(false);
+					enableMenuHtmlOutput(false);
+					ModelTest.getMainConsole().println(" OK.");
+					ModelTest.getMainConsole().println(
+							"  number of sequences: " + options.getNumTaxa());
+					ModelTest.getMainConsole().println(
+							"  number of sites: " + options.getNumSites());
+					menuFileOpenCkpFile.setEnabled(true);
+				} catch (Exception e1) {
+					JOptionPane.showMessageDialog(this, "The specified file \""
+							+ inputFile.getAbsolutePath()
+							+ "\" cannot be read as an alignment",
+							"jModelTest error", JOptionPane.ERROR_MESSAGE);
+					ModelTest.getMainConsole().println(" failed.\n");
+					menuFileOpenCkpFile.setEnabled(false);
+				}
+			} else {
+				JOptionPane.showMessageDialog(this, "The specified file \""
+						+ inputFile.getAbsolutePath() + "\" cannot be found",
+						"jModelTest error", JOptionPane.ERROR_MESSAGE);
+				ModelTest.getMainConsole().println(" failed.\n");
+				menuFileOpenCkpFile.setEnabled(false);
+			}
+		}
+		
+	}
+
+	private void menuFileOpenCkpFileActionPerformed(java.awt.event.ActionEvent e) {
+		
+		JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));
+		fc.setFileFilter(new FileNameExtensionFilter("jModelTest checkpoint (*.ckp)", "ckp"));
+		
+		int returnVal = fc.showOpenDialog(this);
+
+		File file = null;
+        if (returnVal == JFileChooser.APPROVE_OPTION) {
+            file = fc.getSelectedFile();
+        }        
+
+		if (file != null) // menu not canceled
+		{
+			ModelTest.getMainConsole().print(
+					"Loading checkpoint from \"" + file.getName() + "\"...");
+
+			if (file.exists()) // file exists
+			{
+				ModelTest.loadCheckpoint(file);
+			} else {
+				JOptionPane.showMessageDialog(this, "The specified file \""
+						+ file.getName() + "\" cannot be found",
+						"jModelTest error", JOptionPane.ERROR_MESSAGE);
+				ModelTest.getMainConsole().println(" failed.\n");
+			}
+		}
+		
+	}
+
+	private void menuFileQuitActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			dispose();
+			System.exit(0);
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuEditCutActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			mainEditorPane.cut();
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuEditPreferencesActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			XManager.getInstance().loadFramePreferences();
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuEditCopyActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			mainEditorPane.copy();
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuEditPasteActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			mainEditorPane.paste();
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuEditSelectAllActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			mainEditorPane.selectAll();
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	public void initPanelInfo() {
+		try {
+			mainEditorPane.setText("");
+			ModelTest.printHeader(ModelTest.getMainConsole());
+			ModelTest.printNotice(ModelTest.getMainConsole());
+			ModelTest.printCitation(ModelTest.getMainConsole());
+			
+			// Check binary
+        	if (!ModelTestConfiguration.isGlobalPhymlBinary()) {
+				if (!RunPhyml.phymlBinary.exists()) {
+					Utilities
+					.printRed("ERROR: PhyML binary cannot be found: " + RunPhyml.phymlBinary.getAbsolutePath());
+				} else if (!RunPhyml.phymlBinary.canExecute()) {
+					Utilities
+					.printRed("ERROR: PhyML binary exists, but it cannot be executed: " + RunPhyml.phymlBinary.getAbsolutePath());
+				}
+			}
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+	
+	public void menuEditClearActionPerformed(java.awt.event.ActionEvent e) {
+		initPanelInfo();
+	}
+
+	private void menuEditSaveConsoleActionPerformed(java.awt.event.ActionEvent e) {
+		FileDialog dialog;
+		try {
+			try {
+				dialog = new FileDialog(this,
+						"Open file to save console results", FileDialog.SAVE);
+				dialog.setFile(options.getInputFile().getName()
+						+ ".jmodeltest.console");
+				dialog.setVisible(true);
+			} catch (Throwable f) {
+				JOptionPane.showMessageDialog(this,
+						"It appears your VM does not allow file saving",
+						"jModelTest error", JOptionPane.ERROR_MESSAGE);
+				return;
+			}
+
+			if (dialog.getFile() != null) /* a file was selected */
+			{
+				String sname = dialog.getFile();
+				File sfile = new File(dialog.getDirectory() + sname);
+				FileOutputStream fos = new FileOutputStream(sfile);
+				PrintWriter pw = new PrintWriter(fos);
+				mainEditorPane.write(pw);
+				pw.close();
+			}
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuEditPrintConsoleActionPerformed(
+			java.awt.event.ActionEvent e) {
+		try {
+			PrintUtilities.printComponent(mainEditorPane);
+			// mainEditorPane.print(mainEditorPane.getGraphics());
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuResultsHtmlOutputActionPerformed(
+			java.awt.event.ActionEvent e) {
+
+		FileDialog dialog;
+		try {
+			try {
+				dialog = new FileDialog(this, "Open file to save HTML log",
+						FileDialog.SAVE);
+				dialog.setFile(options.getInputFile().getName()
+						+ ".jmodeltest.html");
+				dialog.setDirectory("log");
+				dialog.setVisible(true);
+			} catch (Throwable f) {
+				JOptionPane.showMessageDialog(this,
+						"It appears your VM does not allow file saving",
+						"jModelTest error", JOptionPane.ERROR_MESSAGE);
+				return;
+			}
+
+			if (!dialog.getDirectory().equals(
+					LOG_DIR.getAbsolutePath() + File.separator)) {
+				Utilities
+						.printRed("\nWarning: If you save the log files out from the log directory, make sure to copy the \"log"
+								+ File.separator
+								+ "resources\" folder with the log file\n");
+			}
+
+			if (dialog.getFile() != null
+					&& ModelTestConfiguration.isHtmlLogEnabled()) /*
+																 * a file was
+																 * selected
+																 */
+			{
+				Tree bestAIC = ModelTest.getMinAIC() != null ? ModelTest
+						.getMinAIC().getTree() : null;
+				Tree bestAICc = ModelTest.getMinAICc() != null ? ModelTest
+						.getMinAICc().getTree() : null;
+				Tree bestBIC = ModelTest.getMinBIC() != null ? ModelTest
+						.getMinBIC().getTree() : null;
+				Tree bestDT = ModelTest.getMinDT() != null ? ModelTest
+						.getMinDT().getTree() : null;
+
+				TreeSummary treeSummary = new TreeSummary(bestAIC, bestAICc,
+						bestBIC, bestDT, ModelTest.getCandidateModels());
+
+				HtmlReporter.buildReport(options,
+						ModelTest.getCandidateModels(),
+						new File(dialog.getDirectory() + dialog.getFile()),
+						treeSummary);
+			}
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuResultsShowModelTableActionPerformed(
+			java.awt.event.ActionEvent e) {
+		try {
+			XManager.getInstance().resultsFrame.setVisible(true);
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuAnalysisCalculateLikelihoodsActionPerformed(
+			java.awt.event.ActionEvent e) {
+		boolean err = !ModelTestConfiguration.isGlobalPhymlBinary() && (!RunPhyml.phymlBinary.exists() || !RunPhyml.phymlBinary.canExecute());
+
+    	if (!err) {
+			try {
+				Frame_CalcLike Likeframe = new Frame_CalcLike();
+				Likeframe.initComponents();
+				InitialFocusSetter.setInitialFocus(Likeframe,
+						Likeframe.RunButtonCalcLike);
+				Likeframe.setVisible(true);
+			} catch (Exception f) {
+				f.printStackTrace();
+			}
+		}
+	}
+
+	private void menuAnalysisAICActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			Frame_AIC AICframe = new Frame_AIC();
+			AICframe.initComponents();
+			AICframe.setVisible(true);
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuAnalysisBICActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			Frame_BIC BICframe = new Frame_BIC();
+			BICframe.initComponents();
+			BICframe.setVisible(true);
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuAnalysisDTActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			Frame_DT DTframe = new Frame_DT();
+			DTframe.initComponents();
+			DTframe.setVisible(true);
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuAnalysishLRTActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			Frame_hLRT hLRTframe = new Frame_hLRT();
+			hLRTframe.initComponents();
+			hLRTframe.setVisible(true);
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuAnalysisAveragingActionPerformed(
+			java.awt.event.ActionEvent e) {
+		try {
+			Frame_Consense consenseFrame = new Frame_Consense();
+			consenseFrame.initComponents();
+			consenseFrame.setVisible(true);
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuToolsLRTActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			Frame_LRTcalculator LRTframe = new Frame_LRTcalculator();
+			LRTframe.initComponents();
+			LRTframe.setVisible(true);
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuHelpOpenActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			if (Desktop.isDesktopSupported()) {
+				Desktop desktop = Desktop.getDesktop();
+				URI wikiURI = new URI(ModelTest.WIKI);
+				desktop.browse(wikiURI);
+			} else {
+				BrowserLauncher launcher = new BrowserLauncher();
+				launcher.openURLinBrowser(ModelTest.WIKI);
+			}
+		} catch (Exception f) {
+			JOptionPane.showMessageDialog(new JFrame(), f.getMessage(),
+					"Error loading webpage", JOptionPane.ERROR_MESSAGE);
+		}
+	}
+
+	private void menuAboutDiscussionGroupActionPerformed(
+			java.awt.event.ActionEvent e) {
+		try {
+			if (Desktop.isDesktopSupported()) {
+				Desktop desktop = Desktop.getDesktop();
+				URI groupURI = new URI(ModelTest.DISCUSSION_GROUP);
+				desktop.browse(groupURI);
+			} else {
+				BrowserLauncher launcher = new BrowserLauncher();
+				launcher.openURLinBrowser(ModelTest.DISCUSSION_GROUP);
+			}
+		} catch (Exception f) {
+			JOptionPane.showMessageDialog(new JFrame(), f.getMessage(),
+					"Error loading webpage", JOptionPane.ERROR_MESSAGE);
+		}
+	}
+
+	private void menuAboutWWWActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			if (Desktop.isDesktopSupported()) {
+				Desktop desktop = Desktop.getDesktop();
+				URI jModelTestURI = new URI(ModelTest.URL);
+				desktop.browse(jModelTestURI);
+			} else {
+				BrowserLauncher launcher = new BrowserLauncher();
+				launcher.openURLinBrowser(ModelTest.URL);
+			}
+		} catch (Exception f) {
+			JOptionPane.showMessageDialog(new JFrame(), f.getMessage(),
+					"Error loading webpage", JOptionPane.ERROR_MESSAGE);
+		}
+	}
+
+	private void menuAboutCreditsActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			String credits = "Likelihood calculations with Phyml by Stephane Guindon et al.\n";
+			credits += "Alignment conversion with ALTER by Daniel Glez-Peña et al.\n";
+			credits += "Phylogenetic trees management with PAL: Phylogenetic Analysis Library by A. Drummond and K. Strimmer\n";
+			credits += "Table utilities by Philip Milne\n";
+			credits += "BrowserLauncher by Eric Albert and Jeff Chapman\n";
+
+			JOptionPane.showMessageDialog(new JFrame(), credits,
+					"jModelTest - CREDITS", JOptionPane.INFORMATION_MESSAGE,
+					XManager.makeIcon("JMT48", "JMT2"));
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void menuAboutModelTestActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			String about = "jModelTest " + ModelTest.CURRENT_VERSION + "\n";
+			about += "(c) 2011-onwards D.Darriba, G.L.Taboada, R.Doallo and D.Posada\n";
+			about += "Department of Biochemistry, Genetics and Immunology\n";
+			about += "University of Vigo, 36310 Vigo, Spain.\n";
+			about += "Department of Electronics and Systems\n";
+			about += "University of A Coruna, 15071 A Coruna, Spain.\n";
+			about += "e-mail: ddarriba at udc.es, dposada at uvigo.es\n\n";
+			about += "Citation: Darriba D, Taboada GL, Doallo R and Posada D. 2012.\n"
+					+ "\"jModelTest 2: more models, new heuristics and parallel computing\".\n"
+					+ "Nature Methods 9(8), 772.\n";
+			JOptionPane.showMessageDialog(new JFrame(), about, "jModelTest",
+					JOptionPane.INFORMATION_MESSAGE,
+					XManager.makeIcon("JMT48", "JMT2"));
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	public JTextPane getMainEditorPane() {
+		return mainEditorPane;
+	}
+
+	public void setLikeLabelText(String text) {
+		LabelStatusLikelihoods.setText(text);
+	}
+
+	public void setLikeLabelColor(Color color) {
+		LabelStatusLikelihoods.setForeground(color);
+	}
+
+	public void setDataLabelText(String text) {
+		LabelStatusData.setText(text);
+	}
+
+	public void enableMenuAIC(boolean enabled) {
+		menuAIC.setEnabled(enabled);
+	}
+
+	public void enableMenuBIC(boolean enabled) {
+		menuBIC.setEnabled(enabled);
+	}
+
+	public void enableMenuDT(boolean enabled) {
+		menuDT.setEnabled(enabled);
+	}
+
+	public void enableMenuhLRT(boolean enabled) {
+		menuhLRT.setEnabled(enabled);
+	}
+
+	public void enableMenuAveraging(boolean enabled) {
+		menuAveraging.setEnabled(enabled);
+	}
+
+	public void enableMenuShowModelTable(boolean enabled) {
+		menuShowModelTable.setEnabled(enabled);
+	}
+
+	public void enableMenuHtmlOutput(boolean enabled) {
+		menuResultsHtmlOutput.setEnabled(enabled);
+	}
+
+	public void selectedMenuResultsBLasParameters(boolean selected) {
+		menuResultsBLasParameters.setSelected(selected);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/FramePreferences.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/FramePreferences.java
new file mode 100644
index 0000000..c075c25
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/FramePreferences.java
@@ -0,0 +1,341 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.FileDialog;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Properties;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.WindowConstants;
+import javax.swing.border.LineBorder;
+import javax.swing.plaf.BorderUIResource;
+import javax.swing.plaf.BorderUIResource.TitledBorderUIResource;
+
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.ModelTestConfiguration;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class FramePreferences extends JModelTestFrame {
+
+	private static final int WINDOW_WIDTH = 500;
+	private static final int OUTER_MARGIN = 10;
+	private static final int MARGIN = 20;
+	private static final int COMPONENTS_WIDTH = WINDOW_WIDTH - 2 * OUTER_MARGIN;
+	private static final int COMPONENTS_HEIGHT = 20;
+	private static final int MAX_INNER_WIDTH = COMPONENTS_WIDTH - 2 * MARGIN;
+	private static final int BINARIES_PANEL_HEIGHT = MARGIN + 6
+			* COMPONENTS_HEIGHT + OUTER_MARGIN;
+	private static final int BUTTONS_RESET_WIDTH = 140;
+	private static final int BUTTONS_WIDTH = 110;
+	private static final int BUTTONS_HEIGHT = 40;
+	private static final int BUTTONS_PADDING = 10;
+	private static final int BUTTONS_PANEL_WIDTH = BUTTONS_RESET_WIDTH + 2 * BUTTONS_WIDTH + 2 * BUTTONS_PADDING;
+	private static final int BUTTONS_VLOC = BINARIES_PANEL_HEIGHT;
+	private static final int BUTTONS_HLOC = (COMPONENTS_WIDTH - BUTTONS_PANEL_WIDTH)/2;
+	private static final int WINDOW_HEIGHT = 250;
+	private static final long serialVersionUID = 1L;
+	private static final String BACKUP_FILE = ModelTest.CONFIG_FILE + ".bk";
+
+	private static final String BINARIES_COMMENT = "Set the phyml binary directory. The selected directory "
+			+ "should exist and contain a valid phyml binary (\"phyml\" or \""+ Utilities.getBinaryVersion()+"\"). If Global "
+			+ "Phyml checkbox is selected, \"phyml\" should exist in the path.";
+
+	private static final String PROPERTIES_COMMENT = "This properties file was modified from "
+			+ "jModelTest 2 GUI. A backup of the original configuration file has been "
+			+ "stored in "
+			+ BACKUP_FILE
+			+ ". Replace this file with the backup for "
+			+ "restoring the original format.";
+
+	private JTextArea tfBinaryDescription = new JTextArea();
+	private JCheckBox cbGlobalPhyml = new JCheckBox();
+	private JLabel lbPathToPhyml = new JLabel();
+	private JTextField tfPathToPhyml = new JTextField();
+	private JPanel binarySettingsPanel = new JPanel();
+	private JPanel buttonsPanel = new JPanel();
+	private JPanel preferencesPanel = new JPanel();
+	private JButton btnSetDefault = new JButton();
+	private JButton btnAccept = new JButton();
+	private JButton btnCancel = new JButton();
+	private JButton btnOpen;
+
+	public FramePreferences() {
+		initComponents();
+	}
+
+	public void initComponents() {
+
+		preferencesPanel.setLocation(0, 0);
+		preferencesPanel.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
+		preferencesPanel.setVisible(true);
+		preferencesPanel.setLayout(null);
+
+		binarySettingsPanel.setLocation(OUTER_MARGIN, OUTER_MARGIN);
+		binarySettingsPanel.setSize(COMPONENTS_WIDTH, BINARIES_PANEL_HEIGHT);
+		binarySettingsPanel
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false),
+						"PhyML Binaries Settings", TitledBorderUIResource.LEFT,
+						TitledBorderUIResource.TOP, XManager.FONT_LABEL,
+						XManager.LABEL_BLUE_COLOR));
+		binarySettingsPanel.setVisible(true);
+		binarySettingsPanel.setLayout(null);
+
+		buttonsPanel.setLocation(BUTTONS_HLOC, BUTTONS_VLOC);
+		buttonsPanel.setSize(COMPONENTS_WIDTH, BINARIES_PANEL_HEIGHT);
+		buttonsPanel.setVisible(true);
+		buttonsPanel.setLayout(null);
+
+		tfBinaryDescription.setVisible(true);
+		tfBinaryDescription.setEditable(false);
+		tfBinaryDescription.setOpaque(false);
+		tfBinaryDescription.setForeground(XManager.DARK_GRAY_COLOR);
+		tfBinaryDescription.setSize(MAX_INNER_WIDTH, 3 * COMPONENTS_HEIGHT);
+		tfBinaryDescription.setLocation(MARGIN, MARGIN);
+		tfBinaryDescription.setText(BINARIES_COMMENT);
+		tfBinaryDescription.setFont(XManager.FONT_LABEL);
+		tfBinaryDescription.setLineWrap(true);
+		tfBinaryDescription.setWrapStyleWord(true);
+
+		cbGlobalPhyml.setVisible(true);
+		cbGlobalPhyml.setSize(MAX_INNER_WIDTH, COMPONENTS_HEIGHT);
+		cbGlobalPhyml.setText("Use global PhyML binary");
+		cbGlobalPhyml.setLocation(MARGIN, 3 * COMPONENTS_HEIGHT + MARGIN);
+		cbGlobalPhyml.setFont(XManager.FONT_LABEL);
+
+		lbPathToPhyml.setVisible(true);
+		lbPathToPhyml.setSize(120, COMPONENTS_HEIGHT);
+		lbPathToPhyml.setText("PhyML binary path:");
+		lbPathToPhyml.setLocation(2 * MARGIN, MARGIN + 4 * COMPONENTS_HEIGHT);
+		lbPathToPhyml.setFont(XManager.FONT_LABEL);
+
+		tfPathToPhyml.setVisible(true);
+		tfPathToPhyml.setSize(280, COMPONENTS_HEIGHT);
+		tfPathToPhyml.setLocation(2 * MARGIN + 120, MARGIN + 4 * COMPONENTS_HEIGHT);
+		tfPathToPhyml.setFont(XManager.FONT_LABEL);
+		
+		btnOpen = XManager.makeIconButton("Open16", "Explore", "...");
+		btnOpen.setLocation(2 * MARGIN + 400, MARGIN + 4 * COMPONENTS_HEIGHT);
+		
+		btnSetDefault.setText("Default Settings");
+		btnSetDefault.setLocation(0, MARGIN);
+		btnSetDefault.setSize(BUTTONS_RESET_WIDTH, BUTTONS_HEIGHT);
+		btnSetDefault.setVisible(true);
+
+		btnCancel.setText("Cancel");
+		btnCancel.setLocation(BUTTONS_RESET_WIDTH+BUTTONS_PADDING, MARGIN);
+		btnCancel.setSize(BUTTONS_WIDTH, BUTTONS_HEIGHT);
+		btnCancel.setVisible(true);
+
+		btnAccept.setText("Accept");
+		btnAccept.setLocation(BUTTONS_RESET_WIDTH + BUTTONS_WIDTH+2*BUTTONS_PADDING, MARGIN);
+		btnAccept.setSize(BUTTONS_WIDTH, BUTTONS_HEIGHT);
+		btnAccept.setVisible(true);
+		
+		setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
+		setResizable(false);
+		binarySettingsPanel.add(tfBinaryDescription);
+		binarySettingsPanel.add(tfPathToPhyml);
+		binarySettingsPanel.add(btnOpen);
+		binarySettingsPanel.add(cbGlobalPhyml);
+		binarySettingsPanel.add(lbPathToPhyml);
+		buttonsPanel.add(btnSetDefault);
+		buttonsPanel.add(btnAccept);
+		buttonsPanel.add(btnCancel);
+
+		preferencesPanel.add(binarySettingsPanel);
+		preferencesPanel.add(buttonsPanel);
+
+		getContentPane().setLayout(null);
+		getContentPane().add(preferencesPanel);
+		setTitle("Preferences");
+		setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+		setLocation(XManager.MAIN_LOCATION);
+		getRootPane().setDefaultButton(btnAccept);
+		setStatus();
+
+		cbGlobalPhyml.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				globalPhymlActionPerformed(e);
+			}
+		});
+
+		btnSetDefault.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				cbGlobalPhyml
+						.setSelected(ModelTestConfiguration.DEFAULT_GLOBAL_PHYML);
+				tfPathToPhyml.setText(ModelTestConfiguration.DEFAULT_EXE_DIR);
+				tfPathToPhyml.setEnabled(!cbGlobalPhyml.isSelected());
+			}
+		});
+
+		btnCancel.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				cancelActionPerformed(e);
+			}
+		});
+
+		btnAccept.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				acceptActionPerformed(e);
+			}
+		});
+		
+		btnOpen.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				exploreActionPerformed(e);
+			}
+		});
+
+	}
+
+	private void setStatus() {
+		cbGlobalPhyml.setSelected(ModelTestConfiguration.isGlobalPhymlBinary());
+		tfPathToPhyml.setText(ModelTestConfiguration.getExeDir());
+		tfPathToPhyml.setEnabled(!cbGlobalPhyml.isSelected());
+	}
+
+	private void cancelActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			setStatus();
+			setVisible(false);
+			dispose();
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void acceptActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			// validate changes
+			boolean validated = true;
+			if (!cbGlobalPhyml.isSelected()) {
+				File testBinDir = new File(tfPathToPhyml.getText());
+				if (validated = (testBinDir.exists() && testBinDir
+						.isDirectory())) {
+					String path = tfPathToPhyml.getText();
+					if (!path.endsWith(File.separator)) {
+						path += File.separator;
+					}
+					File localExe = new File(path
+							+ Utilities.getBinaryVersion());
+					File genericExe = new File(path + "phyml");
+					validated = (localExe.exists() && localExe.isFile() && localExe
+							.canExecute())
+							|| (genericExe.exists() && genericExe.isFile() && genericExe
+									.canExecute());
+				}
+			}
+			if (validated) {
+				// update properties file
+				Properties properties = ModelTestConfiguration.getProperties();
+				properties.setProperty(ModelTestConfiguration.EXE_DIR,
+						tfPathToPhyml.getText());
+				properties.setProperty(ModelTestConfiguration.GLOBAL_PHYML_EXE,
+						cbGlobalPhyml.isSelected() ? "true" : "false");
+				writeProperties();
+
+				setVisible(false);
+				dispose();
+			} else {
+				JOptionPane
+						.showMessageDialog(
+								this,
+								"There is no phyml binary in the selected location. \n"
+										+ "Please make sure that exists an executable file named\n"
+										+ "\"phyml\" or "
+										+ Utilities.getBinaryVersion() + ".",
+								"jModelTest error", JOptionPane.ERROR_MESSAGE);
+				return;
+			}
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void globalPhymlActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			tfPathToPhyml.setEnabled(!cbGlobalPhyml.isSelected());
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+	
+	private void exploreActionPerformed(java.awt.event.ActionEvent e) {
+		FileDialog dialog;
+		try {
+			try {
+				dialog = new FileDialog(this, "Select PhyML binaries directory",
+						FileDialog.LOAD);
+				dialog.setDirectory(ModelTestConfiguration.DEFAULT_EXE_DIR);
+				dialog.setVisible(true);
+			} catch (Throwable f) {
+				f.printStackTrace();
+				return;
+			}
+
+			tfPathToPhyml.setText(dialog.getDirectory());
+
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void writeProperties() {
+		Properties properties = ModelTestConfiguration.getProperties();
+		try {
+			File bkFile = new File(BACKUP_FILE);
+			if (!bkFile.exists()) {
+				File propertiesFile = new File(ModelTest.CONFIG_FILE);
+				InputStream in = new FileInputStream(propertiesFile);
+				OutputStream out = new FileOutputStream(bkFile);
+				byte[] buf = new byte[1024];
+				int len;
+				while ((len = in.read(buf)) > 0) {
+					out.write(buf, 0, len);
+				}
+				in.close();
+				out.close();
+			}
+			// Escribier en el archivo los cambios
+			FileOutputStream fos = new FileOutputStream(
+					ModelTest.CONFIG_FILE.replace("\\", "/"));
+
+			properties.store(fos, PROPERTIES_COMMENT);
+
+		} catch (FileNotFoundException e) {
+			System.out.println(e.getMessage());
+		} catch (IOException e) {
+			System.out.println(e.getMessage());
+		}
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/FrameResults.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/FrameResults.java
new file mode 100644
index 0000000..da544dd
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/FrameResults.java
@@ -0,0 +1,352 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.Point;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import javax.swing.JTable;
+import javax.swing.table.TableColumn;
+
+import es.uvigo.darwin.jmodeltest.utilities.MyTableCellRenderer;
+import es.uvigo.darwin.jmodeltest.utilities.MyTableModel;
+import es.uvigo.darwin.jmodeltest.utilities.TableSorter;
+
+public class FrameResults extends JModelTestFrame {
+
+	public static final int TAB_AIC = 1;
+	public static final int TAB_AICc = 2;
+	public static final int TAB_BIC = 3;
+	public static final int TAB_DT = 4;
+	
+	private static final Dimension TABBED_PANE_DIM = new Dimension(700+100, 400-20);
+	private static final Dimension SCROLL_PANE_DIM = new Dimension(670+100, 320);
+	private static final Dimension PANEL_INFO_DIM = new Dimension(700+100, 30);
+	private static final Dimension LABEL_INFO_DIM = new Dimension(680+100, 20);
+	private static final Dimension LABEL_DATE_DIM = new Dimension(200+100, 20);
+	private static final Dimension FRAME_DIM = new Dimension(700+100, 460);
+	
+	private static final long serialVersionUID = 7368405541555631433L;
+
+	private javax.swing.JPanel panelInfo = new javax.swing.JPanel();
+	private javax.swing.JLabel labelInfo = new javax.swing.JLabel();
+	private javax.swing.JLabel labelDate = new javax.swing.JLabel();
+	private javax.swing.JTabbedPane tabbedPane = new javax.swing.JTabbedPane();
+	private javax.swing.JPanel panelModels = new javax.swing.JPanel();
+	private javax.swing.JScrollPane scrollPaneModels = new javax.swing.JScrollPane();
+	private javax.swing.JTable tableModels = new javax.swing.JTable();
+	private javax.swing.JPanel panelAIC = new javax.swing.JPanel();
+	private javax.swing.JScrollPane scrollPaneAIC = new javax.swing.JScrollPane();
+	private javax.swing.JTable tableAIC = new javax.swing.JTable();
+	private javax.swing.JPanel panelAICc = new javax.swing.JPanel();
+	private javax.swing.JScrollPane scrollPaneAICc = new javax.swing.JScrollPane();
+	private javax.swing.JTable tableAICc = new javax.swing.JTable();
+	private javax.swing.JPanel panelBIC = new javax.swing.JPanel();
+	private javax.swing.JScrollPane scrollPaneBIC = new javax.swing.JScrollPane();
+	private javax.swing.JTable tableBIC = new javax.swing.JTable();
+	private javax.swing.JPanel panelDT = new javax.swing.JPanel();
+	private javax.swing.JScrollPane scrollPaneDT = new javax.swing.JScrollPane();
+	private  javax.swing.JTable tableDT = new javax.swing.JTable();
+
+	private  MyTableModel modelModels = new MyTableModel("Model", options.getNumModels());
+	TableSorter sorterModels = new TableSorter(modelModels);
+	JTable tempTableModels = new JTable(sorterModels);
+
+	private MyTableModel modelAIC = new MyTableModel("AIC", options.getNumModels());
+	TableSorter sorterAIC = new TableSorter(modelAIC);
+	JTable tempTableAIC = new JTable(sorterAIC);
+	MyTableCellRenderer AICRenderer = new MyTableCellRenderer(tempTableAIC,"AIC"); 
+
+	private MyTableModel modelAICc = new MyTableModel("AICc", options.getNumModels());
+	TableSorter sorterAICc = new TableSorter(modelAICc);
+	JTable tempTableAICc = new JTable(sorterAICc);
+	MyTableCellRenderer AICcRenderer = new MyTableCellRenderer(tempTableAICc,"AICc"); 
+
+	private MyTableModel modelBIC = new MyTableModel("BIC", options.getNumModels());
+	TableSorter sorterBIC = new TableSorter(modelBIC);
+	JTable tempTableBIC = new JTable(sorterBIC);
+	MyTableCellRenderer BICRenderer = new MyTableCellRenderer(tempTableBIC,"BIC"); 
+	
+	private MyTableModel modelDT = new MyTableModel("DT", options.getNumModels());
+	TableSorter sorterDT = new TableSorter(modelDT);
+	JTable tempTableDT = new JTable(sorterDT);
+	MyTableCellRenderer DTRenderer = new MyTableCellRenderer(tempTableDT,"DT"); 
+
+	public void initComponents() throws Exception {
+
+	   	tableModels = tempTableModels;
+	    tableAIC = tempTableAIC;
+	   	tableAICc = tempTableAICc;
+		tableBIC = tempTableBIC;
+		tableDT = tempTableDT;
+				
+		// set format for all columns
+		for (int i = 0; i < 8; i++) 
+			{ 
+			TableColumn AICtableColumn = tableAIC.getColumnModel().getColumn(i); 
+			AICtableColumn.setCellRenderer((javax.swing.table.TableCellRenderer) AICRenderer); 
+
+			TableColumn AICctableColumn = tableAICc.getColumnModel().getColumn(i); 
+			AICctableColumn.setCellRenderer((javax.swing.table.TableCellRenderer) AICcRenderer); 
+
+			TableColumn BICtableColumn = tableBIC.getColumnModel().getColumn(i); 
+			BICtableColumn.setCellRenderer((javax.swing.table.TableCellRenderer) BICRenderer); 
+
+			TableColumn DTtableColumn = tableDT.getColumnModel().getColumn(i); 
+			DTtableColumn.setCellRenderer((javax.swing.table.TableCellRenderer) DTRenderer); 
+			}
+
+ 		panelInfo.setSize(PANEL_INFO_DIM);
+ 		panelInfo.setLocation(new java.awt.Point(0, 390));
+ 		panelInfo.setVisible(true);
+ 		panelInfo.setLayout(null);
+ 		labelInfo.setSize(LABEL_INFO_DIM);
+ 		labelInfo.setLocation(new java.awt.Point(40, 0));
+ 		labelInfo.setVisible(true);
+ 		labelInfo.setText("Decimal numbers are rounded. Click on column headers to sort data in ascending or descending order (+Shift)");
+ 		labelInfo.setForeground(java.awt.Color.gray);
+ 		labelInfo.setHorizontalTextPosition(javax.swing.JLabel.CENTER);
+ 		labelInfo.setFont(XManager.FONT_LABEL_BIG);
+ 		labelDate.setSize(LABEL_DATE_DIM);
+ 		labelDate.setLocation(new java.awt.Point(40, 10));
+ 		labelDate.setVisible(true);
+ 		labelDate.setText("Date");
+ 		labelDate.setForeground(java.awt.Color.gray);
+ 		labelDate.setFont(XManager.FONT_LABEL_BIG);
+ 		tabbedPane.setSize(TABBED_PANE_DIM);
+ 		tabbedPane.setLocation(new java.awt.Point(0, 0));
+ 		tabbedPane.setVisible(true);
+ 		tabbedPane.setAutoscrolls(true);
+ 		panelModels.setVisible(true);
+ 		panelModels.setLayout(null);
+		panelModels.setFont(XManager.FONT_CONSOLE);
+
+ 		scrollPaneModels.setSize(SCROLL_PANE_DIM);
+ 		scrollPaneModels.setLocation(new java.awt.Point(12, 14));
+ 		scrollPaneModels.setVisible(true);
+ 		scrollPaneModels.setAutoscrolls(true);
+ 		scrollPaneModels.setForeground(java.awt.Color.blue);
+ 		scrollPaneModels.setBackground(null);
+ 		scrollPaneModels.setFont(XManager.FONT_TABULAR);
+ 		tableModels.setColumnSelectionAllowed(true);
+ 		tableModels.setToolTipText("Click and Shift+Click on headers to order up and down");
+ 		tableModels.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
+ 		tableModels.setCellSelectionEnabled(true);
+ 		tableModels.setVisible(true);
+ 		tableModels.setPreferredScrollableViewportSize(new java.awt.Dimension(600, 300));
+ 		tableModels.setGridColor(java.awt.Color.gray);
+ 		tableModels.setFont(XManager.FONT_TABULAR);
+ 		panelAIC.setVisible(true);
+		panelAIC.setLayout(null);
+ 		scrollPaneAIC.setSize(SCROLL_PANE_DIM);
+ 		scrollPaneAIC.setLocation(new java.awt.Point(12, 14));
+ 		scrollPaneAIC.setVisible(true);
+ 		scrollPaneAIC.setAutoscrolls(true);
+ 		scrollPaneAIC.setForeground(java.awt.Color.blue);
+ 		scrollPaneAIC.setBackground(null);
+ 		scrollPaneAIC.setFont(XManager.FONT_TABULAR);
+ 		tableAIC.setColumnSelectionAllowed(true);
+ 		tableAIC.setToolTipText("Click and Shift+Click on headers to order up and down");
+ 		tableAIC.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS);
+ 		tableAIC.setCellSelectionEnabled(true);
+ 		tableAIC.setVisible(true);
+ 		tableAIC.setPreferredScrollableViewportSize(new java.awt.Dimension(675, 350));
+ 		tableAIC.setGridColor(java.awt.Color.gray);
+ 		tableAIC.setFont(XManager.FONT_TABULAR);
+ 		panelAICc.setVisible(true);
+ 		panelAICc.setLayout(null);
+ 		scrollPaneAICc.setSize(SCROLL_PANE_DIM);
+ 		scrollPaneAICc.setLocation(new java.awt.Point(12, 14));
+ 		scrollPaneAICc.setVisible(true);
+ 		scrollPaneAICc.setAutoscrolls(true);
+ 		scrollPaneAICc.setForeground(java.awt.Color.blue);
+ 		scrollPaneAICc.setBackground(null);
+ 		scrollPaneAICc.setFont(XManager.FONT_TABULAR);
+ 		tableAICc.setColumnSelectionAllowed(true);
+ 		tableAICc.setToolTipText("Click and Shift+Click on headers to order up and down");
+ 		tableAICc.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
+ 		tableAICc.setCellSelectionEnabled(true);
+ 		tableAICc.setVisible(true);
+ 		tableAICc.setPreferredScrollableViewportSize(new java.awt.Dimension(675, 350));
+ 		tableAICc.setGridColor(java.awt.Color.gray);
+ 		tableAICc.setFont(XManager.FONT_TABULAR);
+ 		panelBIC.setVisible(true);
+ 		panelBIC.setLayout(null);
+ 		scrollPaneBIC.setSize(SCROLL_PANE_DIM);
+ 		scrollPaneBIC.setLocation(new java.awt.Point(12, 14));
+ 		scrollPaneBIC.setVisible(true);
+ 		scrollPaneBIC.setAutoscrolls(true);
+ 		scrollPaneBIC.setForeground(java.awt.Color.blue);
+ 		scrollPaneBIC.setBackground(null);
+ 		scrollPaneBIC.setFont(XManager.FONT_TABULAR);
+ 		tableBIC.setColumnSelectionAllowed(true);
+ 		tableBIC.setToolTipText("Click and Shift+Click on headers to order up and down");
+ 		tableBIC.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
+ 		tableBIC.setCellSelectionEnabled(true);
+ 		tableBIC.setVisible(true);
+ 		tableBIC.setPreferredScrollableViewportSize(new java.awt.Dimension(675, 350));
+ 		tableBIC.setGridColor(java.awt.Color.gray);
+ 		tableBIC.setFont(XManager.FONT_TABULAR);
+  		panelDT.setVisible(true);
+ 		panelDT.setLayout(null);
+ 		scrollPaneDT.setSize(SCROLL_PANE_DIM);
+ 		scrollPaneDT.setLocation(new java.awt.Point(12, 14));
+ 		scrollPaneDT.setVisible(true);
+ 		scrollPaneDT.setAutoscrolls(true);
+ 		scrollPaneDT.setForeground(java.awt.Color.blue);
+ 		scrollPaneDT.setBackground(null);
+ 		scrollPaneDT.setFont(XManager.FONT_TABULAR);
+ 		tableDT.setColumnSelectionAllowed(true);
+ 		tableDT.setToolTipText("Click and Shift+Click on headers to order up and down");
+ 		tableDT.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_OFF);
+ 		tableDT.setCellSelectionEnabled(true);
+ 		tableDT.setVisible(true);
+ 		tableDT.setPreferredScrollableViewportSize(new java.awt.Dimension(675, 350));
+ 		tableDT.setGridColor(java.awt.Color.gray);
+ 		tableDT.setFont(XManager.FONT_TABULAR);
+ 		setLocation(new java.awt.Point(281, 80));
+ 		setResizable(true);
+ 		setFont(XManager.FONT_TABULAR);
+ 		setLayout(null);
+ 		setTitle("Results");
+		setResizable(false);
+		
+ 		panelInfo.add(labelInfo);
+ 		panelInfo.add(labelDate);
+ 		tabbedPane.add(panelModels);
+ 		tabbedPane.setTitleAt(tabbedPane.getTabCount() - 1, "Models");
+ 		tabbedPane.add(panelAIC);
+		tabbedPane.setTitleAt(tabbedPane.getTabCount() - 1, "AIC");
+		tabbedPane.setEnabledAt(tabbedPane.getTabCount() - 1, false);
+ 		tabbedPane.setForegroundAt(tabbedPane.getTabCount() - 1, Color.gray);
+		tabbedPane.add(panelAICc);
+ 		tabbedPane.setTitleAt(tabbedPane.getTabCount() - 1, "AICc");
+ 		tabbedPane.setEnabledAt(tabbedPane.getTabCount() - 1, false);
+ 		tabbedPane.setForegroundAt(tabbedPane.getTabCount() - 1, Color.gray);
+		tabbedPane.add(panelBIC);
+ 		tabbedPane.setTitleAt(tabbedPane.getTabCount() - 1, "BIC");
+		tabbedPane.setEnabledAt(tabbedPane.getTabCount() - 1, false);
+		tabbedPane.setForegroundAt(tabbedPane.getTabCount() - 1, Color.gray);
+		tabbedPane.add(panelDT);
+ 		tabbedPane.setTitleAt(tabbedPane.getTabCount() - 1, "DT");
+		tabbedPane.setEnabledAt(tabbedPane.getTabCount() - 1, false);
+		tabbedPane.setForegroundAt(tabbedPane.getTabCount() - 1, Color.gray);
+
+		panelModels.add(scrollPaneModels);
+ 		scrollPaneModels.getViewport().add(tableModels);
+ 		panelAIC.add(scrollPaneAIC);
+ 		scrollPaneAIC.getViewport().add(tableAIC);
+ 		panelAICc.add(scrollPaneAICc);
+ 		scrollPaneAICc.getViewport().add(tableAICc);
+ 		panelBIC.add(scrollPaneBIC);
+ 		scrollPaneBIC.getViewport().add(tableBIC);
+ 		panelDT.add(scrollPaneDT);
+ 		scrollPaneDT.getViewport().add(tableDT);
+
+ 		add(panelInfo);
+ 		add(tabbedPane);
+ 
+ 		tabbedPane.setSelectedIndex(0);
+ 		setSize(FRAME_DIM);
+ 
+ 		// event handling
+ 		addWindowListener(new java.awt.event.WindowAdapter() {
+ 			public void windowClosing(java.awt.event.WindowEvent e) {
+ 				thisWindowClosing(e);
+ 			}
+ 		});
+ 
+ 		 sorterModels.addMouseListenerToHeaderInTable(tableModels);
+ 		 sorterAIC.addMouseListenerToHeaderInTable(tableAIC);
+ 		 sorterAICc.addMouseListenerToHeaderInTable(tableAICc);
+ 		 sorterBIC.addMouseListenerToHeaderInTable(tableBIC);
+ 		 sorterDT.addMouseListenerToHeaderInTable(tableDT);	
+
+		// set date
+		Date today = new Date();
+	    SimpleDateFormat formatter = new SimpleDateFormat("dd MMMMM yyyy");
+	    String datenewformat = formatter.format(today);
+	 	labelDate.setText(datenewformat);
+
+	}
+  
+  	private boolean mShown = false;
+  	
+	public void addNotify() {
+		super.addNotify();
+		
+		if (mShown)
+			return;
+			
+		// move components to account for insets
+		Insets insets = getInsets();
+		Component[] components = getComponents();
+		for (int i = 0; i < components.length; i++) {
+			Point location = components[i].getLocation();
+			location.move(location.x, location.y + insets.top);
+			components[i].setLocation(location);
+		}
+
+		mShown = true;
+	}
+
+	// Close the window when the close box is clicked
+	void thisWindowClosing(java.awt.event.WindowEvent e) {
+		setVisible(false);
+		dispose();
+		//System.exit(0);
+	}
+	
+	public void enablePane(int pane) {
+		tabbedPane.setEnabledAt(pane, true);
+		tabbedPane.setForegroundAt(pane, Color.black);
+	}
+	
+	public void disablePane(int pane) {
+		tabbedPane.setEnabledAt(pane, false);
+		tabbedPane.setForegroundAt(pane, Color.gray);
+	}
+
+	public void populate(int pane) {
+		switch(pane) {
+		case TAB_AIC:
+			modelAIC.populate("AIC");
+			break;
+		case TAB_AICc:
+			modelAICc.populate("AICc");
+			break;
+		case TAB_BIC:
+			modelBIC.populate("BIC");
+			break;
+		case TAB_DT:
+			modelDT.populate("DT");
+			break;
+		}
+	}
+
+}
+
+
+
+
+
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_AIC.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_AIC.java
new file mode 100644
index 0000000..84160e7
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_AIC.java
@@ -0,0 +1,366 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Point;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenuBar;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+import javax.swing.border.LineBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.BorderUIResource;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.selection.AIC;
+import es.uvigo.darwin.jmodeltest.selection.AICc;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class Frame_AIC extends JModelTestFrame {
+
+	private static final long serialVersionUID = 201104031100L;
+
+	private JPanel panelAICSettings = new JPanel();
+	private JTextField textTaxaAIC = new JTextField();
+	private JTextField textSizeAICc = new JTextField();
+	private JButton runButtonAIC = new JButton();
+	private JButton cancelButtonAIC = new JButton();
+	private JButton buttonDefaultAIC = new JButton();
+	private JCheckBox checkBoxAICc = new JCheckBox();
+
+	private JCheckBox checkBoxPAUPblock = new JCheckBox();
+	private JCheckBox checkBoxAveraging = new JCheckBox();
+	private JCheckBox checkBoxImportance = new JCheckBox();
+	private JSlider sliderInterval = new JSlider();
+
+	private AIC myAIC;
+	private AICc myAICc;
+
+	public Frame_AIC() {
+	}
+
+	public void initComponents() throws Exception {
+		panelAICSettings.setSize(490, 240);
+		panelAICSettings
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(new java.awt.Color(
+								153, 153, 153), 1, false), "AIC Settings", 4,
+						2, new java.awt.Font("Application", 1, 10),
+						new java.awt.Color(102, 102, 153)));
+		panelAICSettings.setLocation(10, 10);
+		panelAICSettings.setVisible(true);
+		panelAICSettings.setLayout(null);
+
+		runButtonAIC.setVisible(true);
+		runButtonAIC.setSize(190, 40);
+		runButtonAIC.setText("Do AIC calculations");
+		runButtonAIC.setLocation(280, 190);
+		getRootPane().setDefaultButton(runButtonAIC);
+
+		buttonDefaultAIC.setVisible(true);
+		buttonDefaultAIC.setSize(141, 40);
+		buttonDefaultAIC.setText("Default Settings");
+		buttonDefaultAIC.setLocation(10, 190);
+
+		cancelButtonAIC.setVisible(true);
+		cancelButtonAIC.setSize(110, 40);
+		cancelButtonAIC.setText("Cancel");
+		cancelButtonAIC.setLocation(160, 190);
+
+		checkBoxAICc.setVisible(true);
+		checkBoxAICc.setSize(170, 20);
+		checkBoxAICc.setText("Use AICc correction");
+		checkBoxAICc.setLocation(30, 30);
+		checkBoxAICc.setSelected(false);
+
+		textSizeAICc.setEnabled(false);
+		textSizeAICc
+				.setToolTipText("Enter the sample size you want to use for the AICc correction and click RETURN. By default this is the number of sites in the alignment");
+		textSizeAICc
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(new java.awt.Color(
+								153, 153, 153), 1, false), "Sample size", 4, 2,
+						new java.awt.Font("Application", 1, 10),
+						new java.awt.Color(102, 102, 153)));
+		textSizeAICc.setVisible(true);
+		textSizeAICc.setSize(170, 40);
+		textSizeAICc.setText(Utilities.format(options.getSampleSize(),10,4,false));
+		textSizeAICc.setHorizontalAlignment(JTextField.RIGHT);
+		textSizeAICc.setLocation(300, 20);
+
+		checkBoxImportance.setVisible(true);
+		checkBoxImportance.setSize(260, 20);
+		checkBoxImportance.setText("Calculate parameter importances");
+		checkBoxImportance.setLocation(30, 70);
+		checkBoxImportance.setSelected(true);
+
+		checkBoxAveraging.setVisible(true);
+		checkBoxAveraging.setSize(260, 20);
+		checkBoxAveraging.setText("Do model averaging");
+		checkBoxAveraging.setLocation(30, 110);
+		checkBoxAveraging.setSelected(true);
+
+		checkBoxPAUPblock.setVisible(true);
+		checkBoxPAUPblock.setSize(260, 20);
+		checkBoxPAUPblock.setText("Write PAUP* block");
+		checkBoxPAUPblock.setLocation(30, 150);
+		checkBoxPAUPblock.setSelected(false);
+		checkBoxPAUPblock
+				.setToolTipText("Writes a block of PAUP* commands implementing the selected model");
+
+		sliderInterval.setVisible(true);
+		sliderInterval
+				.setToolTipText("Set the confidence interval for model averaging and/or parameter importance");
+		sliderInterval
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(new java.awt.Color(
+								153, 153, 153), 1, false),
+						"Confidence interval = 100%", 4, 2, new java.awt.Font(
+								"Application", 1, 10), new java.awt.Color(102,
+								102, 153)));
+		sliderInterval.setSize(170, 70);
+		sliderInterval.setLocation(300, 105);
+		sliderInterval.setMinimum(0);
+		sliderInterval.setMaximum(100);
+		sliderInterval.setValue(100);
+		sliderInterval.setMajorTickSpacing(20);
+		sliderInterval.setMinorTickSpacing(5);
+		sliderInterval.setPaintTicks(true);
+		sliderInterval.setPaintLabels(true);
+		sliderInterval.setEnabled(true);
+		sliderInterval.setFont(XManager.FONT_SLIDER);
+
+		setLocation(281, 80);
+		getContentPane().setLayout(null);
+		setTitle("Akaike Information Criterion (AIC) Settings");
+
+		panelAICSettings.add(runButtonAIC);
+		panelAICSettings.add(buttonDefaultAIC);
+		panelAICSettings.add(cancelButtonAIC);
+		panelAICSettings.add(checkBoxAICc);
+		panelAICSettings.add(textTaxaAIC);
+		panelAICSettings.add(textSizeAICc);
+		// PanelAICSettings.add(jCheckBoxIncludeBL_AIC);
+		panelAICSettings.add(checkBoxAveraging);
+		panelAICSettings.add(checkBoxImportance);
+		panelAICSettings.add(checkBoxPAUPblock);
+		panelAICSettings.add(sliderInterval);
+		getContentPane().add(panelAICSettings);
+
+		setSize(510, 280);
+		setResizable(false);
+
+		// event handling
+
+		checkBoxAICc.addChangeListener(new ChangeListener() {
+			public void stateChanged(ChangeEvent e) {
+				jCheckBoxAICcStateChanged(e);
+			}
+		});
+
+		checkBoxAveraging
+				.addChangeListener(new ChangeListener() {
+					public void stateChanged(ChangeEvent e) {
+						jCheckBoxAveragingStateChanged(e);
+					}
+				});
+
+		checkBoxImportance
+				.addChangeListener(new ChangeListener() {
+					public void stateChanged(ChangeEvent e) {
+						jCheckBoxImportanceStateChanged(e);
+					}
+				});
+
+		sliderInterval
+				.addChangeListener(new ChangeListener() {
+					public void stateChanged(ChangeEvent e) {
+						JSliderIntervalStateChanged(e);
+					}
+				});
+		
+		buttonDefaultAIC
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						JButtonDefaultAICActionPerformed(e);
+					}
+				});
+		cancelButtonAIC.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				CancelButtonAICActionPerformed(e);
+			}
+		});
+		runButtonAIC.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				RunButtonAICActionPerformed(e);
+			}
+		});
+
+		addWindowListener(new java.awt.event.WindowAdapter() {
+			public void windowClosing(java.awt.event.WindowEvent e) {
+				thisWindowClosing(e);
+			}
+		});
+
+	}
+
+	private boolean mShown = false;
+
+	public void addNotify() {
+		super.addNotify();
+
+		if (mShown)
+			return;
+
+		// resize frame to account for menubar
+		JMenuBar jMenuBar = getJMenuBar();
+		if (jMenuBar != null) {
+			int jMenuBarHeight = jMenuBar.getPreferredSize().height;
+			Dimension dimension = getSize();
+			dimension.height += jMenuBarHeight;
+			setSize(dimension);
+
+			// move down components in layered pane
+			Component[] components = getLayeredPane().getComponentsInLayer(
+					JLayeredPane.DEFAULT_LAYER.intValue());
+			for (int i = 0; i < components.length; i++) {
+				Point location = components[i].getLocation();
+				location.move(location.x, location.y + jMenuBarHeight);
+				components[i].setLocation(location);
+			}
+		}
+
+		mShown = true;
+	}
+
+	// Close the window when the close box is clicked
+	void thisWindowClosing(java.awt.event.WindowEvent e) {
+		setVisible(false);
+		dispose();
+		// System.exit(0);
+	}
+
+	public void jCheckBoxAICcStateChanged(ChangeEvent e) {
+		if (checkBoxAICc.isSelected()) {
+			textSizeAICc.setEnabled(true);
+			runButtonAIC.setText("Do AICc calculations");
+		} else {
+			textSizeAICc.setEnabled(false);
+			runButtonAIC.setText("Do AIC calculations");
+		}
+	}
+
+	public void jCheckBoxImportanceStateChanged(ChangeEvent e) {
+		if (checkBoxImportance.isSelected()) {
+			sliderInterval.setEnabled(true);
+		} else {
+			if (!checkBoxAveraging.isSelected())
+				sliderInterval.setEnabled(false);
+		}
+	}
+
+	public void jCheckBoxAveragingStateChanged(ChangeEvent e) {
+		if (checkBoxAveraging.isSelected()) {
+			sliderInterval.setEnabled(true);
+		} else {
+			if (!checkBoxImportance.isSelected())
+				sliderInterval.setEnabled(false);
+		}
+	}
+
+	public void JSliderIntervalStateChanged(ChangeEvent e) {
+		sliderInterval
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(new java.awt.Color(
+								153, 153, 153), 1, false),
+						"Confidence interval = " + sliderInterval.getValue()
+								+ "%", 4, 2, new java.awt.Font("Application",
+								1, 10), new java.awt.Color(102, 102, 153)));
+	}
+
+	public void JButtonDefaultAICActionPerformed(java.awt.event.ActionEvent e) {
+		checkBoxAICc.setSelected(false);
+		textSizeAICc.setEnabled(false);
+		runButtonAIC.setText("Do AIC calculations");
+		ApplicationOptions.getInstance().countBLasParameters = true;
+		XManager.getInstance().selectedMenuResultsBLasParameters(true);
+		checkBoxPAUPblock.setSelected(false);
+		checkBoxAveraging.setSelected(true);
+		checkBoxImportance.setSelected(true);
+		sliderInterval.setValue(100);
+	}
+
+	public void CancelButtonAICActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			setVisible(false);
+			dispose();
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	public void RunButtonAICActionPerformed(java.awt.event.ActionEvent e) {
+		boolean writePAUPblock, doImportances, doModelAveraging;
+		double credibleInterval;
+
+		try {
+			setVisible(false);
+			dispose();
+
+			writePAUPblock = checkBoxPAUPblock.isSelected();
+			options.writePAUPblock |= writePAUPblock;
+			doImportances = checkBoxImportance.isSelected();
+			doModelAveraging = checkBoxAveraging.isSelected();
+
+			credibleInterval = sliderInterval.getValue() / 100.0;
+
+			if (checkBoxAICc.isSelected()) {
+				myAICc = new AICc(writePAUPblock, doImportances,
+						doModelAveraging, credibleInterval);
+				myAICc.compute();
+				myAICc.print(ModelTest.getCurrentOutStream());
+				ModelTest.setMyAICc(myAICc);
+				options.doAICc = myAICc != null;
+				XManager.getInstance().resultsFrame.enablePane(FrameResults.TAB_AICc);
+				XManager.getInstance().resultsFrame.populate(FrameResults.TAB_AICc);
+			} else {
+				myAIC = new AIC(writePAUPblock, doImportances,
+						doModelAveraging, credibleInterval);
+				myAIC.compute();
+				myAIC.print(ModelTest.getCurrentOutStream());
+				ModelTest.setMyAIC(myAIC);
+				options.doAIC = myAIC != null;
+				XManager.getInstance().resultsFrame.enablePane(FrameResults.TAB_AIC);
+				XManager.getInstance().resultsFrame.populate(FrameResults.TAB_AIC);
+			}
+			XManager.getInstance().enableMenuAveraging(!options.fixedTopology);
+			
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_BIC.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_BIC.java
new file mode 100644
index 0000000..b41afba
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_BIC.java
@@ -0,0 +1,325 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Point;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenuBar;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+import javax.swing.border.LineBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.BorderUIResource;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.selection.BIC;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class Frame_BIC extends JModelTestFrame {
+
+	private static final long serialVersionUID = 201104031100L;
+
+	private JPanel PanelBICSettings = new JPanel();
+	private JTextField TextFieldTaxaBIC = new JTextField();
+	private JTextField TextFieldSizeBIC = new JTextField();
+	private JButton RunButtonBIC = new JButton();
+	private JButton CancelButtonBIC = new JButton();
+	private JButton JButtonDefaultBIC = new JButton();
+
+	private JCheckBox jCheckBoxPAUPblock = new JCheckBox();
+	private JCheckBox jCheckBoxAveraging = new JCheckBox();
+	private JCheckBox jCheckBoxImportance = new JCheckBox();
+	private JSlider JSliderInterval = new JSlider();
+
+	private BIC myBIC;
+
+	public Frame_BIC() {
+	}
+
+	public void initComponents() throws Exception {
+		PanelBICSettings.setSize(490, 240);
+		PanelBICSettings
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(new java.awt.Color(
+								153, 153, 153), 1, false), "BIC Settings", 4,
+						2, new java.awt.Font("Application", 1, 10),
+						new java.awt.Color(102, 102, 153)));
+		PanelBICSettings.setLocation(10, 10);
+		PanelBICSettings.setVisible(true);
+		PanelBICSettings.setLayout(null);
+
+		RunButtonBIC.setVisible(true);
+		RunButtonBIC.setSize(190, 40);
+		RunButtonBIC.setText("Do BIC calculations");
+		RunButtonBIC.setLocation(280, 190);
+		getRootPane().setDefaultButton(RunButtonBIC);
+
+		JButtonDefaultBIC.setVisible(true);
+		JButtonDefaultBIC.setSize(141, 40);
+		JButtonDefaultBIC.setText("Default Settings");
+		JButtonDefaultBIC.setLocation(10, 190);
+
+		CancelButtonBIC.setVisible(true);
+		CancelButtonBIC.setSize(110, 40);
+		CancelButtonBIC.setText("Cancel");
+		CancelButtonBIC.setLocation(160, 190);
+
+		TextFieldSizeBIC
+				.setToolTipText("Enter the sample size you want to use for the BIC and click RETURN. By default this is the number of sites in the alignment");
+		TextFieldSizeBIC
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(new java.awt.Color(
+								153, 153, 153), 1, false), "Sample size", 4, 2,
+						new java.awt.Font("Application", 1, 10),
+						new java.awt.Color(102, 102, 153)));
+		TextFieldSizeBIC.setVisible(true);
+		TextFieldSizeBIC.setSize(170, 40);
+		TextFieldSizeBIC.setText(Utilities.format(options.getSampleSize(),10,4,false));
+		TextFieldSizeBIC.setHorizontalAlignment(JTextField.RIGHT);
+		TextFieldSizeBIC.setLocation(30, 20);
+		TextFieldSizeBIC.setEnabled(false);
+
+		jCheckBoxImportance.setVisible(true);
+		jCheckBoxImportance.setSize(260, 20);
+		jCheckBoxImportance.setText("Calculate parameter importances");
+		jCheckBoxImportance.setLocation(30, 70);
+		jCheckBoxImportance.setSelected(true);
+
+		jCheckBoxAveraging.setVisible(true);
+		jCheckBoxAveraging.setSize(260, 20);
+		jCheckBoxAveraging.setText("Do model averaging");
+		jCheckBoxAveraging.setLocation(30, 110);
+		jCheckBoxAveraging.setSelected(true);
+
+		jCheckBoxPAUPblock.setVisible(true);
+		jCheckBoxPAUPblock.setSize(260, 20);
+		jCheckBoxPAUPblock.setText("Write PAUP* block");
+		jCheckBoxPAUPblock.setLocation(30, 150);
+		jCheckBoxPAUPblock.setSelected(false);
+		jCheckBoxPAUPblock
+				.setToolTipText("Writes a block of PAUP* commands implementing the selected model");
+
+		JSliderInterval.setVisible(true);
+		JSliderInterval
+				.setToolTipText("Set the confidence interval for model averaging and/or parameter importance");
+		JSliderInterval
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(new java.awt.Color(
+								153, 153, 153), 1, false),
+						"Confidence interval = 100%", 4, 2, new java.awt.Font(
+								"Application", 1, 10), new java.awt.Color(102,
+								102, 153)));
+		JSliderInterval.setSize(170, 70);
+		JSliderInterval.setLocation(300, 70);
+		JSliderInterval.setMinimum(0);
+		JSliderInterval.setMaximum(100);
+		JSliderInterval.setValue(100);
+		JSliderInterval.setMajorTickSpacing(20);
+		JSliderInterval.setMinorTickSpacing(5);
+		JSliderInterval.setPaintTicks(true);
+		JSliderInterval.setPaintLabels(true);
+		JSliderInterval.setEnabled(true);
+		JSliderInterval.setFont(XManager.FONT_SLIDER);
+
+		setLocation(281, 80);
+		getContentPane().setLayout(null);
+		setTitle("Bayesian Information Criterion (BIC) Settings");
+
+		PanelBICSettings.add(TextFieldTaxaBIC);
+		PanelBICSettings.add(TextFieldSizeBIC);
+		PanelBICSettings.add(jCheckBoxAveraging);
+		PanelBICSettings.add(jCheckBoxImportance);
+		PanelBICSettings.add(jCheckBoxPAUPblock);
+		PanelBICSettings.add(JSliderInterval);
+		PanelBICSettings.add(JButtonDefaultBIC);
+		PanelBICSettings.add(CancelButtonBIC);
+		PanelBICSettings.add(RunButtonBIC);
+		getContentPane().add(PanelBICSettings);
+
+		setSize(510, 280);
+		setResizable(false);
+
+		// event handling
+		jCheckBoxAveraging
+				.addChangeListener(new ChangeListener() {
+					public void stateChanged(ChangeEvent e) {
+						jCheckBoxAveragingStateChanged(e);
+					}
+				});
+
+		jCheckBoxImportance
+				.addChangeListener(new ChangeListener() {
+					public void stateChanged(ChangeEvent e) {
+						jCheckBoxImportanceStateChanged(e);
+					}
+				});
+
+		JSliderInterval
+				.addChangeListener(new ChangeListener() {
+					public void stateChanged(ChangeEvent e) {
+						JSliderIntervalStateChanged(e);
+					}
+				});
+
+		JButtonDefaultBIC
+				.addActionListener(new java.awt.event.ActionListener() {
+					public void actionPerformed(java.awt.event.ActionEvent e) {
+						JButtonDefaultBICActionPerformed(e);
+					}
+				});
+		CancelButtonBIC.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				CancelButtonBICActionPerformed(e);
+			}
+		});
+		RunButtonBIC.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				RunButtonBICActionPerformed(e);
+			}
+		});
+
+		addWindowListener(new java.awt.event.WindowAdapter() {
+			public void windowClosing(java.awt.event.WindowEvent e) {
+				thisWindowClosing(e);
+			}
+		});
+
+	}
+
+	private boolean mShown = false;
+
+	public void addNotify() {
+		super.addNotify();
+
+		if (mShown)
+			return;
+
+		// resize frame to account for menubar
+		JMenuBar jMenuBar = getJMenuBar();
+		if (jMenuBar != null) {
+			int jMenuBarHeight = jMenuBar.getPreferredSize().height;
+			Dimension dimension = getSize();
+			dimension.height += jMenuBarHeight;
+			setSize(dimension);
+
+			// move down components in layered pane
+			Component[] components = getLayeredPane().getComponentsInLayer(
+					JLayeredPane.DEFAULT_LAYER.intValue());
+			for (int i = 0; i < components.length; i++) {
+				Point location = components[i].getLocation();
+				location.move(location.x, location.y + jMenuBarHeight);
+				components[i].setLocation(location);
+			}
+		}
+
+		mShown = true;
+	}
+
+	// Close the window when the close box is clicked
+	void thisWindowClosing(java.awt.event.WindowEvent e) {
+		setVisible(false);
+		dispose();
+		// System.exit(0);
+	}
+
+	public void jCheckBoxImportanceStateChanged(ChangeEvent e) {
+		if (jCheckBoxImportance.isSelected()) {
+			JSliderInterval.setEnabled(true);
+		} else {
+			if (!jCheckBoxAveraging.isSelected())
+				JSliderInterval.setEnabled(false);
+		}
+	}
+
+	public void jCheckBoxAveragingStateChanged(ChangeEvent e) {
+		if (jCheckBoxAveraging.isSelected()) {
+			JSliderInterval.setEnabled(true);
+		} else {
+			if (!jCheckBoxImportance.isSelected())
+				JSliderInterval.setEnabled(false);
+		}
+	}
+
+	public void JSliderIntervalStateChanged(ChangeEvent e) {
+		JSliderInterval
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(new java.awt.Color(
+								153, 153, 153), 1, false),
+						"Confidence interval = " + JSliderInterval.getValue()
+								+ "%", 4, 2, new java.awt.Font("Application",
+								1, 10), new java.awt.Color(102, 102, 153)));
+	}
+
+	public void JButtonDefaultBICActionPerformed(java.awt.event.ActionEvent e) {
+		TextFieldSizeBIC.setEnabled(false);
+		TextFieldSizeBIC.setText(Utilities.format(options.getSampleSize(),10,4,false));
+		ApplicationOptions.getInstance().countBLasParameters = true;
+		XManager.getInstance().selectedMenuResultsBLasParameters(true);
+		jCheckBoxPAUPblock.setSelected(false);
+		jCheckBoxAveraging.setSelected(true);
+		jCheckBoxImportance.setSelected(true);
+		JSliderInterval.setValue(100);
+	}
+
+	public void CancelButtonBICActionPerformed(java.awt.event.ActionEvent e) {
+		try {
+			setVisible(false);
+			dispose();
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	public void RunButtonBICActionPerformed(java.awt.event.ActionEvent e) {
+		boolean writePAUPblock, doImportances, doModelAveraging;
+		double credibleInterval;
+
+		try {
+			setVisible(false);
+			dispose();
+
+			writePAUPblock = jCheckBoxPAUPblock.isSelected();
+			options.writePAUPblock |= writePAUPblock;
+			doImportances = jCheckBoxImportance.isSelected();
+			doModelAveraging = jCheckBoxAveraging.isSelected();
+
+			credibleInterval = JSliderInterval.getValue() / 100.0;
+
+			myBIC = new BIC(writePAUPblock, doImportances, doModelAveraging,
+					credibleInterval);
+			myBIC.compute();
+			myBIC.print(ModelTest.getCurrentOutStream());
+			ModelTest.setMyBIC(myBIC);
+			options.doBIC = myBIC != null;
+			XManager.getInstance().resultsFrame.enablePane(FrameResults.TAB_BIC);
+			XManager.getInstance().resultsFrame.populate(FrameResults.TAB_BIC);
+			XManager.getInstance().enableMenuAveraging(!options.fixedTopology);
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_CalcLike.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_CalcLike.java
new file mode 100644
index 0000000..7665d50
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_CalcLike.java
@@ -0,0 +1,943 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FileDialog;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.IOException;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenuBar;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+import javax.swing.border.LineBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.BorderUIResource;
+
+import pal.tree.Tree;
+import pal.tree.TreeParseException;
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.exe.RunPhyml;
+import es.uvigo.darwin.jmodeltest.exe.RunPhymlThread;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+import es.uvigo.darwin.jmodeltest.threads.SwingWorker;
+import es.uvigo.darwin.jmodeltest.tree.TreeUtilities;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class Frame_CalcLike extends JModelTestFrame {
+
+	private static final long serialVersionUID = 201103091058L;
+	private static final int TOTAL_NUMBER_OF_THREADS = Runtime.getRuntime()
+			.availableProcessors();
+	private static final int DEFAULT_NUMBER_OF_THREADS = TOTAL_NUMBER_OF_THREADS;
+	private static final int DEFAULT_THRESHOLD = 100; // DEFAULT_THRESHOLD/1000
+
+	private static final int PANEL_X = 10;
+	private static final int PANEL_PROCESSORS_Y = 10;
+	private static final int PANEL_HEURISTICS_Y = 100;
+	private static final int PANEL_CALCLIKE_Y = 230;
+
+	private ApplicationOptions options = ApplicationOptions.getInstance();
+
+	private JPanel PanelProcessors = new JPanel();
+	private JSlider SliderProcessors = new JSlider(1, TOTAL_NUMBER_OF_THREADS,
+			DEFAULT_NUMBER_OF_THREADS);
+	private JLabel jLabelNumProcessors = new JLabel();
+
+	private JPanel PanelHeuristics = new JPanel();
+	private JRadioButton ButtonAICClustering = new JRadioButton();
+	private JRadioButton ButtonAICcClustering = new JRadioButton();
+	private JRadioButton ButtonBICClustering = new JRadioButton();
+	private ButtonGroup ButtonGroupClusteringIC = new ButtonGroup();
+
+	private JPanel PanelCalcLike = new JPanel();
+	JButton RunButtonCalcLike = new JButton();
+	private JButton CancelButtonCalcLike = new JButton();
+	private JButton JButtonDefaultCalcLike = new JButton();
+	private JPanel PanelNumberModelsCalcLike = new JPanel();
+	private JRadioButton Button3SubsTypeCalcLike = new JRadioButton();
+	private JRadioButton Button5SubsTypeCalcLike = new JRadioButton();
+	private JRadioButton Button7SubsTypeCalcLike = new JRadioButton();
+	private JRadioButton Button11SubsTypeCalcLike = new JRadioButton();
+	private JRadioButton Button203SubsTypeCalcLike = new JRadioButton();
+
+	private JCheckBox jCheckBoxModelFiltering = new JCheckBox();
+	private JLabel jLabelThreshold = new JLabel();
+	// private JLabel jLabelSliderCaption = new JLabel();
+	private JCheckBox jCheckBoxClustering = new JCheckBox();
+	private JSlider SliderThreshold = new JSlider(1, 1000, 100);
+
+	private JPanel PanelFrequenciesCalcLike = new JPanel();
+	private JCheckBox jCheckBoxFrequencies = new JCheckBox();
+
+	private JPanel PanelRateVariationCalcLike = new JPanel();
+	private JCheckBox jCheckBoxPinv = new JCheckBox();
+	private JCheckBox jCheckBoxGamma = new JCheckBox();
+	private JTextField TextFieldNcat = new JTextField();
+
+	private JPanel PanelTreeOptimizationCalcLike = new JPanel();
+	private JPanel PanelTreeOptimizationMethod = new JPanel();
+	private JRadioButton ButtonFixedCalcLike = new JRadioButton();
+	private JRadioButton ButtonBIONJCalcLike = new JRadioButton();
+	private JRadioButton ButtonMLCalcLike = new JRadioButton();
+	private JRadioButton ButtonFixedUserTopologyCalcLike = new JRadioButton();
+	private JRadioButton ButtonNNICalcLike = new JRadioButton();
+	private JRadioButton ButtonSPRCalcLike = new JRadioButton();
+	private JRadioButton ButtonBestCalcLike = new JRadioButton();
+
+	private ButtonGroup ButtonGroupTreeOptimizationCalcLike = new ButtonGroup();
+	private ButtonGroup ButtonGroupNumberModelsCalcLike = new ButtonGroup();
+	private ButtonGroup ButtonGroupTreeSearchCalcLike = new ButtonGroup();
+
+	private JLabel jLabelNumModels = new JLabel();
+	private JLabel jLabelUserTree = new JLabel();
+	private JLabel jLabelUserTopology = new JLabel();
+
+	private Frame_Progress progressFrame;
+
+	private RunPhyml runPhyml;
+	private ComputeLikelihoodTask task;
+
+	public void cancelTask() {
+		task.interrupt();
+	}
+
+	public RunPhyml getRunPhyml() {
+		return runPhyml;
+	}
+
+	public Frame_CalcLike() {
+	}
+
+	public void initComponents() throws Exception {
+		PanelProcessors.setLocation(PANEL_X, PANEL_PROCESSORS_Y);
+		PanelProcessors.setSize(460, 80);
+		PanelProcessors.setBorder(new BorderUIResource.TitledBorderUIResource(
+				new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false),
+				"Number of processors requested", 4, 2, XManager.FONT_LABEL,
+				XManager.LABEL_BLUE_COLOR));
+		PanelProcessors.setVisible(true);
+		PanelProcessors.setLayout(null);
+
+		SliderProcessors.setValue(SliderProcessors.getMaximum());
+		SliderProcessors.setLocation(10, 20);
+		SliderProcessors.setSize(400, 45);
+
+		jLabelNumProcessors
+				.setText(String.valueOf(SliderProcessors.getValue()));
+		jLabelNumProcessors.setLocation(420, 25);
+		jLabelNumProcessors.setSize(20, 40);
+
+		PanelProcessors.add(SliderProcessors);
+		PanelProcessors.add(jLabelNumProcessors);
+
+		PanelHeuristics.setLocation(PANEL_X, PANEL_HEURISTICS_Y);
+		PanelHeuristics.setSize(460, 120);
+		PanelHeuristics.setBorder(new BorderUIResource.TitledBorderUIResource(
+				new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false),
+				"Heuristics", 4, 2, XManager.FONT_LABEL,
+				XManager.LABEL_BLUE_COLOR));
+		PanelHeuristics.setVisible(true);
+		PanelHeuristics.setLayout(null);
+
+		jCheckBoxClustering.setEnabled(false);
+		jCheckBoxClustering.setText("Clustering");
+		jCheckBoxClustering.setSelected(false);
+		jCheckBoxClustering.setLocation(10, 30);
+		jCheckBoxClustering.setSize(150, 20);
+		jCheckBoxClustering.setVisible(true);
+
+		ButtonAICClustering.setText("AIC");
+		ButtonAICClustering.setLocation(180, 30);
+		ButtonAICClustering.setSize(70, 20);
+		ButtonAICClustering.setVisible(true);
+		ButtonAICClustering.setEnabled(jCheckBoxClustering.isSelected());
+		ButtonAICClustering
+				.setToolTipText("Use AIC for clustering next-step best model selection");
+
+		ButtonAICcClustering.setText("AICc");
+		ButtonAICcClustering.setLocation(250, 30);
+		ButtonAICcClustering.setSize(70, 20);
+		ButtonAICcClustering.setVisible(true);
+		ButtonAICcClustering
+				.setToolTipText("Use AICc for clustering next-step best model selection");
+		ButtonAICcClustering.setEnabled(jCheckBoxClustering.isSelected());
+
+		ButtonBICClustering.setText("BIC");
+		ButtonBICClustering.setLocation(320, 30);
+		ButtonBICClustering.setSize(70, 20);
+		ButtonBICClustering.setVisible(true);
+		ButtonBICClustering.setSelected(true);
+		ButtonBICClustering
+				.setToolTipText("Use BIC for clustering next-step best model selection");
+		ButtonBICClustering.setEnabled(jCheckBoxClustering.isSelected());
+
+		ButtonGroupClusteringIC.add(ButtonAICClustering);
+		ButtonGroupClusteringIC.add(ButtonAICcClustering);
+		ButtonGroupClusteringIC.add(ButtonBICClustering);
+
+		// jLabelSliderCaption.setText("Model filtering threshold:");
+		// jLabelSliderCaption.setLocation(160, 50);
+		// jLabelSliderCaption.setSize(250,40);
+		// jLabelSliderCaption.setVisible(true);
+
+		jCheckBoxModelFiltering.setEnabled(true);
+		jCheckBoxModelFiltering.setText("Model Filtering");
+		jCheckBoxModelFiltering.setSelected(false);
+		jCheckBoxModelFiltering.setLocation(10, 75);
+		jCheckBoxModelFiltering.setSize(140, 20);
+		jCheckBoxModelFiltering.setVisible(true);
+
+		jLabelThreshold.setText(Utilities.format(
+				SliderThreshold.getValue() / 1000.0, 5, 3, false));
+		jLabelThreshold.setLocation(400, 65);
+		jLabelThreshold.setSize(60, 40);
+		jLabelThreshold.setEnabled(jCheckBoxModelFiltering.isSelected());
+		jLabelThreshold.setVisible(true);
+
+		SliderThreshold.setEnabled(jCheckBoxModelFiltering.isSelected());
+		SliderThreshold.setLocation(150, 65);
+		SliderThreshold.setSize(240, 45);
+		SliderThreshold.setValue(DEFAULT_THRESHOLD);
+		SliderThreshold.setVisible(true);
+		SliderThreshold.setToolTipText("Model filtering threshold");
+
+		PanelHeuristics.add(jCheckBoxClustering);
+		PanelHeuristics.add(jCheckBoxModelFiltering);
+		PanelHeuristics.add(SliderThreshold);
+		PanelHeuristics.add(jLabelThreshold);
+		// PanelHeuristics.add(jLabelSliderCaption);
+		PanelHeuristics.add(ButtonAICClustering);
+		PanelHeuristics.add(ButtonAICcClustering);
+		PanelHeuristics.add(ButtonBICClustering);
+
+		PanelCalcLike.setLocation(PANEL_X, PANEL_CALCLIKE_Y);
+		PanelCalcLike.setSize(460, 360);
+		PanelCalcLike.setBorder(new BorderUIResource.TitledBorderUIResource(
+				new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false),
+				"Likelihood settings", 4, 2, XManager.FONT_LABEL,
+				XManager.LABEL_BLUE_COLOR));
+		PanelCalcLike.setVisible(true);
+		PanelCalcLike.setLayout(null);
+
+		JButtonDefaultCalcLike.setText("Default Settings");
+		JButtonDefaultCalcLike.setLocation(10, 310);
+		JButtonDefaultCalcLike.setSize(141, 40);
+		JButtonDefaultCalcLike.setVisible(true);
+
+		CancelButtonCalcLike.setText("Cancel");
+		CancelButtonCalcLike.setLocation(160, 310);
+		CancelButtonCalcLike.setSize(110, 40);
+		CancelButtonCalcLike.setVisible(true);
+
+		RunButtonCalcLike.setText("Compute Likelihods");
+		RunButtonCalcLike.setLocation(280, 310);
+		RunButtonCalcLike.setSize(170, 40);
+		RunButtonCalcLike.setVisible(true);
+		getRootPane().setDefaultButton(RunButtonCalcLike);
+
+		PanelNumberModelsCalcLike.setLocation(20, 20);
+		PanelNumberModelsCalcLike.setSize(420, 50);
+		PanelNumberModelsCalcLike
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false),
+						"Number of substitution schemes", 4, 2,
+						XManager.FONT_LABEL, XManager.LABEL_BLUE_COLOR));
+		PanelNumberModelsCalcLike.setVisible(true);
+		PanelNumberModelsCalcLike.setLayout(null);
+		Button3SubsTypeCalcLike.setVisible(true);
+		Button3SubsTypeCalcLike.setSize(45, 20);
+		Button3SubsTypeCalcLike.setText("3");
+		Button3SubsTypeCalcLike.setLocation(20, 20);
+		Button5SubsTypeCalcLike.setVisible(true);
+		Button5SubsTypeCalcLike.setSize(45, 20);
+		Button5SubsTypeCalcLike.setText("5");
+		Button5SubsTypeCalcLike.setLocation(65, 20);
+		Button7SubsTypeCalcLike.setVisible(true);
+		Button7SubsTypeCalcLike.setSize(45, 20);
+		Button7SubsTypeCalcLike.setText("7");
+		Button7SubsTypeCalcLike.setLocation(110, 20);
+		Button11SubsTypeCalcLike.setVisible(true);
+		Button11SubsTypeCalcLike.setSize(50, 20);
+		Button11SubsTypeCalcLike.setText("11");
+		Button11SubsTypeCalcLike.setLocation(155, 20);
+		Button11SubsTypeCalcLike.setSelected(true);
+		Button203SubsTypeCalcLike.setVisible(true);
+		Button203SubsTypeCalcLike.setSize(60, 20);
+		Button203SubsTypeCalcLike.setText("203");
+		Button203SubsTypeCalcLike.setLocation(205, 20);
+		Button203SubsTypeCalcLike.setSelected(true);
+		ButtonGroupNumberModelsCalcLike.add(Button3SubsTypeCalcLike);
+		ButtonGroupNumberModelsCalcLike.add(Button5SubsTypeCalcLike);
+		ButtonGroupNumberModelsCalcLike.add(Button7SubsTypeCalcLike);
+		ButtonGroupNumberModelsCalcLike.add(Button11SubsTypeCalcLike);
+		ButtonGroupNumberModelsCalcLike.add(Button203SubsTypeCalcLike);
+		jLabelNumModels.setSize(165, 20);
+		jLabelNumModels.setLocation(275, 20);
+		jLabelNumModels.setAlignmentX(JLabel.CENTER_ALIGNMENT);
+		jLabelNumModels.setAlignmentY(JLabel.CENTER_ALIGNMENT);
+		jLabelNumModels.setVisible(true);
+		jLabelNumModels.setForeground(Color.gray);
+		jLabelNumModels.setFont(XManager.FONT_LABEL_BIG);
+
+		PanelFrequenciesCalcLike.setSize(130, 50);
+		PanelFrequenciesCalcLike
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false),
+						"Base frequencies", 4, 2, XManager.FONT_LABEL,
+						XManager.LABEL_BLUE_COLOR));
+		PanelFrequenciesCalcLike.setLocation(20, 80);
+		PanelFrequenciesCalcLike.setVisible(true);
+		PanelFrequenciesCalcLike.setLayout(null);
+		jCheckBoxFrequencies.setVisible(true);
+		jCheckBoxFrequencies.setSize(50, 20);
+		jCheckBoxFrequencies.setText("+F");
+		jCheckBoxFrequencies.setLocation(20, 20);
+		jCheckBoxFrequencies.setSelected(true);
+
+		PanelRateVariationCalcLike.setLocation(170, 80);
+		PanelRateVariationCalcLike.setSize(270, 50);
+		PanelRateVariationCalcLike
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false),
+						"Rate variation", 4, 2, XManager.FONT_LABEL,
+						XManager.LABEL_BLUE_COLOR));
+		PanelRateVariationCalcLike.setVisible(true);
+		PanelRateVariationCalcLike.setLayout(null);
+		jCheckBoxPinv.setLocation(20, 20);
+		jCheckBoxPinv.setSize(50, 20);
+		jCheckBoxPinv.setText("+I");
+		jCheckBoxPinv.setVisible(true);
+		jCheckBoxPinv.setSelected(true);
+		jCheckBoxGamma.setVisible(true);
+		jCheckBoxGamma.setSize(55, 20);
+		jCheckBoxGamma.setText("+G");
+		jCheckBoxGamma.setLocation(70, 20);
+		jCheckBoxGamma.setSelected(true);
+		TextFieldNcat.setEnabled(jCheckBoxGamma.isSelected());
+		TextFieldNcat
+				.setToolTipText("Number of rate categories for the discrete gamma distribution");
+		TextFieldNcat.setBorder(new BorderUIResource.TitledBorderUIResource(
+				new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false), "nCat",
+				4, 2, XManager.FONT_LABEL, XManager.LABEL_BLUE_COLOR));
+		TextFieldNcat.setVisible(true);
+		TextFieldNcat.setSize(65, 35);
+		TextFieldNcat.setText("4");
+		TextFieldNcat.setHorizontalAlignment(JTextField.RIGHT);
+		TextFieldNcat.setLocation(122, 10);
+
+		PanelTreeOptimizationCalcLike.setLocation(20, 140);
+		PanelTreeOptimizationCalcLike.setSize(420, 90);
+		PanelTreeOptimizationCalcLike
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false),
+						"Base tree for likelihood calculations", 4, 2,
+						XManager.FONT_LABEL, XManager.LABEL_BLUE_COLOR));
+		PanelTreeOptimizationCalcLike.setVisible(true);
+		PanelTreeOptimizationCalcLike.setLayout(null);
+
+		ButtonFixedCalcLike.setText("Fixed BIONJ-JC");
+		ButtonFixedCalcLike.setSize(160, 20);
+		ButtonFixedCalcLike.setLocation(20, 20);
+		ButtonFixedCalcLike.setVisible(true);
+
+		ButtonFixedUserTopologyCalcLike.setText("Fixed user topology");
+		ButtonFixedUserTopologyCalcLike.setLocation(200, 20);
+		ButtonFixedUserTopologyCalcLike.setSize(200, 20);
+		ButtonFixedUserTopologyCalcLike.setVisible(true);
+
+		ButtonBIONJCalcLike.setText("BIONJ");
+		ButtonBIONJCalcLike.setLocation(20, 57);
+		ButtonBIONJCalcLike.setSize(160, 20);
+		ButtonBIONJCalcLike.setVisible(true);
+
+		ButtonMLCalcLike.setText("ML optimized");
+		ButtonMLCalcLike.setLocation(200, 57);
+		ButtonMLCalcLike.setSize(200, 20);
+		ButtonMLCalcLike.setVisible(true);
+		ButtonMLCalcLike.setSelected(true);
+
+		enableTreeSearching(ButtonMLCalcLike.isSelected());
+
+		jLabelUserTopology.setLocation(194, 22);
+		jLabelUserTopology.setSize(300, 50);
+		jLabelUserTopology.setForeground(Color.gray);
+		jLabelUserTopology.setFont(XManager.FONT_LABEL_BIG);
+		jLabelUserTopology.setVisible(true);
+
+		ButtonGroupTreeOptimizationCalcLike.add(ButtonFixedCalcLike);
+		ButtonGroupTreeOptimizationCalcLike.add(ButtonBIONJCalcLike);
+		ButtonGroupTreeOptimizationCalcLike.add(ButtonMLCalcLike);
+		ButtonGroupTreeOptimizationCalcLike
+				.add(ButtonFixedUserTopologyCalcLike);
+
+		setLocation(XManager.MAIN_LOCATION);
+		getContentPane().setLayout(null);
+		setTitle("Likelihood settings");
+
+		PanelTreeOptimizationMethod.setLocation(95, 240);
+		PanelTreeOptimizationMethod.setSize(250, 60);
+		PanelTreeOptimizationMethod
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false),
+						"Base tree search", 4, 2, XManager.FONT_LABEL,
+						XManager.LABEL_BLUE_COLOR));
+		PanelTreeOptimizationMethod.setVisible(true);
+		PanelTreeOptimizationMethod.setLayout(null);
+
+		ButtonNNICalcLike.setText("NNI");
+		ButtonNNICalcLike.setLocation(20, 20);
+		ButtonNNICalcLike.setSize(70, 20);
+		ButtonNNICalcLike.setVisible(true);
+		ButtonNNICalcLike.setSelected(true);
+		ButtonNNICalcLike.setToolTipText("Nearest Neighbor Interchange");
+
+		ButtonSPRCalcLike.setText("SPR");
+		ButtonSPRCalcLike.setLocation(90, 20);
+		ButtonSPRCalcLike.setSize(70, 20);
+		ButtonSPRCalcLike.setVisible(true);
+		ButtonSPRCalcLike.setToolTipText("Subtree Pruning and Regrafting");
+
+		ButtonBestCalcLike.setText("Best");
+		ButtonBestCalcLike.setLocation(160, 20);
+		ButtonBestCalcLike.setSize(70, 20);
+		ButtonBestCalcLike.setVisible(true);
+		ButtonBestCalcLike
+				.setToolTipText("Best of NNI and SPR algorithms. Tests both of them (Slowest).");
+
+		ButtonGroupTreeSearchCalcLike.add(ButtonNNICalcLike);
+		ButtonGroupTreeSearchCalcLike.add(ButtonSPRCalcLike);
+		ButtonGroupTreeSearchCalcLike.add(ButtonBestCalcLike);
+
+		PanelCalcLike.add(RunButtonCalcLike);
+		PanelCalcLike.add(CancelButtonCalcLike);
+		PanelCalcLike.add(JButtonDefaultCalcLike);
+		PanelCalcLike.add(PanelNumberModelsCalcLike);
+		PanelCalcLike.add(PanelTreeOptimizationCalcLike);
+		PanelCalcLike.add(PanelTreeOptimizationMethod);
+		PanelCalcLike.add(PanelRateVariationCalcLike);
+		PanelCalcLike.add(PanelFrequenciesCalcLike);
+
+		PanelNumberModelsCalcLike.add(Button3SubsTypeCalcLike);
+		PanelNumberModelsCalcLike.add(Button5SubsTypeCalcLike);
+		PanelNumberModelsCalcLike.add(Button7SubsTypeCalcLike);
+		PanelNumberModelsCalcLike.add(Button11SubsTypeCalcLike);
+		PanelNumberModelsCalcLike.add(Button203SubsTypeCalcLike);
+		PanelNumberModelsCalcLike.add(jLabelNumModels);
+		PanelRateVariationCalcLike.add(jCheckBoxPinv);
+		PanelRateVariationCalcLike.add(jCheckBoxGamma);
+		PanelRateVariationCalcLike.add(TextFieldNcat);
+		PanelFrequenciesCalcLike.add(jCheckBoxFrequencies);
+		PanelTreeOptimizationCalcLike.add(ButtonFixedCalcLike);
+		PanelTreeOptimizationCalcLike.add(ButtonBIONJCalcLike);
+		PanelTreeOptimizationCalcLike.add(ButtonMLCalcLike);
+		PanelTreeOptimizationCalcLike.add(ButtonFixedUserTopologyCalcLike);
+		PanelTreeOptimizationMethod.add(ButtonNNICalcLike);
+		PanelTreeOptimizationMethod.add(ButtonSPRCalcLike);
+		PanelTreeOptimizationMethod.add(ButtonBestCalcLike);
+		// PanelTreeOptimizationCalcLike.add(ButtonFixedUserTreeCalcLike);
+		PanelTreeOptimizationCalcLike.add(jLabelUserTopology);
+		PanelTreeOptimizationCalcLike.add(jLabelUserTree);
+
+		getContentPane().add(PanelProcessors);
+		getContentPane().add(PanelCalcLike);
+		getContentPane().add(PanelHeuristics);
+
+		setSize(480, 630);
+		setResizable(false);
+
+		// Update number of models
+		CalculateNumberOfModels(null);
+
+		// event handling
+		RunButtonCalcLike.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				RunButtonCalcLikeActionPerformed(e);
+			}
+		});
+
+		CancelButtonCalcLike.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				CancelButtonCalcLikeActionPerformed(e);
+			}
+		});
+
+		JButtonDefaultCalcLike.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				JButtonDefaultCalcLikeActionPerformed(e);
+			}
+		});
+
+		SliderProcessors.addChangeListener(new ChangeListener() {
+
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				processorsSliderChangeListener(e);
+			}
+		});
+
+		jCheckBoxModelFiltering.addChangeListener(new ChangeListener() {
+
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				SliderThreshold.setEnabled(jCheckBoxModelFiltering.isSelected());
+				jLabelThreshold.setEnabled(jCheckBoxModelFiltering.isSelected());
+			}
+		});
+
+		SliderThreshold.addChangeListener(new ChangeListener() {
+
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				jLabelThreshold.setText(Utilities.format(
+						SliderThreshold.getValue() / 1000.0, 5, 3, false));
+			}
+		});
+
+		ActionListener subsSchemeButtonListener = new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				CalculateNumberOfModels(e);
+				jCheckBoxClustering.setSelected(Button203SubsTypeCalcLike
+						.isSelected());
+				ButtonAICClustering
+						.setEnabled(jCheckBoxClustering.isSelected());
+				ButtonAICcClustering.setEnabled(jCheckBoxClustering
+						.isSelected());
+				ButtonBICClustering
+						.setEnabled(jCheckBoxClustering.isSelected());
+			}
+		};
+		// common event handling for set of models
+		Button3SubsTypeCalcLike.addActionListener(subsSchemeButtonListener);
+		Button5SubsTypeCalcLike.addActionListener(subsSchemeButtonListener);
+		Button7SubsTypeCalcLike.addActionListener(subsSchemeButtonListener);
+		Button11SubsTypeCalcLike.addActionListener(subsSchemeButtonListener);
+		Button203SubsTypeCalcLike.addActionListener(subsSchemeButtonListener);
+		jCheckBoxPinv.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				CalculateNumberOfModels(e);
+			}
+		});
+		jCheckBoxGamma.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+
+				if (jCheckBoxGamma.isSelected())
+					TextFieldNcat.setEnabled(true);
+				else
+					TextFieldNcat.setEnabled(false);
+
+				CalculateNumberOfModels(e);
+			}
+		});
+
+		jCheckBoxFrequencies.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				CalculateNumberOfModels(e);
+			}
+		});
+
+		ButtonFixedUserTopologyCalcLike.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				ReadUserTopologyCalcLike(e);
+			}
+		});
+
+		ButtonBIONJCalcLike.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				enableTreeSearching(false);
+			}
+		});
+
+		ButtonFixedCalcLike.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				enableTreeSearching(false);
+			}
+		});
+
+		ButtonFixedUserTopologyCalcLike.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				enableTreeSearching(false);
+			}
+		});
+
+		ButtonMLCalcLike.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				enableTreeSearching(true);
+			}
+		});
+
+		/*
+		 * ButtonFixedUserTreeCalcLike.addActionListener(new ActionListener() {
+		 * public void actionPerformed(ActionEvent e) { ReadUserTreeCalcLike(e);
+		 * } });
+		 * 
+		 * 
+		 * CheckBoxFixedTopology.addActionListener(new ActionListener() { public
+		 * void actionPerformed(ActionEvent e) {
+		 * CheckBoxFixedTopologyActionPerformed(e); } });
+		 * 
+		 * 
+		 * CheckBoxOptimizeTopology.addActionListener(new ActionListener() {
+		 * public void actionPerformed(ActionEvent e) {
+		 * CheckBoxOptimizeTopologyActionPerformed(e); } });
+		 */
+		addWindowListener(new WindowAdapter() {
+			public void windowClosing(WindowEvent e) {
+				thisWindowClosing(e);
+			}
+		});
+
+		// END GENERATED CODE
+	}
+
+	private void enableTreeSearching(boolean enabled) {
+		ButtonNNICalcLike.setEnabled(enabled);
+		ButtonSPRCalcLike.setEnabled(enabled);
+		ButtonBestCalcLike.setEnabled(enabled);
+	}
+
+	private boolean mShown = false;
+
+	public void addNotify() {
+		super.addNotify();
+
+		if (mShown)
+			return;
+
+		// resize frame to account for menubar
+		JMenuBar jMenuBar = getJMenuBar();
+		if (jMenuBar != null) {
+			int jMenuBarHeight = jMenuBar.getPreferredSize().height;
+			Dimension dimension = getSize();
+			dimension.height += jMenuBarHeight;
+			setSize(dimension);
+
+			// move down components in layered pane
+			Component[] components = getLayeredPane().getComponentsInLayer(
+					JLayeredPane.DEFAULT_LAYER.intValue());
+			for (int i = 0; i < components.length; i++) {
+				Point location = components[i].getLocation();
+				location.move(location.x, location.y + jMenuBarHeight);
+				components[i].setLocation(location);
+			}
+		}
+
+		mShown = true;
+	}
+
+	// Close the window when the close box is clicked
+	void thisWindowClosing(WindowEvent e) {
+		setVisible(false);
+		dispose();
+		// System.exit(0);
+	}
+
+	public void RunButtonCalcLikeActionPerformed(ActionEvent e) {
+		try {
+			// set number of processors
+			options.setNumberOfThreads(SliderProcessors.getValue());
+
+			// get parameters
+			if (Button3SubsTypeCalcLike.isSelected())
+				options.setSubstTypeCode(0);
+			else if (Button5SubsTypeCalcLike.isSelected())
+				options.setSubstTypeCode(1);
+			else if (Button7SubsTypeCalcLike.isSelected())
+				options.setSubstTypeCode(2);
+			else if (Button11SubsTypeCalcLike.isSelected())
+				options.setSubstTypeCode(3);
+			else
+				options.setSubstTypeCode(4);
+
+			if (jCheckBoxFrequencies.isSelected())
+				options.doF = true;
+			else
+				options.doF = false;
+
+			if (jCheckBoxPinv.isSelected())
+				options.doI = true;
+			else
+				options.doI = false;
+
+			if (jCheckBoxGamma.isSelected()) {
+				options.doG = true;
+				options.numGammaCat = Integer.parseInt(TextFieldNcat.getText());
+			} else
+				options.doG = false;
+
+			CalculateNumberOfModels(e);
+
+			// base tree for ML calculations
+			if (ButtonFixedCalcLike.isSelected()) {
+				options.fixedTopology = true;
+				options.optimizeMLTopology = false;
+				options.userTopologyExists = false;
+				// ModelTest.userTreeExists = false;
+			} else if (ButtonBIONJCalcLike.isSelected()) {
+				options.fixedTopology = false;
+				options.optimizeMLTopology = false;
+				options.userTopologyExists = false;
+				// ModelTest.userTreeExists = false;
+			} else if (ButtonMLCalcLike.isSelected()) {
+				options.fixedTopology = false;
+				options.optimizeMLTopology = true;
+				options.userTopologyExists = false;
+				// ModelTest.userTreeExists = false;
+			} else if (ButtonFixedUserTopologyCalcLike.isSelected()) {
+				options.fixedTopology = false;
+				options.optimizeMLTopology = false;
+				options.userTopologyExists = true;
+				// ModelTest.userTreeExists = false;
+			}
+
+			if (ButtonNNICalcLike.isSelected()) {
+				options.treeSearchOperations = ApplicationOptions.TreeSearch.NNI;
+			} else if (ButtonSPRCalcLike.isSelected()) {
+				options.treeSearchOperations = ApplicationOptions.TreeSearch.SPR;
+			} else if (ButtonBestCalcLike.isSelected()) {
+				options.treeSearchOperations = ApplicationOptions.TreeSearch.BEST;
+			}
+			/*
+			 * else if (ButtonFixedUserTreeCalcLike.isSelected()) {
+			 * ModelTest.fixedTopology = false; ModelTest.optimizeMLTopology =
+			 * false; ModelTest.userTopologyExists = false;
+			 * ModelTest.userTreeExists = true; }
+			 */else { /* should not be here */
+			}
+
+			if (jCheckBoxClustering.isSelected()) {
+				if (ButtonAICClustering.isSelected()) {
+					options.setHeuristicInformationCriterion(InformationCriterion.IC_AIC);
+				} else if (ButtonAICcClustering.isSelected()) {
+					options.setHeuristicInformationCriterion(InformationCriterion.IC_AICc);
+				} else if (ButtonBICClustering.isSelected()) {
+					options.setHeuristicInformationCriterion(InformationCriterion.IC_BIC);
+				}
+			}
+
+			if (jCheckBoxModelFiltering.isSelected()) {
+				options.setGuidedSearchThreshold(SliderThreshold.getValue() / 1000.0);
+			} else {
+				options.setGuidedSearchThreshold(0.0d);
+			}
+			// build set of models
+			options.setCandidateModels();
+
+			// build progress frame
+			progressFrame = new Frame_Progress(options.getNumModels(), this,
+					options);
+
+			setVisible(false);
+			
+			// scroll to the bottom
+			XManager.getInstance()
+					.getPane()
+					.setCaretPosition(
+							XManager.getInstance().getPane().getDocument()
+									.getLength());
+			options.createLogFile();
+			options.createCkpFile();
+			
+			// run phyml
+			this.task = new ComputeLikelihoodTask();
+			this.runPhyml = task.getValue();
+
+			task.start();
+
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	public void JButtonDefaultCalcLikeActionPerformed(ActionEvent e) {
+		try {
+			SliderProcessors.setValue(DEFAULT_NUMBER_OF_THREADS);
+			Button11SubsTypeCalcLike.setSelected(true);
+			ButtonMLCalcLike.setSelected(true);
+			enableTreeSearching(ButtonMLCalcLike.isSelected());
+			ButtonBestCalcLike.setSelected(true);
+
+			jCheckBoxFrequencies.setSelected(true);
+			jCheckBoxPinv.setSelected(true);
+			jCheckBoxGamma.setSelected(true);
+			TextFieldNcat.setEnabled(true);
+			TextFieldNcat.setText("4");
+
+			jCheckBoxClustering.setSelected(false);
+			ButtonAICClustering.setEnabled(jCheckBoxClustering.isSelected());
+			ButtonAICcClustering.setEnabled(jCheckBoxClustering.isSelected());
+			ButtonBICClustering.setEnabled(jCheckBoxClustering.isSelected());
+			jCheckBoxModelFiltering.setSelected(false);
+			SliderThreshold.setValue(DEFAULT_THRESHOLD);
+
+			CalculateNumberOfModels(null);
+			jLabelUserTopology.setText("");
+			jLabelUserTree.setText("");
+
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	public void CancelButtonCalcLikeActionPerformed(ActionEvent e) {
+		try {
+			setVisible(false);
+			dispose();
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	public void CalculateNumberOfModels(ActionEvent e) {
+		int numberOfModels;
+		try {
+			if (Button3SubsTypeCalcLike.isSelected())
+				numberOfModels = 3;
+			else if (Button5SubsTypeCalcLike.isSelected())
+				numberOfModels = 5;
+			else if (Button7SubsTypeCalcLike.isSelected())
+				numberOfModels = 7;
+			else if (Button11SubsTypeCalcLike.isSelected())
+				numberOfModels = 11;
+			else
+				numberOfModels = 203;
+
+			if (jCheckBoxFrequencies.isSelected())
+				numberOfModels *= 2;
+
+			if (jCheckBoxPinv.isSelected() && jCheckBoxGamma.isSelected())
+				numberOfModels *= 4;
+			else if (jCheckBoxPinv.isSelected() || jCheckBoxGamma.isSelected())
+				numberOfModels *= 2;
+
+			options.setNumModels(numberOfModels);
+			jLabelNumModels.setText("NumModels = " + numberOfModels);
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+	}
+
+	private void processorsSliderChangeListener(ChangeEvent e) {
+		jLabelNumProcessors
+				.setText(String.valueOf(SliderProcessors.getValue()));
+	}
+
+	public void ReadUserTopologyCalcLike(ActionEvent e) {
+		FileDialog fc = new FileDialog(this,
+				"Load Newick tree file with branch lengths", FileDialog.LOAD);
+		fc.setDirectory(System.getProperty("user.dir"));
+		fc.setVisible(true);
+
+		String treefilename = fc.getFile();
+
+		if (treefilename != null) // menu not canceled
+		{
+			String treefilenameComplete = fc.getDirectory() + treefilename;
+			ModelTest.getMainConsole().print(
+					"Reading tree file \"" + treefilename + "\"...");
+			System.err.print("\nreading tree file \"" + treefilename + "\"...");
+
+			options.setInputTreeFile(new File(treefilename));
+
+			// read the tree in
+			Tree tree = null;
+			try {
+				tree = TreeUtilities.readTree(treefilenameComplete);
+			} catch (IOException e1) {
+				JOptionPane.showMessageDialog(this, "The specified file \""
+						+ treefilename + "\" cannot be found",
+						"jModelTest error", JOptionPane.ERROR_MESSAGE);
+				ModelTest.getMainConsole().println(" failed.\n");
+				ButtonMLCalcLike.setSelected(true);
+				;
+			} catch (TreeParseException e1) {
+				ModelTest.getMainConsole().println(" failed.\n");
+				System.err.println(" failed.\n");
+				ButtonMLCalcLike.setSelected(true);
+				;
+			}
+			if (tree != null) {
+				options.setUserTree(TreeUtilities.toNewick(tree, true, false,
+						false));
+				TextOutputStream out = new TextOutputStream(options
+						.getTreeFile().getAbsolutePath());
+				System.out.println("INPUT TREE: " + options.getUserTree());
+				out.print(options.getUserTree());
+				out.close();
+				jLabelUserTopology.setText(treefilename);
+				ModelTest.getMainConsole().println(" OK.");
+				System.err.println("OK.");
+			}
+		} else // file does not exists
+		{
+			ButtonMLCalcLike.setSelected(true);
+			enableTreeSearching(true);
+			// ModelTest.mainConsole.println ("\nOpen file canceled\n");
+		}
+	}
+
+	private class ComputeLikelihoodTask extends SwingWorker {
+
+		private RunPhyml runPhyml;
+
+		public ComputeLikelihoodTask() {
+			this.runPhyml = new RunPhymlThread(progressFrame, options,
+					ModelTest.getCandidateModels());
+		}
+
+		public Object construct() {
+			try {
+				Thread.sleep(1000);
+			} catch (InterruptedException e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+			this.runPhyml.execute();
+			return runPhyml;
+		}
+
+		public void interrupt() {
+			runPhyml.interruptThread();
+			super.interrupt();
+		}
+
+		public RunPhyml getValue() {
+			return runPhyml;
+		}
+
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_Consense.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_Consense.java
new file mode 100644
index 0000000..bafb9f7
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_Consense.java
@@ -0,0 +1,348 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Point;
+
+import javax.swing.JLayeredPane;
+import javax.swing.JMenuBar;
+
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.exe.RunConsense;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+
+public class Frame_Consense extends JModelTestFrame {
+
+	private static final long serialVersionUID = 201104031005L;
+
+	javax.swing.JPanel PanelConsense = new javax.swing.JPanel();
+	javax.swing.JButton RunButtonConsense = new javax.swing.JButton();
+	javax.swing.JButton CancelButtonConsense = new javax.swing.JButton();
+	javax.swing.JButton DefaultButtonConsense = new javax.swing.JButton();
+
+	javax.swing.JPanel PanelCriterion = new javax.swing.JPanel();
+	javax.swing.JRadioButton ButtonAIC = new javax.swing.JRadioButton();
+	javax.swing.JRadioButton ButtonAICc = new javax.swing.JRadioButton();
+	javax.swing.JRadioButton ButtonBIC = new javax.swing.JRadioButton();
+	javax.swing.JRadioButton ButtonDT = new javax.swing.JRadioButton();
+	javax.swing.ButtonGroup ButtonGroupCriterion = new javax.swing.ButtonGroup();
+
+	javax.swing.JPanel PanelConsensus = new javax.swing.JPanel();
+	javax.swing.JRadioButton ButtonMajority = new javax.swing.JRadioButton();
+	javax.swing.JRadioButton ButtonStrict = new javax.swing.JRadioButton();
+	javax.swing.ButtonGroup ButtonGroupConsensus = new javax.swing.ButtonGroup();
+
+	public static javax.swing.JSlider JSliderInterval = new javax.swing.JSlider();
+
+
+	public RunConsense runConsense;
+
+	public Frame_Consense() {
+	}
+
+	public void initComponents() throws Exception {
+		PanelConsense.setSize(new java.awt.Dimension(490, 210));
+		PanelConsense.setBorder(new javax.swing.plaf.BorderUIResource.TitledBorderUIResource(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Phylogenetic averaging", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		PanelConsense.setLocation(new java.awt.Point(10, 10));
+		PanelConsense.setVisible(true);
+		PanelConsense.setLayout(null);
+		RunButtonConsense.setVisible(true);
+		RunButtonConsense.setSize(new java.awt.Dimension(190, 40));
+		RunButtonConsense.setText("Run");
+		RunButtonConsense.setLocation(new java.awt.Point(280, 160));
+		getRootPane().setDefaultButton(RunButtonConsense);
+		CancelButtonConsense.setVisible(true);
+		CancelButtonConsense.setSize(new java.awt.Dimension(110, 40));
+		CancelButtonConsense.setText("Cancel");
+		CancelButtonConsense.setLocation(new java.awt.Point(160, 160));
+		DefaultButtonConsense.setVisible(true);
+		DefaultButtonConsense.setSize(new java.awt.Dimension(141, 40));
+		DefaultButtonConsense.setText("Default Settings");
+		DefaultButtonConsense.setLocation(new java.awt.Point(10, 160));
+		
+		PanelCriterion.setSize(new java.awt.Dimension(300, 50));
+		PanelCriterion.setBorder(new javax.swing.plaf.BorderUIResource.TitledBorderUIResource(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Criterion for tree weights", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		PanelCriterion.setLocation(new java.awt.Point(20, 20));
+		PanelCriterion.setVisible(true);
+		PanelCriterion.setLayout(null);
+		ButtonAIC.setVisible(true);
+		ButtonAIC.setSize(new java.awt.Dimension(60, 20));
+		ButtonAIC.setText("AIC");
+		ButtonAIC.setLocation(new java.awt.Point(20, 20));
+		ButtonAICc.setVisible(true);
+		ButtonAICc.setSize(new java.awt.Dimension(60, 20));
+		ButtonAICc.setText("AICc");
+		ButtonAICc.setLocation(new java.awt.Point(90, 20));
+		ButtonBIC.setVisible(true);
+		ButtonBIC.setSize(new java.awt.Dimension(60, 20));
+		ButtonBIC.setText("BIC");
+		ButtonBIC.setLocation(new java.awt.Point(160, 20));
+		ButtonDT.setVisible(true);
+		ButtonDT.setSize(new java.awt.Dimension(60, 20));
+		ButtonDT.setText("DT");
+		ButtonDT.setLocation(new java.awt.Point(230, 20));
+
+		PanelConsensus.setSize(new java.awt.Dimension(240, 50));
+		PanelConsensus.setBorder(new javax.swing.plaf.BorderUIResource.TitledBorderUIResource(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Consensus type", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		PanelConsensus.setLocation(new java.awt.Point(20, 80));
+		PanelConsensus.setVisible(true);
+		PanelConsensus.setLayout(null);
+		ButtonMajority.setVisible(true);
+		ButtonMajority.setSize(new java.awt.Dimension(120, 20));
+		ButtonMajority.setText("Majority rule");
+		ButtonMajority.setLocation(new java.awt.Point(20, 20));
+		ButtonMajority.setSelected(true);
+		ButtonStrict.setVisible(true);
+		ButtonStrict.setSize(new java.awt.Dimension(80, 20));
+		ButtonStrict.setText("Strict");
+		ButtonStrict.setLocation(new java.awt.Point(140, 20));
+
+		ButtonAIC.setEnabled(ModelTest.testAIC());
+		ButtonAICc.setEnabled(ModelTest.testAICc());
+		ButtonBIC.setEnabled(ModelTest.testBIC());
+		ButtonDT.setEnabled(ModelTest.testDT());
+		if (ButtonAIC.isEnabled())
+			ButtonAIC.setSelected(true);
+		else if (ButtonAICc.isEnabled())
+			ButtonAICc.setSelected(true);
+		else if (ButtonBIC.isEnabled())
+			ButtonBIC.setSelected(true);
+		else if (ButtonDT.isEnabled())
+			ButtonDT.setSelected(true);
+	
+		ButtonGroupCriterion.add(ButtonAIC);
+		ButtonGroupCriterion.add(ButtonAICc);
+		ButtonGroupCriterion.add(ButtonBIC);
+		ButtonGroupCriterion.add(ButtonDT);
+
+		PanelCriterion.add(ButtonAIC);
+		PanelCriterion.add(ButtonAICc);
+		PanelCriterion.add(ButtonBIC);
+		PanelCriterion.add(ButtonDT);
+
+		ButtonGroupConsensus.add(ButtonMajority);
+		ButtonGroupConsensus.add(ButtonStrict);
+		PanelConsensus.add(ButtonMajority);
+		PanelConsensus.add(ButtonStrict);
+
+		JSliderInterval.setVisible(true);
+		JSliderInterval.setToolTipText("Set the confidence interval for model averaging and/or parameter importance");
+		JSliderInterval.setBorder(new javax.swing.plaf.BorderUIResource.TitledBorderUIResource(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Confidence interval = 100%", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		JSliderInterval.setSize(new java.awt.Dimension(170, 70));
+		JSliderInterval.setLocation(new java.awt.Point(280, 80));
+		JSliderInterval.setMinimum(0);
+		JSliderInterval.setMaximum(100);
+		JSliderInterval.setValue(100);
+		JSliderInterval.setMajorTickSpacing(20);
+		JSliderInterval.setMinorTickSpacing(5);
+		JSliderInterval.setPaintTicks(true);
+		JSliderInterval.setPaintLabels(true);	
+		JSliderInterval.setEnabled(true);
+		JSliderInterval.setFont(XManager.FONT_SLIDER);
+		setLocation(new java.awt.Point(281, 80));
+		getContentPane().setLayout(null);
+		setTitle("Phylogenetic averaging settings");
+
+		PanelConsense.add(PanelCriterion);
+		PanelConsense.add(PanelConsensus);
+		PanelConsense.add(JSliderInterval);
+		PanelConsense.add(RunButtonConsense);
+		PanelConsense.add(CancelButtonConsense);
+		PanelConsense.add(DefaultButtonConsense);
+
+		getContentPane().add(PanelConsense);
+
+		setSize(new java.awt.Dimension(510, 250));
+		setResizable(false);
+
+		// event handling
+		RunButtonConsense.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				RunButtonConsenseActionPerformed(e);
+			}
+		});
+
+		CancelButtonConsense.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				CancelButtonConsenseActionPerformed(e);
+			}
+		});
+
+	
+		DefaultButtonConsense.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				DefaultButtonConsenseActionPerformed(e);
+			}
+		});
+
+		JSliderInterval.addChangeListener(new javax.swing.event.ChangeListener() {
+			public void stateChanged(javax.swing.event.ChangeEvent e) {
+				JSliderIntervalStateChanged(e);
+			}
+		});
+
+
+		addWindowListener(new java.awt.event.WindowAdapter() {
+			public void windowClosing(java.awt.event.WindowEvent e) {
+				thisWindowClosing(e);
+			}
+		});
+
+// END GENERATED CODE
+	}
+  
+  	private boolean mShown = false;
+  	
+	public void addNotify() {
+		super.addNotify();
+		
+		if (mShown)
+			return;
+			
+		// resize frame to account for menubar
+		JMenuBar jMenuBar = getJMenuBar();
+		if (jMenuBar != null) {
+			int jMenuBarHeight = jMenuBar.getPreferredSize().height;
+			Dimension dimension = getSize();
+			dimension.height += jMenuBarHeight;
+			setSize(dimension);
+			
+			// move down components in layered pane
+			Component[] components = getLayeredPane().getComponentsInLayer(JLayeredPane.DEFAULT_LAYER.intValue());
+			for (int i = 0; i < components.length; i++) {
+				Point location = components[i].getLocation();
+				location.move(location.x, location.y + jMenuBarHeight);
+				components[i].setLocation(location);
+			}
+		}
+
+		mShown = true;
+	}
+
+	// Close the window when the close box is clicked
+	void thisWindowClosing(java.awt.event.WindowEvent e) {
+		setVisible(false);
+		dispose();
+		//System.exit(0);
+	}
+	
+	public void JSliderIntervalStateChanged(javax.swing.event.ChangeEvent e) 
+		{
+		JSliderInterval.setBorder(new javax.swing.plaf.BorderUIResource.TitledBorderUIResource(new javax.swing.border.LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Confidence interval = " + JSliderInterval.getValue() + "%", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		}
+
+
+	public void RunButtonConsenseActionPerformed(java.awt.event.ActionEvent e)
+		{
+		InformationCriterion criterion;
+		String consensusType;
+
+		double	credibleInterval;
+		
+		try
+			{
+			// get criterion
+			if (ButtonAIC.isSelected()) {
+				criterion = ModelTest.getMyAIC();
+			}
+			else if (ButtonAICc.isSelected()) {
+				criterion = ModelTest.getMyAICc();
+			}
+			else if (ButtonBIC.isSelected()) {
+				criterion = ModelTest.getMyBIC();
+			}
+			else {
+				criterion = ModelTest.getMyDT();
+			}
+
+			// get consensus type
+			if (ButtonMajority.isSelected())
+				consensusType = "50% majority rule";
+			else
+				consensusType = "strict";
+
+			credibleInterval = JSliderInterval.getValue()/100.0;
+
+			setVisible(false);
+			dispose();
+
+			// run consense
+			runConsense = new RunConsense(criterion, consensusType, credibleInterval);
+
+			if (ButtonAIC.isSelected()) {
+				ModelTest.setConsensusAIC(runConsense);
+			}
+			else if (ButtonAICc.isSelected()) {
+				ModelTest.setConsensusAICc(runConsense);
+			}
+			else if (ButtonBIC.isSelected()) {
+				ModelTest.setConsensusBIC(runConsense);
+			}
+			else {
+				ModelTest.setConsensusDT(runConsense);
+			}
+			}
+		catch (Exception f) 
+			{
+			f.printStackTrace();
+			}
+		}
+
+	public void DefaultButtonConsenseActionPerformed (java.awt.event.ActionEvent e)
+		{
+		try
+			{
+			if (ModelTest.testAIC())
+				ButtonAIC.setSelected(true);
+			else if (ModelTest.testAICc())
+				ButtonAICc.setSelected(true);
+			else if (ModelTest.testBIC())
+				ButtonBIC.setSelected(true);
+			else if (ModelTest.testDT())
+				ButtonDT.setEnabled(true);
+
+			ButtonMajority.setSelected(true);
+
+			JSliderInterval.setValue(100);
+
+			}
+		catch (Exception f) 
+			{
+			f.printStackTrace();
+			}
+		}
+
+
+
+	public void CancelButtonConsenseActionPerformed (java.awt.event.ActionEvent e)
+		{
+		try
+			{
+			setVisible(false);
+			dispose();
+			}
+		catch (Exception f) 
+			{
+			f.printStackTrace();
+			}
+		}
+
+	
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_DT.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_DT.java
new file mode 100644
index 0000000..1f87379
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_DT.java
@@ -0,0 +1,313 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Point;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenuBar;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JTextField;
+import javax.swing.border.LineBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.BorderUIResource;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.selection.DT;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class Frame_DT extends JModelTestFrame {
+
+	private static final long serialVersionUID = 201104031100L;
+	
+	private JPanel panelDTSettings = new JPanel();
+	private JTextField textTaxaDT = new JTextField();
+	private JTextField textSizeDT = new JTextField();
+	private JButton runButtonDT = new JButton();
+	private JButton cancelButtonDT = new JButton();
+	private JButton buttonDefaultDT = new JButton();
+
+	private JCheckBox checkBoxIncludeBL_DT = new JCheckBox();
+	private JCheckBox checkBoxPAUPblock = new JCheckBox();
+	private JCheckBox checkBoxAveraging = new JCheckBox();
+	private JCheckBox checkBoxImportance = new JCheckBox();
+	private JSlider sliderInterval = new JSlider();
+
+	private DT myDT;
+
+	public Frame_DT() {
+	}
+
+	public void initComponents() throws Exception {
+		panelDTSettings.setSize(490, 240);
+		panelDTSettings.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "DT Settings", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		panelDTSettings.setLocation(10, 10);
+		panelDTSettings.setVisible(true);
+		panelDTSettings.setLayout(null);
+
+		runButtonDT.setVisible(true);
+		runButtonDT.setSize(190, 40);
+		runButtonDT.setText("Do DT calculations");
+		runButtonDT.setLocation(280, 190);
+		getRootPane().setDefaultButton(runButtonDT);
+
+		buttonDefaultDT.setVisible(true);
+		buttonDefaultDT.setSize(141, 40);
+		buttonDefaultDT.setText("Default Settings");
+		buttonDefaultDT.setLocation(10, 190);
+
+		cancelButtonDT.setVisible(true);
+		cancelButtonDT.setSize(110, 40);
+		cancelButtonDT.setText("Cancel");
+		cancelButtonDT.setLocation(160, 190);
+
+		textSizeDT.setToolTipText("Enter the sample size you want to use for the DT and click RETURN. By default this is the number of sites in the alignment");
+		textSizeDT.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Sample size", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		textSizeDT.setVisible(true);
+		textSizeDT.setSize(100, 40);
+		textSizeDT.setText(Utilities.format(options.getSampleSize(),10,4,false));
+		textSizeDT.setHorizontalAlignment(JTextField.RIGHT);
+		textSizeDT.setLocation(30, 20);
+		textSizeDT.setEnabled(false);
+
+		checkBoxImportance.setVisible(true);
+		checkBoxImportance.setSize(260, 20);
+		checkBoxImportance.setText("Calculate parameter importances");
+		checkBoxImportance.setLocation(30, 70);
+		checkBoxImportance.setSelected(true);
+
+		checkBoxAveraging.setVisible(true);
+		checkBoxAveraging.setSize(260, 20);
+		checkBoxAveraging.setText("Do model averaging");
+		checkBoxAveraging.setLocation(30, 110);
+		checkBoxAveraging.setSelected(true);
+
+		checkBoxPAUPblock.setVisible(true);
+		checkBoxPAUPblock.setSize(260, 20);
+		checkBoxPAUPblock.setText("Write PAUP* block");
+		checkBoxPAUPblock.setLocation(30, 150);
+		checkBoxPAUPblock.setSelected(false);
+		checkBoxPAUPblock.setToolTipText("Writes a block of PAUP* commands implementing the selected model");
+
+		sliderInterval.setVisible(true);
+		sliderInterval.setToolTipText("Set the confidence interval for model averaging and/or parameter importance");
+		sliderInterval.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Confidence interval = 100%", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		sliderInterval.setSize(170, 70);
+		sliderInterval.setLocation(300, 70);
+		sliderInterval.setMinimum(0);
+		sliderInterval.setMaximum(100);
+		sliderInterval.setValue(100);
+		sliderInterval.setMajorTickSpacing(20);
+		sliderInterval.setMinorTickSpacing(5);
+		sliderInterval.setPaintTicks(true);
+		sliderInterval.setPaintLabels(true);	
+		sliderInterval.setEnabled(true);
+		sliderInterval.setFont(XManager.FONT_SLIDER);
+					
+		setLocation(281, 80);
+		getContentPane().setLayout(null);
+		setTitle("Decision Theory (DT) Settings");
+
+		panelDTSettings.add(textTaxaDT);
+		panelDTSettings.add(textSizeDT);
+		panelDTSettings.add(checkBoxIncludeBL_DT);
+		panelDTSettings.add(checkBoxAveraging);
+		panelDTSettings.add(checkBoxImportance);
+		panelDTSettings.add(checkBoxPAUPblock);
+		panelDTSettings.add(sliderInterval);
+		panelDTSettings.add(buttonDefaultDT);
+		panelDTSettings.add(cancelButtonDT);
+		panelDTSettings.add(runButtonDT);
+		getContentPane().add(panelDTSettings);
+
+		setSize(510, 280);
+		setResizable(false);
+
+		checkBoxAveraging.addChangeListener(new ChangeListener() {
+			public void stateChanged(ChangeEvent e) {
+				jCheckBoxAveragingStateChanged(e);
+			}
+		});
+
+		checkBoxImportance.addChangeListener(new ChangeListener() {
+			public void stateChanged(ChangeEvent e) {
+				jCheckBoxImportanceStateChanged(e);
+			}
+		});
+
+		sliderInterval.addChangeListener(new ChangeListener() {
+			public void stateChanged(ChangeEvent e) {
+				JSliderIntervalStateChanged(e);
+			}
+		});
+
+		buttonDefaultDT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				JButtonDefaultDTActionPerformed(e);
+			}
+		});
+		cancelButtonDT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				CancelButtonDTActionPerformed(e);
+			}
+		});
+		runButtonDT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				RunButtonDTActionPerformed(e);
+			}
+		});
+
+		addWindowListener(new java.awt.event.WindowAdapter() {
+			public void windowClosing(java.awt.event.WindowEvent e) {
+				thisWindowClosing(e);
+			}
+		});
+
+	}
+  
+  	private boolean mShown = false;
+  	
+	public void addNotify() {
+		super.addNotify();
+		
+		if (mShown)
+			return;
+			
+		// resize frame to account for menubar
+		JMenuBar jMenuBar = getJMenuBar();
+		if (jMenuBar != null) {
+			int jMenuBarHeight = jMenuBar.getPreferredSize().height;
+			Dimension dimension = getSize();
+			dimension.height += jMenuBarHeight;
+			setSize(dimension);
+			
+			// move down components in layered pane
+			Component[] components = getLayeredPane().getComponentsInLayer(JLayeredPane.DEFAULT_LAYER.intValue());
+			for (int i = 0; i < components.length; i++) {
+				Point location = components[i].getLocation();
+				location.move(location.x, location.y + jMenuBarHeight);
+				components[i].setLocation(location);
+			}
+		}
+
+		mShown = true;
+	}
+
+	// Close the window when the close box is clicked
+	void thisWindowClosing(java.awt.event.WindowEvent e) {
+		setVisible(false);
+		dispose();
+		//System.exit(0);
+	}
+	
+	public void jCheckBoxImportanceStateChanged(ChangeEvent e) 
+		{
+		if (checkBoxImportance.isSelected())
+			{
+			sliderInterval.setEnabled(true);
+			}
+		else
+			{
+			if (!checkBoxAveraging.isSelected())
+				sliderInterval.setEnabled(false);
+			}
+		}
+
+	public void jCheckBoxAveragingStateChanged(ChangeEvent e) 
+		{
+		if (checkBoxAveraging.isSelected())
+			{
+			sliderInterval.setEnabled(true);
+			}
+		else
+			{
+			if (!checkBoxImportance.isSelected())
+				sliderInterval.setEnabled(false);
+			}
+		}
+	
+
+	public void JSliderIntervalStateChanged(ChangeEvent e) 
+		{
+		sliderInterval.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Confidence interval = " + sliderInterval.getValue() + "%", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		}
+
+				
+	public void JButtonDefaultDTActionPerformed(java.awt.event.ActionEvent e) 
+		{
+		textSizeDT.setEnabled(false);
+		ApplicationOptions.getInstance().countBLasParameters = true;
+		XManager.getInstance().selectedMenuResultsBLasParameters(true);
+		checkBoxPAUPblock.setSelected(false);
+		checkBoxAveraging.setSelected(true);
+		checkBoxImportance.setSelected(true);
+		sliderInterval.setValue(100);
+		}
+	
+	public void CancelButtonDTActionPerformed(java.awt.event.ActionEvent e) 
+		{
+		try
+			{
+			setVisible(false);
+			dispose();
+			}
+		catch (Exception f) 
+			{
+			f.printStackTrace();
+			}
+		}
+	
+	public void RunButtonDTActionPerformed(java.awt.event.ActionEvent e) 
+		{
+		boolean	writePAUPblock, doImportances, doModelAveraging;
+		double	credibleInterval;
+
+		try
+			{
+			setVisible(false);
+			dispose();
+
+			writePAUPblock = checkBoxPAUPblock.isSelected();
+			options.writePAUPblock |= writePAUPblock;
+			doImportances = checkBoxImportance.isSelected();
+			doModelAveraging = checkBoxAveraging.isSelected();
+			credibleInterval = sliderInterval.getValue()/100.0;
+			
+			myDT = new DT(writePAUPblock, doImportances, doModelAveraging, credibleInterval);
+			myDT.compute();
+			myDT.print(ModelTest.getCurrentOutStream());
+			ModelTest.setMyDT(myDT);
+			options.doDT = myDT != null;
+			XManager.getInstance().resultsFrame.enablePane(FrameResults.TAB_DT);
+			XManager.getInstance().resultsFrame.populate(FrameResults.TAB_DT);
+			XManager.getInstance().enableMenuAveraging(!options.fixedTopology);
+			}
+		catch (Exception f) 
+			{
+			f.printStackTrace();
+			}
+		}
+	
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_LRTcalculator.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_LRTcalculator.java
new file mode 100644
index 0000000..1dc5675
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_LRTcalculator.java
@@ -0,0 +1,363 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Point;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenuBar;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.border.LineBorder;
+import javax.swing.plaf.BorderUIResource;
+
+import es.uvigo.darwin.jmodeltest.statistics.Statistics;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class Frame_LRTcalculator extends JModelTestFrame {
+
+	private static final long serialVersionUID = 3100651418525568495L;
+	
+	private JPanel jPanelLRTsettings = new JPanel();
+	private JButton jButtonRunLRT = new JButton();
+	private JButton jButtonCancelLRT = new JButton();
+	private JButton jButtonDefaultLRT = new JButton();
+	private JTextField jTextFieldLRT0 = new JTextField();
+	private JTextField jTextFieldLRT1 = new JTextField();
+	private JLabel jLabelLRTpvalue = new JLabel();
+	private JLabel jLabelLRT = new JLabel();
+	private JTextField jTextFieldLRTdf = new JTextField();
+	private JPanel PanelChi2Type = new JPanel();
+	private JRadioButton ButtonStandardChi = new JRadioButton();
+	private JRadioButton ButtonMixedChi = new JRadioButton();
+	private ButtonGroup ButtonGroupChi = new ButtonGroup();
+
+	public Frame_LRTcalculator() {
+	}
+
+	public void initComponents() throws Exception {
+		// Dimensions(width, height));
+		jPanelLRTsettings.setSize(new java.awt.Dimension(480, 270));
+		jPanelLRTsettings.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Likelihood Ratio Test for Nested Models", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		jPanelLRTsettings.setLocation(new java.awt.Point(10, 10));
+		jPanelLRTsettings.setVisible(true);
+		jPanelLRTsettings.setLayout(null);
+
+		jTextFieldLRT0.setToolTipText("Enter here the absolute log likelihood of the simple model");
+		jTextFieldLRT0.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "-lnL null model", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		jTextFieldLRT0.setVisible(true);
+		jTextFieldLRT0.setSize(new java.awt.Dimension(150, 50));
+		jTextFieldLRT0.setLocation(new java.awt.Point(30, 30));
+
+		jTextFieldLRT1.setToolTipText("Enter here the absolute log likelihood of the complex model");
+		jTextFieldLRT1.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "-ln alternative model", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		jTextFieldLRT1.setVisible(true);
+		jTextFieldLRT1.setSize(new java.awt.Dimension(150, 50));
+		jTextFieldLRT1.setLocation(new java.awt.Point(220, 30));
+
+		jTextFieldLRTdf.setToolTipText("Enter here the difference in free parameters between the two models");
+		jTextFieldLRTdf.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "degrees of freedom", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		jTextFieldLRTdf.setVisible(true);
+		jTextFieldLRTdf.setSize(new java.awt.Dimension(150, 50));
+		jTextFieldLRTdf.setLocation(new java.awt.Point(30, 90));
+
+		jLabelLRT.setSize(new java.awt.Dimension(330, 40));
+		jLabelLRT.setLocation(new java.awt.Point(30, 145));
+		jLabelLRT.setVisible(true);
+		jLabelLRT.setText("LRT = ");
+
+		jLabelLRTpvalue.setSize(new java.awt.Dimension(330, 40));
+		jLabelLRTpvalue.setLocation(new java.awt.Point(30, 175));
+		jLabelLRTpvalue.setVisible(true);
+		jLabelLRTpvalue.setText("P-value =");
+
+		PanelChi2Type.setSize(new java.awt.Dimension(210, 50));
+		PanelChi2Type.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Chi-square distribution", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		PanelChi2Type.setLocation(new java.awt.Point(220, 90));
+		PanelChi2Type.setVisible(true);
+		PanelChi2Type.setLayout(null);
+		ButtonStandardChi.setVisible(true);
+		ButtonStandardChi.setSize(new java.awt.Dimension(100, 20));
+		ButtonStandardChi.setText("Standard");
+		ButtonStandardChi.setLocation(new java.awt.Point(20, 20));
+		ButtonStandardChi.setToolTipText("Select this if the value of the restricted parameter in the null model is not at the boundary of its range");
+		ButtonStandardChi.setSelected(true);
+		ButtonMixedChi.setVisible(true);
+		ButtonMixedChi.setSize(new java.awt.Dimension(70, 20));
+		ButtonMixedChi.setText("Mixed");
+		ButtonMixedChi.setToolTipText("Select this if the value of the restricted parameter in the null model is at the boundary of its range");
+		ButtonMixedChi.setLocation(new java.awt.Point(125, 20));
+		ButtonGroupChi.add(ButtonStandardChi);
+		ButtonGroupChi.add(ButtonMixedChi);
+		PanelChi2Type.add(ButtonStandardChi);
+		PanelChi2Type.add(ButtonMixedChi);
+
+		jButtonDefaultLRT.setVisible(true);
+		jButtonDefaultLRT.setSize(new java.awt.Dimension(141, 40));
+		jButtonDefaultLRT.setText("Default Settings");
+		jButtonDefaultLRT.setLocation(new java.awt.Point(30, 220));
+
+		jButtonCancelLRT.setVisible(true);
+		jButtonCancelLRT.setSize(new java.awt.Dimension(110, 40));
+		jButtonCancelLRT.setText("Cancel");
+		jButtonCancelLRT.setLocation(new java.awt.Point(190, 220));
+
+		jButtonRunLRT.setVisible(true);
+		jButtonRunLRT.setSize(new java.awt.Dimension(110, 40));
+		jButtonRunLRT.setText("Run");
+		jButtonRunLRT.setLocation(new java.awt.Point(320, 220));
+		jButtonRunLRT.setToolTipText("Remember that models have to be nested!");
+
+
+		setLocation(new java.awt.Point(281, 80));
+		getContentPane().setLayout(null);
+		setTitle("LRT calculator");
+
+		jPanelLRTsettings.add(jTextFieldLRT0);
+		jPanelLRTsettings.add(jTextFieldLRT1);
+		jPanelLRTsettings.add(jTextFieldLRTdf);
+		jPanelLRTsettings.add(jButtonDefaultLRT);
+		jPanelLRTsettings.add(jButtonCancelLRT);
+		jPanelLRTsettings.add(jButtonRunLRT);
+		jPanelLRTsettings.add(jLabelLRT);
+		jPanelLRTsettings.add(jLabelLRTpvalue);
+		jPanelLRTsettings.add(PanelChi2Type);
+		getContentPane().add(jPanelLRTsettings);
+
+		setSize(new java.awt.Dimension(500, 310));
+		setResizable(false);
+		
+		
+		
+		// event handling
+		jButtonDefaultLRT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				jButtonDefaultLRTActionPerformed(e);
+			}
+		});
+		jButtonCancelLRT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				jButtonCancelLRTActionPerformed(e);
+			}
+		});
+		jButtonRunLRT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				jButtonRunLRTActionPerformed(e);
+			}
+		});
+
+
+		addWindowListener(new java.awt.event.WindowAdapter() {
+			public void windowClosing(java.awt.event.WindowEvent e) {
+			
+				thisWindowClosing(e);
+			}
+		});
+
+	}
+  
+  
+  	private boolean mShown = false;
+  	
+	public void addNotify() {
+		super.addNotify();
+		
+		if (mShown)
+			return;
+			
+		// resize frame to account for menubar
+		JMenuBar jMenuBar = getJMenuBar();
+		if (jMenuBar != null) {
+			int jMenuBarHeight = jMenuBar.getPreferredSize().height;
+			Dimension dimension = getSize();
+			dimension.height += jMenuBarHeight;
+			setSize(dimension);
+			
+			// move down components in layered pane
+			Component[] components = getLayeredPane().getComponentsInLayer(JLayeredPane.DEFAULT_LAYER.intValue());
+			for (int i = 0; i < components.length; i++) {
+				Point location = components[i].getLocation();
+				location.move(location.x, location.y + jMenuBarHeight);
+				components[i].setLocation(location);
+			}
+		}
+
+		mShown = true;
+	}
+
+	// Close the window when the close box is clicked
+	void thisWindowClosing(java.awt.event.WindowEvent e) {
+		setVisible(false);
+		dispose();
+		//System.exit(0);
+	}
+
+
+
+  
+/**************************** LRT **************************************
+ *																		*
+ *	Computes a likelihood ratio test given a LRT and df					*					
+ *	Returns  P-value according to a standard chi2 distribution			*	
+ *																		*
+ ***********************************************************************/
+
+	public double LRT (double delta, int df)
+		{
+		double prob;
+		
+		if (delta == 0)
+			prob = 1.0;
+		else
+			prob = Statistics.chiSquareProbability (delta, df);
+	
+		return prob;
+		}
+
+ /**************************** LRTboundary *****************************
+ *																		*
+ *	Computes a likelihood ratio test given a LRT and df					*					
+ *	Returns  P-value according to a mixed chi2 distribution				*	
+ *																		*
+ ***********************************************************************/
+
+	static private double LRTboundary(double delta, int df)
+		{
+		double prob;
+
+		if (delta == 0)
+			prob = 1.0;
+		else
+			{
+			if (df == 1)
+				prob = Statistics.chiSquareProbability(delta,df)/2;
+			else	
+				prob= (Statistics.chiSquareProbability(delta,df-1) + 
+					Statistics.chiSquareProbability(delta,df)) / 2;
+			}
+
+		return prob;
+		}
+
+  
+  
+	public void jButtonRunLRTActionPerformed(java.awt.event.ActionEvent e) 
+		{
+		double	L0, L1, delta, pvalue;
+		int		df;
+		String sL0, sL1, sdf;
+
+		try
+			{
+			// get the strings from the text fields
+			sL0 = jTextFieldLRT0.getText();
+			sL1 = jTextFieldLRT1.getText();
+			sdf = jTextFieldLRTdf.getText();
+
+			// check for empty fields and numbers
+			if (sL0.length() == 0 || !Utilities.isNumber(sL0))
+					JOptionPane.showMessageDialog (new JFrame(), "Enter a positive likelihood for the null model (" + sL0 + ")",
+				"jModeltest error", JOptionPane.ERROR_MESSAGE); 
+			else if (sL1.length() == 0 || !Utilities.isNumber(sL1))
+					JOptionPane.showMessageDialog (new JFrame(), "Enter a positive likelihood for the alternative model",
+				"jModeltest error", JOptionPane.ERROR_MESSAGE);
+			else if (sdf.length() == 0 || !Utilities.isNumber(sdf))
+					JOptionPane.showMessageDialog (new JFrame(), "Enter a positive number of degrees of freedom",
+				"jModeltest error", JOptionPane.ERROR_MESSAGE); 
+			else
+				{
+				// get values
+				L0 = Double.parseDouble (sL0);
+				L1 = Double.parseDouble (sL1);
+				df = Integer.parseInt (sdf);
+				delta = 2 * (L0 - L1);
+								
+				// check for valid values
+				if (L0 <= 0 || Double.isNaN(L0))
+					JOptionPane.showMessageDialog (new JFrame(), "Enter a positive likelihood for the null model*",
+					"jModeltest error", JOptionPane.ERROR_MESSAGE); 
+				else if (L1 <= 0 || Double.isNaN(L1))
+					JOptionPane.showMessageDialog (new JFrame(), "Enter a positive likelihood for the alternative model*",
+					"jModeltest error", JOptionPane.ERROR_MESSAGE); 
+				else if (df <= 0 || Double.isNaN(df))
+					JOptionPane.showMessageDialog (new JFrame(), "Enter a positive number of degrees of freedom",
+					"jModeltest error", JOptionPane.ERROR_MESSAGE); 
+				else if (delta < 0)
+					JOptionPane.showMessageDialog (new JFrame(), "The likelihood of the null model cannot be bigger than the likelihood of the alternative model!",
+					"jModeltest error", JOptionPane.ERROR_MESSAGE); 
+				else
+					{
+					if (ButtonMixedChi.isSelected())
+						pvalue = LRTboundary(delta, df);
+					else
+						pvalue = LRT(delta, df);
+	
+					jLabelLRT.setText("LRT = " + Utilities.roundDoubleTo(delta,6));
+					jLabelLRTpvalue.setText("P-value = " + Utilities.roundDoubleTo(pvalue,6));
+					}
+				}			
+			}
+		catch (Exception f) 
+			{
+			f.printStackTrace();
+			}
+		}
+
+
+	public void jButtonDefaultLRTActionPerformed(java.awt.event.ActionEvent e) 
+		{
+		try
+			{
+			ButtonStandardChi.setSelected(true);
+			jTextFieldLRT0.setText("");
+			jTextFieldLRT1.setText("");
+			jTextFieldLRTdf.setText("");
+			jLabelLRT.setText("LRT = ");
+			jLabelLRTpvalue.setText("P-value =");
+			}
+		catch (Exception f) 
+			{
+			f.printStackTrace();
+			}
+		}
+
+
+	public void jButtonCancelLRTActionPerformed(java.awt.event.ActionEvent e) 
+		{
+		try
+			{
+			setVisible(false);
+			dispose();
+			}
+		catch (Exception f) 
+			{
+			f.printStackTrace();
+			}
+		}
+
+
+	
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_Progress.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_Progress.java
new file mode 100644
index 0000000..8305ee3
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_Progress.java
@@ -0,0 +1,663 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.util.Locale;
+import java.util.Observable;
+import java.util.Observer;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenuBar;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+import javax.swing.Timer;
+import javax.swing.border.LineBorder;
+import javax.swing.plaf.BorderUIResource;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.ModelTestConfiguration;
+import es.uvigo.darwin.jmodeltest.exe.ProcessManager;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+import es.uvigo.darwin.prottest.exe.ExternalExecutionManager;
+
+public class Frame_Progress extends JModelTestFrame implements Observer,
+		ActionListener {
+
+	private static final long serialVersionUID = 201102181036L;
+	private static final int LABEL_HEIGHT = 20;
+	private static final int THREAD_BAR_HEIGHT = 20;
+	private static final int PROGRESS_BAR_HEIGHT = 30;
+	private static final int WINDOW_WIDTH = 400;
+	private static final int H_MARGIN = 20;
+	private static final int V_MARGIN = 10;
+	private static final int V_INNER_MARGIN = 5;
+	private static final int SECTION_WIDTH = WINDOW_WIDTH - 2 * H_MARGIN;
+	private static final int HEADER_HEIGHT = LABEL_HEIGHT + 2 * V_INNER_MARGIN;
+	private static int FOOTER_HEIGHT = 2 * PROGRESS_BAR_HEIGHT + 3
+			* V_INNER_MARGIN;
+	private static final int THREADS_SECTIONS_VLOC = HEADER_HEIGHT + 2
+			* V_MARGIN;
+	private static final int HEIGHT_PER_THREAD = THREAD_BAR_HEIGHT
+			+ LABEL_HEIGHT + V_INNER_MARGIN;
+	private static final int BUTTON_WIDTH = 100;
+	private static final int THREAD_LABEL_WIDTH = 80;
+
+	private static final String NO_MODEL = "idle";
+	private static final long lockTime = 3000;
+	
+	private static final Color[] THREAD_COLOR = { new Color(177, 68, 68),
+			new Color(177, 68, 161), new Color(126, 68, 177),
+			new Color(68, 97, 177), new Color(68, 177, 162),
+			new Color(68, 177, 63), new Color(161, 177, 68),
+			new Color(177, 141, 48), new Color(177, 73, 68) };
+
+	private TextOutputStream stream;
+
+	private int numberOfThreads;
+
+	private JPanel headerPanel = new JPanel();
+	private JPanel threadsActivityPanel = new JPanel();
+	private JPanel footerPanel = new JPanel();
+
+	private JProgressBar threadProgressBar[];
+	private JLabel threadProgressLabel[];
+	private JLabel threadProgressModelLabel[];
+	private JButton progressBarCancelButton = new JButton();
+	private JProgressBar progressBarLike = new JProgressBar();
+	private JLabel progressBarLikeLabel = new JLabel();
+	private JLabel timerLabel = new JLabel();
+	private int maxNumOfModelsPerStage[] = new int[] { 1, 15, 10, 6, 3, 1 };
+	private JLabel footerStageLabel = new JLabel();
+
+	/** Timer for calculate the elapsed time **/
+	private volatile long startTime;
+	private volatile long lockTimer = 0;
+	
+	private Frame_CalcLike frameCalcLike;
+	private Timer timer;
+
+	private int completedModels = 0;
+	private int totalModels;
+	private int currentStage = 1;
+
+	private boolean interrupted;
+
+	private int maximum;
+
+	public Frame_Progress(int numModels, Frame_CalcLike frameCalcLike,
+			ApplicationOptions options) {
+		this.numberOfThreads = options.getNumberOfThreads();
+		this.totalModels = ModelTest.getCandidateModels().length;
+		this.interrupted = false;
+		this.options = options;
+		this.startTime = System.currentTimeMillis();
+		this.stream = ModelTest.getMainConsole();
+		this.threadProgressBar = new JProgressBar[numberOfThreads];
+		this.threadProgressLabel = new JLabel[numberOfThreads];
+		this.threadProgressModelLabel = new JLabel[numberOfThreads];
+		this.maximum = numModels;
+		this.frameCalcLike = frameCalcLike;
+
+		initComponents();
+		setVisible(true);
+
+		timer = new Timer(1000, this);
+		timer.setRepeats(true);
+		timer.start();
+	}
+
+	public void initComponents() {
+
+		/* TOP LABEL */
+		
+		headerPanel.setSize(SECTION_WIDTH, HEADER_HEIGHT);
+		headerPanel.setLocation(H_MARGIN, V_MARGIN);
+		headerPanel.setBorder(new BorderUIResource.LineBorderUIResource(
+				XManager.PANEL_BORDER_COLOR));
+		headerPanel.setLayout(null);
+		headerPanel.setVisible(true);
+
+		progressBarLikeLabel.setSize(120, LABEL_HEIGHT);
+		progressBarLikeLabel.setLocation(H_MARGIN, V_INNER_MARGIN);
+		progressBarLikeLabel.setVisible(true);
+		progressBarLikeLabel.setFont(XManager.FONT_CONSOLE);
+		progressBarLikeLabel.setText("Completed 0/" + totalModels);
+
+		timerLabel.setSize(180, LABEL_HEIGHT);
+		timerLabel.setLocation(160, V_INNER_MARGIN);
+		timerLabel.setVisible(true);
+		timerLabel.setFont(XManager.FONT_CONSOLE);
+		timerLabel.setAlignmentX(RIGHT_ALIGNMENT);
+
+		/* THREAD SECTION */
+
+		int threadsPanelHeight = numberOfThreads * HEIGHT_PER_THREAD + 4
+				* V_INNER_MARGIN;
+		threadsActivityPanel.setSize(SECTION_WIDTH, threadsPanelHeight);
+		threadsActivityPanel.setLocation(H_MARGIN, THREADS_SECTIONS_VLOC);
+		threadsActivityPanel
+				.setBorder(new BorderUIResource.TitledBorderUIResource(
+						new LineBorder(XManager.PANEL_BORDER_COLOR, 1, false),
+						"Thread activity", 4, 2, XManager.FONT_LABEL,
+						XManager.LABEL_BLUE_COLOR));
+		threadsActivityPanel.setLayout(null);
+		threadsActivityPanel.setVisible(true);
+		int colorStep = Math.max(THREAD_COLOR.length / numberOfThreads, 1);
+		for (int i = 0; i < numberOfThreads; i++) {
+			threadProgressLabel[i] = new JLabel();
+			threadProgressLabel[i].setSize(THREAD_LABEL_WIDTH, LABEL_HEIGHT);
+			threadProgressLabel[i].setLocation(H_MARGIN, LABEL_HEIGHT + (i)
+					* HEIGHT_PER_THREAD + V_INNER_MARGIN);
+			threadProgressLabel[i].setVisible(true);
+			threadProgressLabel[i].setFont(XManager.FONT_CONSOLE);
+			threadProgressLabel[i].setText(" Thread " + i + ":");
+			threadProgressLabel[i].setOpaque(true);
+			threadProgressLabel[i].setBackground(THREAD_COLOR[(i * colorStep)
+					% THREAD_COLOR.length]);
+			threadProgressLabel[i].setForeground(Color.WHITE);
+			threadProgressModelLabel[i] = new JLabel();
+			threadProgressModelLabel[i].setSize(SECTION_WIDTH
+					- (THREAD_LABEL_WIDTH + 3 * H_MARGIN), LABEL_HEIGHT);
+			threadProgressModelLabel[i].setLocation(THREAD_LABEL_WIDTH + 2
+					* H_MARGIN, (i) * HEIGHT_PER_THREAD + 2 * V_INNER_MARGIN);
+			threadProgressModelLabel[i].setVisible(true);
+			threadProgressModelLabel[i].setFont(XManager.FONT_CONSOLE);
+			threadProgressModelLabel[i].setText(NO_MODEL);
+			threadProgressModelLabel[i].setOpaque(false);
+			threadProgressModelLabel[i]
+					.setForeground(XManager.LABEL_FAIL_COLOR);
+			threadProgressBar[i] = new JProgressBar();
+			threadProgressBar[i].setSize(SECTION_WIDTH
+					- (THREAD_LABEL_WIDTH + 3 * H_MARGIN), THREAD_BAR_HEIGHT);
+			threadProgressBar[i].setStringPainted(false);
+			threadProgressBar[i].setIndeterminate(false);
+			threadProgressBar[i]
+					.setLocation(THREAD_LABEL_WIDTH + 2 * H_MARGIN,
+							LABEL_HEIGHT + (i) * HEIGHT_PER_THREAD + 2
+									* V_INNER_MARGIN);
+			threadProgressBar[i].setVisible(true);
+		}
+
+		/* BOTTOM SECTION */
+		
+		int FOOTER_SECTION_VLOC = THREADS_SECTIONS_VLOC + threadsPanelHeight
+				+ V_MARGIN;
+		footerPanel.setSize(SECTION_WIDTH,
+				FOOTER_HEIGHT + (options.isClusteringSearch() ? 30 : 0));
+		footerPanel.setLocation(H_MARGIN, FOOTER_SECTION_VLOC);
+		footerPanel.setBorder(new BorderUIResource.LineBorderUIResource(
+				XManager.PANEL_BORDER_COLOR));
+		footerPanel.setLayout(null);
+		footerPanel.setVisible(true);
+
+		if (options.isClusteringSearch()) {
+			footerStageLabel.setSize(80, 20);
+			footerStageLabel.setLocation(H_MARGIN, V_INNER_MARGIN);
+			footerStageLabel.setVisible(true);
+			footerStageLabel.setText("Step 1/6");
+			footerPanel.add(footerStageLabel);
+		}
+
+		int progressBarVPosition = V_INNER_MARGIN;
+		if (options.isClusteringSearch()) {
+			int scaleFactor = (options.doI ? 2 : 1) * (options.doG ? 2 : 1)
+					* (options.doF ? 2 : 1);
+			for (int i = 0; i < 6; i++) {
+				this.maxNumOfModelsPerStage[i] *= scaleFactor;
+			}
+			progressBarVPosition += 30;
+			FOOTER_HEIGHT += 30;
+		}
+
+		int initialMaxValue = options.isClusteringSearch() ? maxNumOfModelsPerStage[0]
+				: maximum;
+		progressBarLike.setMaximum(initialMaxValue);
+		progressBarLike.setValue(0);
+		progressBarLike.setStringPainted(true);
+		progressBarLike.setString(null);
+
+		progressBarLike.setSize(SECTION_WIDTH - 2 * H_MARGIN,
+				PROGRESS_BAR_HEIGHT);
+		progressBarLike.setLocation(H_MARGIN, progressBarVPosition);
+		progressBarLike.setVisible(true);
+
+		progressBarCancelButton.setVisible(true);
+		progressBarCancelButton.setSize(BUTTON_WIDTH, PROGRESS_BAR_HEIGHT);
+		progressBarCancelButton.setText("Cancel");
+		progressBarCancelButton.setLocation((SECTION_WIDTH - BUTTON_WIDTH) / 2,
+				PROGRESS_BAR_HEIGHT + V_INNER_MARGIN + progressBarVPosition);
+
+		/* MAIN WINDOW */
+
+		setLocation(281, 80);
+		getContentPane().setLayout(null);
+		setTitle("Progress");
+
+		for (JProgressBar progressBar : threadProgressBar) {
+			threadsActivityPanel.add(progressBar);
+		}
+
+		for (JLabel progressLabel : threadProgressLabel) {
+			threadsActivityPanel.add(progressLabel);
+		}
+
+		for (JLabel progressModelLabel : threadProgressModelLabel) {
+			threadsActivityPanel.add(progressModelLabel);
+		}
+
+		headerPanel.add(progressBarLikeLabel);
+		headerPanel.add(timerLabel);
+		getContentPane().add(headerPanel);
+		getContentPane().add(threadsActivityPanel);
+		footerPanel.add(progressBarLike);
+		footerPanel.add(progressBarCancelButton);
+		getContentPane().add(footerPanel);
+
+		setSize(WINDOW_WIDTH, FOOTER_SECTION_VLOC + FOOTER_HEIGHT + 4
+				* V_MARGIN);
+		setResizable(false);
+
+		/* event handling */
+		addWindowListener(new WindowAdapter() {
+			public void windowClosing(WindowEvent e) {
+				thisWindowClosing(e);
+			}
+		});
+
+		progressBarCancelButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				progressBarCancel(e);
+			}
+		});
+	}
+
+	private boolean mShown = false;
+
+	public void addNotify() {
+		super.addNotify();
+
+		if (mShown)
+			return;
+
+		/* resize frame to account for menubar */
+		JMenuBar jMenuBar = getJMenuBar();
+		if (jMenuBar != null) {
+			int jMenuBarHeight = jMenuBar.getPreferredSize().height;
+			Dimension dimension = getSize();
+			dimension.height += jMenuBarHeight;
+			setSize(dimension);
+
+			/* move down components in layered pane */
+			Component[] components = getLayeredPane().getComponentsInLayer(
+					JLayeredPane.DEFAULT_LAYER.intValue());
+			for (int i = 0; i < components.length; i++) {
+				Point location = components[i].getLocation();
+				location.move(location.x, location.y + jMenuBarHeight);
+				components[i].setLocation(location);
+			}
+		}
+
+		mShown = true;
+	}
+
+	/* close the window when the close box is clicked */
+	private void thisWindowClosing(WindowEvent e) {
+		setVisible(false);
+		dispose();
+	}
+
+	private void progressBarCancel(ActionEvent e) {
+		this.setEnabled(false);
+		try {
+			/* show confirm dialog */
+			Object[] options = {"Yes","No"};
+			int option;
+			option = JOptionPane.showOptionDialog(null, "Are you sure you want to cancel?", 
+					"Cancel Execution", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[1]);
+	        if (option == JOptionPane.YES_OPTION) {
+	        	/* cancel execution */
+				frameCalcLike.getRunPhyml().interruptThread();
+				frameCalcLike.cancelTask();
+				setVisible(false);
+	        }
+		} catch (Exception f) {
+			f.printStackTrace();
+		}
+		this.setEnabled(true);
+	}
+
+	@Override
+	@SuppressWarnings("fallthrough")
+	public synchronized void update(Observable o, Object arg) {
+		
+		if (Math.abs(System.currentTimeMillis() - lockTimer) < lockTime) return;
+		
+		if (arg != null) {
+			ProgressInfo info = (ProgressInfo) arg;
+
+			switch (info.getType()) {
+
+			case ProgressInfo.BASE_TREE_INIT:
+				stream.print("\nEstimating a BIONJ-JC tree ... ");
+				System.out.print("estimating a BIONJ-JC tree ... ");
+				threadProgressModelLabel[0]
+						.setText("Computing BIONJ tree for JC");
+				threadProgressModelLabel[0]
+						.setForeground(XManager.LABEL_GREEN_COLOR);
+				threadProgressBar[0].setIndeterminate(true);
+				break;
+
+			case ProgressInfo.BASE_TREE_COMPUTED:
+				stream.println("OK");
+				System.out.println("OK");
+				threadProgressModelLabel[0].setText(NO_MODEL);
+				threadProgressModelLabel[0]
+						.setForeground(XManager.LABEL_FAIL_COLOR);
+				threadProgressBar[0].setIndeterminate(false);
+				stream.print(info.getModel().getName() + " tree: "
+						+ info.getModel().getTreeString() + "\n");
+				break;
+
+			case ProgressInfo.GTR_OPTIMIZATION_INIT:
+				stream.println("[Heuristic search] Optimizing "
+						+ info.getModel().getName() + " model");
+				threadProgressModelLabel[0].setText("Computing "
+						+ info.getModel().getName()
+						+ " model for heuristic search");
+				threadProgressModelLabel[0]
+						.setForeground(XManager.LABEL_GREEN_COLOR);
+				threadProgressBar[0].setIndeterminate(true);
+				break;
+
+			case ProgressInfo.GTR_OPTIMIZATION_COMPLETED:
+				stream.println("[Heuristic search] OK");
+				threadProgressModelLabel[0].setText(NO_MODEL);
+				threadProgressModelLabel[0]
+						.setForeground(XManager.LABEL_FAIL_COLOR);
+				threadProgressBar[0].setIndeterminate(false);
+				break;
+
+			case ProgressInfo.SINGLE_OPTIMIZATION_INIT:
+				for (int i = 0; i < numberOfThreads; i++) {
+					JLabel progressLabel = threadProgressModelLabel[i];
+					if (progressLabel.getText().equals(NO_MODEL)) {
+						progressLabel.setText("Computing "
+								+ info.getModel().getName() + "...");
+						progressLabel.setForeground(XManager.LABEL_GREEN_COLOR);
+						threadProgressBar[i].setIndeterminate(true);
+						break;
+					}
+				}
+				break;
+
+			case ProgressInfo.OPTIMIZATION_INIT:
+				stream.println(" ");
+				stream.println("::Progress::");
+				stream.println(" ");
+				stream.println("Model \t\t Exec. Time \t Total Time \t -lnL");
+				stream.println("-------------------------------------------------------------------------");
+
+				ModelTest.setMyAIC(null);
+				ModelTest.setMyAICc(null);
+				ModelTest.setMyBIC(null);
+				ModelTest.setMyDT(null);
+
+				break;
+
+			case ProgressInfo.SINGLE_OPTIMIZATION_COMPLETED:
+				this.completedModels++;
+				try {
+					for (int i = 0; i < numberOfThreads; i++) {
+						JLabel progressLabel = threadProgressModelLabel[i];
+						if (progressLabel.getText().equals(
+								"Computing " + info.getModel().getName()
+										+ "...")) {
+							progressLabel.setText(NO_MODEL);
+							progressLabel
+									.setForeground(XManager.LABEL_FAIL_COLOR);
+							threadProgressBar[i].setIndeterminate(false);
+							break;
+						}
+					}
+					if (options.isClusteringSearch()) {
+						if (currentStage != info.getHeuristicStage()) {
+							currentStage = info.getHeuristicStage();
+							completedModels = 0;
+							footerStageLabel.setText("Step " + currentStage
+									+ "/6");
+							int newMaximum = maxNumOfModelsPerStage[currentStage - 1];
+							progressBarLike.setMaximum(newMaximum);
+						}
+						progressBarLikeLabel.setText("[" + currentStage + "/6]"
+								+ completedModels + "/"
+								+ info.getNumModelsInStage());
+					} else {
+						/* update total number of models */
+						totalModels = options.getNumModels();
+						progressBarLikeLabel.setText("Completed "
+								+ completedModels + "/" + totalModels);
+					}
+
+					if (ModelTestConfiguration.isCkpEnabled()) {
+						try {
+							OutputStream file = new FileOutputStream(
+									options.getCkpFile());
+							OutputStream buffer = new BufferedOutputStream(file);
+							ObjectOutput output = new ObjectOutputStream(buffer);
+							output.writeObject(ModelTest.getCandidateModels());
+							output.close();
+						} catch (IOException ex) {
+							System.err.println("Cannot perform output.");
+						}
+					}
+					
+					progressBarLike.setValue(completedModels);
+				} catch (NullPointerException e) {
+					/* Ignore... */
+				}
+
+				String modelTab = (info.getModel().getName().length() > 10) ? "\t"
+						: "\t\t";
+				stream.println(info.getModel().getName()
+						+ modelTab
+						+ info.getMessage()
+						+ "\t"
+						+ Utilities.calculateRuntime(startTime,
+								System.currentTimeMillis())
+						+ "\t"
+						+ String.format(Locale.ENGLISH, "%5.4f", info
+								.getModel().getLnL()));
+
+				// scroll to the bottom
+				XManager.getInstance()
+						.getPane()
+						.setCaretPosition(
+								XManager.getInstance().getPane().getDocument()
+										.getLength());
+				break;
+
+			case ProgressInfo.INTERRUPTED:
+				lockTimer = System.currentTimeMillis();
+				if (!interrupted) {
+					interrupted = true;
+					stream.println(" ");
+
+					XManager.getInstance().setLikeLabelColor(
+							XManager.LABEL_FAIL_COLOR);
+
+					System.err
+							.println("\nComputation of likelihood scores discontinued...");
+					Utilities
+							.printRed("\nComputation of likelihood scores interrupted. It took "
+									+ Utilities.calculateRuntime(startTime,
+											System.currentTimeMillis()) + ".\n");
+					stream.println(" ");
+					XManager.getInstance()
+							.getPane()
+							.setCaretPosition(
+									XManager.getInstance().getPane()
+											.getDocument().getLength());
+					ProcessManager.getInstance().killAll();
+				}
+				break;
+
+			case ProgressInfo.ERROR:
+				lockTimer = System.currentTimeMillis();
+				progressBarCancel(null);
+				Utilities.printRed(info.getMessage());
+				JOptionPane.showMessageDialog(new JFrame(), info.getMessage(),
+						"jModeltest error", JOptionPane.ERROR_MESSAGE);
+				break;
+			case ProgressInfo.ERROR_BINARY_NOEXECUTE:
+				lockTimer = System.currentTimeMillis();
+				progressBarCancel(null);
+				Utilities.printRed("\n********************\n");
+				Utilities.printRed("PhyML binary does not have execution permission: " + info.getMessage());
+				Utilities.printRed("\n********************\n");
+				JOptionPane.showMessageDialog(new JFrame(),  "PhyML binary does not have execution permission:\n   " +info.getMessage(),
+						"jModeltest error", JOptionPane.ERROR_MESSAGE);
+				break;
+			case ProgressInfo.ERROR_BINARY_NOEXISTS:
+				lockTimer = System.currentTimeMillis();
+				progressBarCancel(null);
+				Utilities.printRed("\n********************\n");
+				Utilities.printRed("PhyML binary does not exist: " + info.getMessage());
+				Utilities.printRed("\n********************\n");
+				JOptionPane.showMessageDialog(new JFrame(),  "PhyML binary does not exist:\n   " +info.getMessage(),
+						"jModeltest error", JOptionPane.ERROR_MESSAGE);
+				break;
+
+			case ProgressInfo.OPTIMIZATION_COMPLETED_OK:
+
+				if (!interrupted) {
+
+					stream.println(" ");
+					stream.println("::Results::");
+					stream.println(" ");
+					int numComputedModels = 0;
+					for (Model model : ModelTest.getCandidateModels()) {
+						if (model.getLnL() > 0.0) {
+							numComputedModels++;
+							model.print(ModelTest.getMainConsole());
+							ModelTest.getMainConsole().println(" ");
+						}
+					}
+
+					String baseTree = "";
+
+					/* update gui status */
+					if (!options.fixedTopology && !options.userTopologyExists)
+						baseTree = "(optimized trees)";
+					else
+						baseTree = "(fixed tree)";
+
+					XManager.getInstance()
+							.setLikeLabelText(
+									"  Likelihood scores loaded for "
+											+ numComputedModels + " models "
+											+ baseTree);
+
+					if (options.isClusteringSearch()
+							|| (numComputedModels == options.getNumModels())) {
+						XManager.getInstance().setLikeLabelColor(
+								XManager.LABEL_BLUE_COLOR);
+
+						stream.println("\nComputation of likelihood scores completed. It took "
+								+ Utilities.calculateRuntime(startTime,
+										System.currentTimeMillis()) + ".\n");
+
+						XManager.getInstance()
+								.enableMenuhLRT(
+										options.getSubstTypeCode() < 4
+												& (options.fixedTopology | options.userTopologyExists));
+						XManager.getInstance()
+								.enableMenuAveraging(
+										!(options.fixedTopology | options.userTopologyExists));
+
+						XManager.getInstance().enableMenuAIC(true);
+						XManager.getInstance().enableMenuBIC(true);
+						XManager.getInstance().enableMenuDT(true);
+
+						/* build results table */
+						XManager.getInstance().buildFrameResults();
+						XManager.getInstance().enableMenuShowModelTable(true);
+						XManager.getInstance().enableMenuHtmlOutput(true);
+
+						System.out.println(" ... OK");
+
+					} else {
+						XManager.getInstance().setLikeLabelColor(
+								XManager.LABEL_FAIL_COLOR);
+
+						stream.println("\nComputation of likelihood scores interrupted. It took "
+								+ Utilities.calculateRuntime(startTime,
+										System.currentTimeMillis()) + ".\n");
+					}
+
+				}
+
+				XManager.getInstance()
+						.getPane()
+						.setCaretPosition(
+								XManager.getInstance().getPane().getDocument()
+										.getLength());
+				/* continue */
+
+			case ProgressInfo.OPTIMIZATION_COMPLETED_INTERRUPTED:
+				ExternalExecutionManager.getInstance().killProcesses();
+				setVisible(false);
+				break;
+			}
+		} else {
+			/* dispose */
+			setVisible(false);
+			dispose();
+		}
+
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		/* if the timer caused this event */
+		timerLabel.setText("Elapsed time: "
+				+ Utilities.calculateRuntimeMinutes(startTime,
+						System.currentTimeMillis()));
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_hLRT.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_hLRT.java
new file mode 100644
index 0000000..f9ba4d6
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/Frame_hLRT.java
@@ -0,0 +1,519 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Point;
+import java.awt.Toolkit;
+
+import javax.swing.ButtonGroup;
+import javax.swing.DefaultListModel;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLayeredPane;
+import javax.swing.JList;
+import javax.swing.JMenuBar;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.LineBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.plaf.BorderUIResource;
+
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.selection.HLRT;
+
+public class Frame_hLRT extends JModelTestFrame {
+
+	private static final long serialVersionUID = -3314020071170637296L;
+	
+	private JPanel PanelSettings = new JPanel();
+	private JTextField TextFieldConfidenceLevelhLRT = new JTextField();
+	private JList<String> HypothesisList = new JList<String>();
+	private DefaultListModel<String> listModel = new DefaultListModel<String>();
+	private JButton ButtonListUp = new JButton();
+	private JButton ButtonListDown = new JButton();
+	private JButton CancelButtonhLRT = new JButton();
+	private JButton RunButtonhLRT = new JButton();
+	private JButton JButtonDefaulthLRT = new JButton();
+	private JPanel PanelForwardBackward = new JPanel();
+	private JRadioButton ButtonForward = new JRadioButton();
+	private JRadioButton ButtonBackward = new JRadioButton();
+	private ButtonGroup ButtonGroupForwardBackward = new ButtonGroup();
+	private JCheckBox jCheckBoxPAUPblock = new JCheckBox();
+	private JCheckBox jCheckBoxDynamical = new JCheckBox();
+
+	private String currentDirectory = System.getProperty("user.dir");
+
+	public Frame_hLRT() {
+	}
+
+	public void initComponents() throws Exception {
+		java.awt.Image img0 = Toolkit.getDefaultToolkit().getImage(currentDirectory + "/resources/icons/Up24.gif");
+		java.awt.Image img1 = Toolkit.getDefaultToolkit().getImage(currentDirectory + "/resources/icons/Down24.gif");
+
+		PanelSettings.setSize(new java.awt.Dimension(460, 370));
+		PanelSettings.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "hLRT Settings", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		PanelSettings.setLocation(new java.awt.Point(10, 10));
+		PanelSettings.setVisible(true);
+		PanelSettings.setLayout(null);
+
+		TextFieldConfidenceLevelhLRT.setToolTipText("Enter the confidence level for individual LRTs and click ENTER");
+		TextFieldConfidenceLevelhLRT.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Confidence level LRT", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		TextFieldConfidenceLevelhLRT.setVisible(true);
+		TextFieldConfidenceLevelhLRT.setSize(new java.awt.Dimension(130, 50));
+		TextFieldConfidenceLevelhLRT.setText("0.01");
+		TextFieldConfidenceLevelhLRT.setHorizontalAlignment(JTextField.RIGHT);
+		TextFieldConfidenceLevelhLRT.setLocation(new java.awt.Point(20, 20));
+
+		HypothesisList.setToolTipText("Use the buttons to move up and down the different hypotheses");
+		HypothesisList.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Hypotheses order", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		HypothesisList.setVisible(true);
+		HypothesisList.setSize(new java.awt.Dimension(130, 230));
+		HypothesisList.setVisibleRowCount(ModelTest.testingOrder.size());
+		HypothesisList.setFont(XManager.FONT_LABEL_BIG);
+		HypothesisList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		HypothesisList.setLocation(new java.awt.Point(20, 80));
+
+		ButtonListUp.setIcon(new ImageIcon(img0));
+		ButtonListUp.setVisible(true);
+		ButtonListUp.setSize(new java.awt.Dimension(35, 40));
+		ButtonListUp.setLocation(new java.awt.Point(155, 100));
+
+		ButtonListDown.setIcon(new ImageIcon(img1));
+		ButtonListDown.setVisible(true);
+		ButtonListDown.setSize(new java.awt.Dimension(35, 40));
+		ButtonListDown.setLocation(new java.awt.Point(155, 140));
+
+		PanelForwardBackward.setSize(new java.awt.Dimension(200, 50));
+		PanelForwardBackward.setBorder(new BorderUIResource.TitledBorderUIResource(new LineBorder(new java.awt.Color(153, 153, 153), 1, false), "Forward/Backward Selection", 4, 2, new java.awt.Font("Application", 1, 10), new java.awt.Color(102, 102, 153)));
+		PanelForwardBackward.setLocation(new java.awt.Point(200, 20));
+		PanelForwardBackward.setVisible(true);
+		PanelForwardBackward.setLayout(null);
+
+		ButtonForward.setVisible(true);
+		ButtonForward.setSize(new java.awt.Dimension(90, 20));
+		ButtonForward.setText("Forward");
+		ButtonForward.setLocation(new java.awt.Point(10, 20));
+		ButtonForward.setToolTipText("Adds parameters starting from a JC model");
+		ButtonForward.setSelected(true);
+
+		ButtonBackward.setVisible(true);
+		ButtonBackward.setSize(new java.awt.Dimension(90, 20));
+		ButtonBackward.setText("Backward");
+		ButtonBackward.setLocation(new java.awt.Point(100, 20));
+		ButtonBackward.setToolTipText("Removes parameters starting from a GTR+I+G model");
+
+		jCheckBoxDynamical.setVisible(true);
+		jCheckBoxDynamical.setSize(new java.awt.Dimension(200, 20));
+		jCheckBoxDynamical.setText("Perform dynamical LRTs");
+		jCheckBoxDynamical.setLocation(new java.awt.Point(230, 100));
+		jCheckBoxDynamical.setSelected(false);
+		jCheckBoxDynamical.setToolTipText("The sequences of LRTs will be build according to best lnL moves");
+
+		jCheckBoxPAUPblock.setVisible(true);
+		jCheckBoxPAUPblock.setSize(new java.awt.Dimension(160, 20));
+		jCheckBoxPAUPblock.setText("Write PAUP* block");
+		jCheckBoxPAUPblock.setLocation(new java.awt.Point(230, 160));
+		jCheckBoxPAUPblock.setSelected(false);
+		jCheckBoxPAUPblock.setToolTipText("Writes a block of PAUP* commands implementing the selected model");
+
+		JButtonDefaulthLRT.setVisible(true);
+		JButtonDefaulthLRT.setSize(new java.awt.Dimension(141, 40));
+		JButtonDefaulthLRT.setText("Default Settings");
+		JButtonDefaulthLRT.setLocation(new java.awt.Point(10, 320));
+
+		CancelButtonhLRT.setVisible(true);
+		CancelButtonhLRT.setSize(new java.awt.Dimension(140, 40));
+		CancelButtonhLRT.setText("Cancel");
+		CancelButtonhLRT.setLocation(new java.awt.Point(160, 320));
+
+		RunButtonhLRT.setVisible(true);
+		RunButtonhLRT.setSize(new java.awt.Dimension(140, 40));
+		RunButtonhLRT.setText("Run");
+		RunButtonhLRT.setLocation(new java.awt.Point(310, 320));
+		RunButtonhLRT.setToolTipText("Click here to start the hLRT selection");
+		getRootPane().setDefaultButton(RunButtonhLRT);
+
+		ButtonGroupForwardBackward.add(ButtonForward);
+		ButtonGroupForwardBackward.add(ButtonBackward);
+
+		setLocation(new java.awt.Point(281, 80));
+		getContentPane().setLayout(null);
+		setTitle("Hierarchical Likelihood Ratio Tests (hLRT) Settings");
+
+		PanelSettings.add(TextFieldConfidenceLevelhLRT);
+		PanelSettings.add(HypothesisList);
+		PanelSettings.add(ButtonListUp);
+		PanelSettings.add(ButtonListDown);
+		PanelSettings.add(PanelForwardBackward);
+		PanelSettings.add(jCheckBoxDynamical);
+		PanelSettings.add(jCheckBoxPAUPblock);
+		PanelSettings.add(CancelButtonhLRT);
+		PanelSettings.add(RunButtonhLRT);
+		PanelSettings.add(JButtonDefaulthLRT);
+	
+		PanelForwardBackward.add(ButtonForward);
+		PanelForwardBackward.add(ButtonBackward);
+	
+		getContentPane().add(PanelSettings);
+
+		setSize(new java.awt.Dimension(482, 420));
+		setResizable(false);
+
+
+		// event handling
+		HypothesisList.addListSelectionListener(new ListSelectionListener() {
+			public void valueChanged(ListSelectionEvent e) {
+				HypothesisListValueChanged(e);
+			}
+		});
+
+		ButtonListUp.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				ButtonListUpActionPerformed(e);
+			}
+		});
+		ButtonListDown.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				ButtonListDownActionPerformed(e);
+			}
+		});
+	
+		ButtonForward.addChangeListener(new ChangeListener(){
+			public void stateChanged(ChangeEvent e) {
+				ButtonForwardActionPerformed(e);
+			}
+		});
+
+
+		jCheckBoxDynamical.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				jCheckBoxDynamicalActionPerformed(e);
+			}
+		});
+
+		CancelButtonhLRT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				CancelButtonhLRTActionPerformed(e);
+			}
+		});
+		RunButtonhLRT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				RunButtonhLRTActionPerformed(e);
+			}
+		});
+		JButtonDefaulthLRT.addActionListener(new java.awt.event.ActionListener() {
+			public void actionPerformed(java.awt.event.ActionEvent e) {
+				JButtonDefaulthLRTActionPerformed(e);
+			}
+		});
+		addWindowListener(new java.awt.event.WindowAdapter() {
+			public void windowClosing(java.awt.event.WindowEvent e) {
+				thisWindowClosing(e);
+			}
+		});
+
+
+//		for (Enumeration e=testOrder.elements(); e.hasMoreElements();) 
+//			ModelTest.testingOrder[i++] = (String)e.nextElement();
+
+
+	if (options.doF)
+		listModel.addElement("freq");	
+
+	listModel.addElement("titv");
+
+	if (options.getSubstTypeCode() == 0)
+		listModel.addElement("2ti4tv");
+	else if (options.getSubstTypeCode() == 1)
+		{
+		listModel.addElement("2ti");
+		listModel.addElement("2tv");
+		}
+	else
+		{
+		listModel.addElement("2ti");
+		listModel.addElement("2tv");
+		listModel.addElement("4tv");
+		}
+
+	if (options.doG)
+		listModel.addElement("gamma");
+
+	if (options.doI)
+		listModel.addElement("pinv");
+
+	
+   HypothesisList.setModel(listModel);
+}
+
+  	private boolean mShown = false;
+  	
+	public void addNotify() {
+		super.addNotify();
+		
+		if (mShown)
+			return;
+			
+		// resize frame to account for menubar
+		JMenuBar jMenuBar = getJMenuBar();
+		if (jMenuBar != null) {
+			int jMenuBarHeight = jMenuBar.getPreferredSize().height;
+			Dimension dimension = getSize();
+			dimension.height += jMenuBarHeight;
+			setSize(dimension);
+			
+			// move down components in layered pane
+			Component[] components = getLayeredPane().getComponentsInLayer(JLayeredPane.DEFAULT_LAYER.intValue());
+			for (int i = 0; i < components.length; i++) {
+				Point location = components[i].getLocation();
+				location.move(location.x, location.y + jMenuBarHeight);
+				components[i].setLocation(location);
+			}
+		}
+
+		mShown = true;
+	}
+
+	// Close the window when the close box is clicked
+	void thisWindowClosing(java.awt.event.WindowEvent e) {
+		setVisible(false);
+		dispose();
+		//System.exit(0);
+	}
+	
+	public void ButtonListUpActionPerformed(java.awt.event.ActionEvent e) 
+		{
+		int moveMe = HypothesisList.getSelectedIndex();
+		if (moveMe != 0)     //not already at top
+			{     
+            swap (moveMe, moveMe-1);
+            HypothesisList.setSelectedIndex(moveMe-1);
+            HypothesisList.ensureIndexIsVisible(moveMe-1);
+            }
+		}
+	
+	public void ButtonListDownActionPerformed(java.awt.event.ActionEvent e) 
+		{
+		int moveMe = HypothesisList.getSelectedIndex();
+		if (moveMe != listModel.getSize()-1)     //not already at bottom
+			{     
+       	 	swap (moveMe, moveMe+1);
+       	 	HypothesisList.setSelectedIndex(moveMe+1);
+        	HypothesisList.ensureIndexIsVisible(moveMe+1);
+        	}
+		}
+	
+	public void HypothesisListValueChanged(ListSelectionEvent e) {
+	}
+	
+    //Swap two elements in the list.
+    private void swap(int a, int b) 
+    	{
+    	if (a >= 0 && b >= 0 
+    			&& a < listModel.getSize()
+    			&& b < listModel.getSize()) {
+	        String aObject = listModel.getElementAt(a);
+	        String bObject = listModel.getElementAt(b);
+	        listModel.set(a, bObject);
+	        listModel.set(b, aObject);
+	    	}
+    	}				
+	
+	
+	public void ButtonForwardActionPerformed(ChangeEvent e)
+		{
+ 		listModel.removeAllElements();
+		
+		if (options.doF)
+			listModel.addElement("freq");	
+
+		if (ButtonForward.isSelected())
+			{
+			listModel.addElement("titv");
+			if (options.getSubstTypeCode() == 0)
+				listModel.addElement("2ti4tv");
+			else if (options.getSubstTypeCode() == 1)
+				{
+				listModel.addElement("2ti");
+				listModel.addElement("2tv");
+				}
+			else if (options.getSubstTypeCode() > 1)
+				{
+				listModel.addElement("2ti");
+				listModel.addElement("2tv");
+				listModel.addElement("4tv");
+				}
+			}
+		else
+			{
+			if (options.getSubstTypeCode() == 0)
+				listModel.addElement("2ti4tv");
+			else if (options.getSubstTypeCode() == 1)
+				{
+				listModel.addElement("2tv");
+				listModel.addElement("2ti");
+				}
+			else if (options.getSubstTypeCode() > 1)
+				{
+				listModel.addElement("4tv");
+				listModel.addElement("2tv");
+				listModel.addElement("2ti");
+				}
+			listModel.addElement("titv");
+			}
+
+		if (options.doG)
+			listModel.addElement("gamma");
+
+		if (options.doI)
+			listModel.addElement("pinv");
+
+		HypothesisList.setModel(listModel);
+		}
+	
+
+	public void jCheckBoxDynamicalActionPerformed(java.awt.event.ActionEvent e)
+		{
+		try
+			{
+			if (jCheckBoxDynamical.isSelected())
+				{
+				ButtonListUp.setEnabled(false);
+				ButtonListDown.setEnabled(false);
+				HypothesisList.setEnabled(false);
+				}
+			else 
+				{
+				ButtonListUp.setEnabled(true);
+				ButtonListDown.setEnabled(true);
+				HypothesisList.setEnabled(true);
+				}
+			}	
+		catch (Exception f) 
+			{
+			f.printStackTrace();
+			}
+		}
+
+
+	public void JButtonDefaulthLRTActionPerformed(java.awt.event.ActionEvent e)
+		{
+   		TextFieldConfidenceLevelhLRT.setText("0.01");
+   		
+		listModel.removeAllElements();
+		
+		if (options.doF)
+			listModel.addElement("freq");	
+
+		listModel.addElement("titv");
+
+		if (options.getSubstTypeCode() == 0)
+			listModel.addElement("2ti4tv");
+		else if (options.getSubstTypeCode() == 1)
+			{
+			listModel.addElement("2ti");
+			listModel.addElement("2tv");
+			}
+		else
+			{
+			listModel.addElement("2ti");
+			listModel.addElement("2tv");
+			listModel.addElement("4tv");
+			}
+
+		if (options.doG)
+			listModel.addElement("gamma");
+
+		if (options.doI)
+			listModel.addElement("pinv");
+
+		HypothesisList.setModel(listModel);
+		
+				
+		ButtonForward.setSelected(true);
+		jCheckBoxPAUPblock.setSelected(false);
+		jCheckBoxDynamical.setSelected(false);
+		}
+
+		
+	public void CancelButtonhLRTActionPerformed(java.awt.event.ActionEvent e)
+		{
+		try
+			{
+			setVisible(false);
+			dispose();
+			}
+		catch (Exception f) 
+			{
+			f.printStackTrace();
+			}
+		}
+
+
+	public void RunButtonhLRTActionPerformed(java.awt.event.ActionEvent e)
+		{
+		int i;
+		double alpha;
+		boolean forward,writePAUPblock;
+		
+		setVisible(false);
+		dispose();
+		
+		alpha = Double.parseDouble (TextFieldConfidenceLevelhLRT.getText());
+		writePAUPblock = jCheckBoxPAUPblock.isSelected();
+		
+		if (ButtonForward.isSelected())
+			forward = true;
+		else
+			forward = false;
+	
+		for (i=0; i< listModel.getSize(); i++) {
+			ModelTest.testingOrder.setElementAt(listModel.getElementAt(i),i);
+		}
+	
+		/* check whether 2tv goes before 4tv */
+		if (forward && ModelTest.testingOrder.indexOf("2tv") > ModelTest.testingOrder.indexOf("4tv"))
+			{
+			JOptionPane.showMessageDialog(this, "for forward hLRTs the hypothesis 2tv needs\nto be tested before the hypothesis 4tv", 
+						"jModelTest error", JOptionPane.ERROR_MESSAGE);
+			ModelTest.getMainConsole().println ("\nError: for forward hLRTs the hypothesis 2tv needs\nto be tested before the hypothesis 4tv");
+			}
+		else	if (!forward && ModelTest.testingOrder.indexOf("2tv") < ModelTest.testingOrder.indexOf("4tv"))
+			{
+			JOptionPane.showMessageDialog(this, "for backward hLRTs the hypothesis 2tv needs\nto be tested after the hypothesis 4tv", 
+						"jModelTest error", JOptionPane.ERROR_MESSAGE);
+			ModelTest.getMainConsole().println ("\nError: for backward hLRTs the hypothesis 2tv needs\nto be tested after the hypothesis 4tv");
+			}
+	
+		HLRT myHLRT = new HLRT(options);
+		if (jCheckBoxDynamical.isSelected())
+			myHLRT.computeDynamical(forward, alpha, writePAUPblock);
+		else
+			myHLRT.compute(forward, alpha, writePAUPblock);
+		}
+						
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/JModelTestFrame.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/JModelTestFrame.java
new file mode 100644
index 0000000..31ed03c
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/JModelTestFrame.java
@@ -0,0 +1,34 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.gui;
+
+import javax.swing.JFrame;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+
+public class JModelTestFrame extends JFrame {
+	
+	private static final long serialVersionUID = -8636558779921904218L;
+	
+	protected ApplicationOptions options;
+	
+	public JModelTestFrame() {
+		options = ApplicationOptions.getInstance();
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/gui/XManager.java b/src/main/java/es/uvigo/darwin/jmodeltest/gui/XManager.java
new file mode 100644
index 0000000..8bef0e7
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/gui/XManager.java
@@ -0,0 +1,258 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.gui;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Point;
+import java.io.PrintStream;
+import java.net.URL;
+import java.util.Calendar;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.JTextPane;
+import javax.swing.UIManager;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyleConstants;
+
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.io.DocumentOutputStream;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class XManager {
+
+	private static XManager instance;
+	
+	public static final Font FONT_CONSOLE, FONT_LABEL, 
+		FONT_MENU, FONT_STATUS, FONT_SLIDER, FONT_LABEL_BIG,
+		FONT_TABULAR;
+	public static final Color LABEL_BLUE_COLOR = new Color(102,102,153);
+	public static final Color LABEL_FAIL_COLOR = new Color(153, 0, 0);
+	public static final Color LABEL_GREEN_COLOR = new Color(0, 153, 0);
+	public static final Color PANEL_BORDER_COLOR = new Color(153, 153, 153);
+	public static final Color MENU_COLOR = new Color(130,130,150);//(199, 199, 220);
+	public static final Color MENU_FG_COLOR = new Color(0,0,0);
+	public static final Color PANE_BACK_COLOR = Color.WHITE;
+	public static final Color INNER_BORDER_COLOR = new Color(182,182,182); //182
+	public static final Color OUTER_BORDER_COLOR = new Color(89,89,89); //89
+	public static final Color DARK_GRAY_COLOR = new Color(89,89,89); //89
+	public static final Color STATUS_BACK_COLOR = new Color(220,220,220); //220
+	
+	public static final Point MAIN_LOCATION = new Point(281, 80);
+	
+	public static SimpleAttributeSet redText;
+	public static SimpleAttributeSet blackText;
+
+	public FrameMain frame;
+	public FrameResults resultsFrame;
+	private FramePreferences preferencesFrame;
+	public static boolean resultsFrameBuilt = false;
+	private JTextPane PANE;
+
+	static {
+
+		if (Utilities.isWindows() == false) {
+			FONT_CONSOLE = new Font(Font.MONOSPACED, 0, 12);
+		} else {
+			FONT_CONSOLE = new Font("Lucida Console", 0, 12);
+		}
+		FONT_LABEL = new Font("Application", 1, 10);
+		FONT_LABEL_BIG = new Font("Application", 0, 12);
+		FONT_SLIDER = new Font("Application", 1, 9);
+		FONT_MENU = new Font("Dialog", 0, 9);
+		FONT_STATUS = new Font("Dialog", 0, 9);
+		FONT_TABULAR = new java.awt.Font("Verdana", 0, 12);
+
+		redText = new SimpleAttributeSet();
+		blackText = new SimpleAttributeSet();
+
+		StyleConstants.setForeground(redText, Color.red);
+		StyleConstants.setForeground(blackText, Color.black);
+	}
+
+	private XManager() {
+
+		try {
+			try {
+				UIManager.setLookAndFeel(UIManager
+						.getSystemLookAndFeelClassName());
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+
+			frame = new FrameMain();
+			frame.initComponents();
+			frame.setVisible(true);
+			PANE = frame.getMainEditorPane();
+
+			ModelTest.setMainConsole(new TextOutputStream(new PrintStream(
+					new DocumentOutputStream(PANE.getDocument()))));
+
+			ModelTest.setCurrentOutStream(ModelTest.getMainConsole());
+			ModelTest.printHeader(ModelTest.getMainConsole());
+			ModelTest.printNotice(ModelTest.getMainConsole());
+			ModelTest.printCitation(ModelTest.getMainConsole());
+
+			// check expiration date
+			// CheckExpiration (frame);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+	}
+
+	/****************************
+	 * CheckExpiration*************************** * Checks for expiration and
+	 * quits if needed * * *
+	 ***********************************************************************/
+	public static void CheckExpiration(JFrame theframe) {
+		java.util.Calendar now = java.util.Calendar.getInstance();
+
+		if ((now.get(Calendar.MONTH) != Calendar.JUNE && now.get(Calendar.MONTH) != Calendar.DECEMBER)
+				|| now.get(Calendar.YEAR) != 2007) {
+			JOptionPane.showMessageDialog(theframe,
+					"Program has expired! \n    Bye...", "jModelTest warning",
+					JOptionPane.WARNING_MESSAGE);
+			theframe.dispose();
+			System.exit(0);
+		}
+	}
+
+	public void setPane(JTextPane pane) {
+		PANE = pane;
+	}
+
+	public JTextPane getPane() {
+		return PANE;
+	}
+
+	/****************************
+	 * buildFrameResults **************************** * Builds the frame that
+	 * displays the model selection results * *
+	 ************************************************************************/
+
+	public void buildFrameResults() {
+		try {
+			if (resultsFrameBuilt) {
+				resultsFrame.dispose();
+			}
+			resultsFrame = new FrameResults();
+			resultsFrame.initComponents();
+			resultsFrame.setVisible(false);
+			resultsFrameBuilt = true;
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	public static XManager getInstance() {
+		if (instance == null) {
+			instance = new XManager();
+		}
+		return instance;
+	}
+	
+	public void loadFramePreferences() {
+		if (preferencesFrame == null) {
+			preferencesFrame = new FramePreferences();			
+		}
+		preferencesFrame.setVisible(true);
+	}
+	
+	public void setLikeLabelText(String text) {
+		frame.setLikeLabelText(text);
+	}
+	
+	public void setDataLabelText(String text) {
+		frame.setDataLabelText(text);
+	}
+	
+	public void setLikeLabelColor(Color color) {
+		frame.setLikeLabelColor(color);
+	}
+	
+	public void enableMenuAIC(boolean enabled) {
+		frame.enableMenuAIC(enabled);
+	}
+	
+	public void enableMenuBIC(boolean enabled) {
+		frame.enableMenuBIC(enabled);
+	}
+	
+	public void enableMenuDT(boolean enabled) {
+		frame.enableMenuDT(enabled);
+	}
+	
+	public void enableMenuhLRT(boolean enabled) {
+		frame.enableMenuhLRT(enabled);
+	}
+	
+	public void enableMenuAveraging(boolean enabled) {
+		frame.enableMenuAveraging(enabled);
+	}
+	
+	public void enableMenuShowModelTable(boolean enabled) {
+		frame.enableMenuShowModelTable(enabled);
+	}
+	
+	public void enableMenuHtmlOutput(boolean enabled) {
+		frame.enableMenuHtmlOutput(enabled);
+	}
+	
+	public void selectedMenuResultsBLasParameters(boolean selected) {
+		frame.selectedMenuResultsBLasParameters(selected);
+	}
+	
+	public static ImageIcon makeIcon(String imageName, String altText) {
+		//Look for the image.
+	    String imgLocation = "icons/" + imageName
+	        + ".gif";
+	    URL imageURL = XManager.class.getResource(imgLocation);
+	    ImageIcon icon = null;
+	    if (imageURL != null) {
+	    	icon = new ImageIcon(imageURL, altText);
+	    }
+	    return icon;
+	}
+	
+	public static JButton makeIconButton(String imageName,
+		      String toolTipText, String altText) {
+
+		    ImageIcon icon = makeIcon(imageName, altText);
+		    
+		    //Create and initialize the button.
+		    JButton button = new JButton();
+		    button.setToolTipText(toolTipText);
+		    button.setLayout(null);
+		    button.setOpaque(false);
+		    button.setSize(20,20);
+		    button.setVisible(true);
+
+		    if (icon != null) { //image found
+		      button.setIcon(icon);
+		    } else { //no image found
+		      button.setText(altText);
+		    }
+
+		    return button;
+	  }
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/io/AlignmentReader.java b/src/main/java/es/uvigo/darwin/jmodeltest/io/AlignmentReader.java
new file mode 100644
index 0000000..f9dc26d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/io/AlignmentReader.java
@@ -0,0 +1,139 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.io;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.PushbackReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+import pal.alignment.Alignment;
+import pal.alignment.ReadAlignment;
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.exception.AlignmentParseException;
+
+public abstract class AlignmentReader {
+	private static ApplicationOptions options = ApplicationOptions
+			.getInstance();;
+
+	/****************************
+	 * readDataFile **************************** * Reads the input file and gets
+	 * the number of taxa and alignment * length * *
+	 ***********************************************************************/
+
+	static public void getHeader(String infilenameComplete) {
+		// needs the complete path to the file
+		try {
+			TextInputStream in = new TextInputStream(infilenameComplete);
+			String line = in.readLine();
+			in.close();
+			StringTokenizer reader = new StringTokenizer(line);
+			options.setNumTaxa(Integer.parseInt(reader.nextToken()));
+			options.setNumSites(Integer.parseInt(reader.nextToken()));
+		} catch (FileNotFoundException e) {
+			JOptionPane.showMessageDialog(new JFrame(),
+					"Could not read the input alignment", "jModelTest error",
+					JOptionPane.ERROR_MESSAGE);
+		}
+
+		if (options.getNumTaxa() <= 4)
+			JOptionPane.showMessageDialog(new JFrame(),
+					"The number of taxa does not seem to be correct: "
+							+ options.getNumTaxa(), "jModelTest error",
+					JOptionPane.ERROR_MESSAGE);
+
+		if (options.getNumSites() <= 1)
+			JOptionPane.showMessageDialog(new JFrame(),
+					"The number of sites does not seem to be correct: "
+							+ options.getNumTaxa(), "jModelTest error",
+					JOptionPane.ERROR_MESSAGE);
+	}
+
+	/**
+	 * Creates an alignment instance.
+	 * 
+	 * @param out
+	 *            the out
+	 * @param pr
+	 *            the pushback reader which contains the alignment
+	 * @param debug
+	 *            the debug state
+	 * 
+	 * @return the alignment
+	 * 
+	 * @throws AlignmentParseException
+	 *             the alignment parse exception
+	 * @throws IOException
+	 *             Signals that an I/O exception has occured.
+	 */
+	public static Alignment createAlignment(PrintWriter out, PushbackReader pr,
+			boolean debug) throws AlignmentParseException, IOException {
+
+		if (debug) {
+			out.println("");
+			out.println("**********************************************************");
+			out.println("  Reading alignment...");
+		}
+		Alignment alignment = null;
+		try {
+			alignment = new ReadAlignment(pr);
+		} catch (pal.alignment.AlignmentParseException e) {
+			throw new AlignmentParseException(e.getMessage());
+		}
+
+		List<String> seqNames = new ArrayList<String>(
+				alignment.getSequenceCount());
+		for (int i = 0; i < alignment.getSequenceCount(); i++) {
+			seqNames.add(alignment.getIdentifier(i).getName());
+		}
+
+		String currString;
+		int size = alignment.getSequenceCount();
+		for (int i = 0; i < size; i++) {
+			currString = seqNames.get(i);
+			for (int j = i + 1; j < size; j++) {
+				if (seqNames.get(j).equals(currString)) {
+					throw new AlignmentParseException(
+							"ERROR: There are duplicated taxa names in the alignment: "
+									+ currString);
+				}
+			}
+		}
+		
+		if (debug) {
+			for (int i = 0; i < alignment.getSequenceCount(); i++) {
+				out.println("    Sequence #" + (i + 1) + ": "
+						+ alignment.getIdentifier(i).getName());
+			}
+			out.println("   Alignment contains " + alignment.getSequenceCount()
+					+ " sequences of length " + alignment.getSiteCount());
+			out.println("");
+			out.println("**********************************************************");
+			out.println("");
+		}
+
+		return alignment;
+	}
+} // class AlignmentReader
+
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/io/DocumentOutputStream.java b/src/main/java/es/uvigo/darwin/jmodeltest/io/DocumentOutputStream.java
new file mode 100644
index 0000000..3e05d77
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/io/DocumentOutputStream.java
@@ -0,0 +1,107 @@
+/*
+Copyright (C) 1999 Timothy Prinzing
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * An OutputStream implementation that places it's
+ * output in a swing text model (Document).  The 
+ * Document can be either a plain text or styled
+ * document implementation.  If styled, the attributes
+ * assigned to the output stream will be used in
+ * the display of the output.
+ *
+ * @author  Timothy Prinzing
+ * @version 1.1 02/05/99
+ */
+
+package es.uvigo.darwin.jmodeltest.io;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+
+public class DocumentOutputStream extends OutputStream {
+
+    /**
+     * Constructs an output stream that will output to the
+     * given document with the given set of character attributes.
+     *
+     * @param doc the document to write to.
+     * @param a the character attributes to use for the written
+     *  text.
+     */
+    public DocumentOutputStream(Document doc, AttributeSet a) {
+	this.doc = doc;
+	this.a = a;
+    }
+
+    /**
+     * Constructs an output stream that will output to the
+     * given document with whatever the default attributes
+     * are.
+     *
+     * @param doc the document to write to.
+     */
+    public DocumentOutputStream(Document doc) {
+	this(doc, null);
+    }
+
+    /**
+     * Writes the specified byte to this output stream. 
+     * <p>
+     * Subclasses of <code>OutputStream</code> must provide an 
+     * implementation for this method. 
+     *
+     * @param      b   the <code>byte</code>.
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JDK1.0
+     */
+    public void write(int b) throws IOException {
+	one[0] = (byte) b;
+	write(one, 0, 1);
+    }
+    
+    /**
+     * Writes <code>len</code> bytes from the specified byte array 
+     * starting at offset <code>off</code> to this output stream. 
+     * <p>
+     * The <code>write</code> method of <code>OutputStream</code> calls 
+     * the write method of one argument on each of the bytes to be 
+     * written out. Subclasses are encouraged to override this method and 
+     * provide a more efficient implementation. 
+     *
+     * @param      b     the data.
+     * @param      off   the start offset in the data.
+     * @param      len   the number of bytes to write.
+     * @exception  IOException  if an I/O error occurs.
+     * @since      JDK1.0
+     */
+    public void write(byte b[], int off, int len) throws IOException {
+	try {
+	    doc.insertString(doc.getLength(), new String(b, off, len), a);
+	} catch (BadLocationException ble) {
+	    throw new IOException(ble.getMessage());
+	}
+    }
+
+    private byte[] one = new byte[1];
+    private Document doc;
+    private AttributeSet a;
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/io/HtmlReporter.java b/src/main/java/es/uvigo/darwin/jmodeltest/io/HtmlReporter.java
new file mode 100644
index 0000000..c7a16a4
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/io/HtmlReporter.java
@@ -0,0 +1,664 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.io;
+
+import java.awt.GraphicsEnvironment;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.jfree.chart.ChartUtilities;
+
+import pal.tree.Tree;
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.ModelTestConfiguration;
+import es.uvigo.darwin.jmodeltest.exe.RunPhyml;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+import es.uvigo.darwin.jmodeltest.tree.TreeSummary;
+import es.uvigo.darwin.jmodeltest.tree.TreeUtilities;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+import es.uvigo.darwin.prottest.facade.TreeFacade;
+import es.uvigo.darwin.prottest.facade.TreeFacadeImpl;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+
+public abstract class HtmlReporter {
+
+	private static String[] TEMPLATE_DIRS = { "resources" };
+	private static String[] TEMPLATE_FILES = {
+			"resources" + File.separator + "style.css",
+			"resources" + File.separator + "homeIcon.gif",
+			"resources" + File.separator + "topIcon.gif",
+			"resources" + File.separator + "logo0.png" };
+	private static TreeFacade treeFacade = new TreeFacadeImpl();
+	private static Map<String, Object> datamodel;
+	private static File LOG_DIR;
+	private static File IMAGES_DIR;
+	private static String RESOURCES_DIR;
+	
+	static {
+		String strLogDir = ModelTestConfiguration.getLogDir();
+		if (!strLogDir.startsWith(File.separator)) {
+			strLogDir = ModelTestConfiguration.PATH + strLogDir;
+		}
+		LOG_DIR = new File(strLogDir);
+		IMAGES_DIR = new File(strLogDir + File.separator + "images");
+		RESOURCES_DIR = ModelTestConfiguration.PATH + "resources" + File.separator + "template";
+	}
+	
+	public static void buildReport(ApplicationOptions options, Model models[],
+			File mOutputFile) {
+		buildReport(options, models, mOutputFile, null);
+	}
+	
+	public static void buildReport(ApplicationOptions options, Model models[],
+			File mOutputFile, TreeSummary summary) {
+
+		File outputFile;
+		if (mOutputFile != null) {
+			if (!(mOutputFile.getName().endsWith(".htm") || mOutputFile.getName()
+					.endsWith(".html"))) {
+				outputFile = new File(mOutputFile.getAbsolutePath() + ".html");
+			} else {
+				outputFile = mOutputFile;
+			}
+		} else {
+			outputFile = new File(LOG_DIR.getPath() + File.separator
+					+ options.getInputFile().getName()
+					+ ".jmodeltest." + options.getExecutionName()
+					+ ".html");
+		}
+		
+		// Add the values in the datamodel
+		datamodel = new HashMap<String, Object>();
+		java.util.Date current_time = new java.util.Date();
+		datamodel.put("date", current_time.toString());
+		datamodel.put("system", System.getProperty("os.name") + " "
+				+ System.getProperty("os.version") + ", arch: "
+				+ System.getProperty("os.arch") + ", bits: "
+				+ System.getProperty("sun.arch.data.model") + ", numcores: "
+				+ Runtime.getRuntime().availableProcessors());
+		
+		fillInWithOptions(options);
+		fillInWithSortedModels(models);
+		datamodel.put("isTopologiesSummary", summary!=null ? new Integer(1) : new Integer(0));
+		if (summary != null) {
+			fillInWithTopologies(summary, options);
+		}
+
+		if (options.doAIC) {
+			Collection<Map<String, String>> aicModels = new ArrayList<Map<String, String>>();
+			Map<String, String> bestAicModel = new HashMap<String, String>();
+			fillInWIthInformationCriterion(ModelTest.getMyAIC(), aicModels,
+					bestAicModel);
+			datamodel.put("aicModels", aicModels);
+			datamodel.put("bestAicModel", bestAicModel);
+			datamodel.put("aicConfidenceCount", ModelTest.getMyAIC()
+					.getConfidenceModels().size());
+			StringBuffer aicConfModels = new StringBuffer();
+			for (Model model : ModelTest.getMyAIC().getConfidenceModels())
+				aicConfModels.append(model.getName() + " ");
+			datamodel.put("aicConfidenceList", aicConfModels.toString());
+			if (options.writePAUPblock) {
+				ByteArrayOutputStream baos = new ByteArrayOutputStream();
+				PrintStream ps = new PrintStream(baos);
+				TextOutputStream strOutput = new TextOutputStream(ps);
+			    ModelTest.WritePaupBlock(strOutput, "AIC", ModelTest.getMyAIC().getMinModel());
+			    try {
+			    	String pblock = baos.toString("UTF8");
+			    	pblock = pblock.replaceAll("\n", "<br/>");
+					datamodel.put("aicPaup", pblock);
+				} catch (UnsupportedEncodingException e) {
+				}
+				
+			}
+			buildChart(outputFile, ModelTest.getMyAIC());
+			datamodel.put("aicEuImagePath",IMAGES_DIR.getName() + File.separator + outputFile.getName() + "_eu_AIC.png");
+			datamodel.put("aicRfImagePath",IMAGES_DIR.getName() + File.separator + outputFile.getName() + "_rf_AIC.png");
+		}
+
+		if (options.doAICc) {
+			Collection<Map<String, String>> aiccModels = new ArrayList<Map<String, String>>();
+			Map<String, String> bestAiccModel = new HashMap<String, String>();
+			fillInWIthInformationCriterion(ModelTest.getMyAICc(), aiccModels,
+					bestAiccModel);
+			datamodel.put("aiccModels", aiccModels);
+			datamodel.put("bestAiccModel", bestAiccModel);
+			datamodel.put("aiccConfidenceCount", ModelTest.getMyAICc()
+					.getConfidenceModels().size());
+			StringBuffer aiccConfModels = new StringBuffer();
+			for (Model model : ModelTest.getMyAICc().getConfidenceModels())
+				aiccConfModels.append(model.getName() + " ");
+			datamodel.put("aiccConfidenceList", aiccConfModels.toString());
+			if (options.writePAUPblock) {
+				ByteArrayOutputStream baos = new ByteArrayOutputStream();
+				PrintStream ps = new PrintStream(baos);
+				TextOutputStream strOutput = new TextOutputStream(ps);
+			    ModelTest.WritePaupBlock(strOutput, "AICc", ModelTest.getMyAICc().getMinModel());
+			    try {
+			    	String pblock = baos.toString("UTF8");
+			    	pblock = pblock.replaceAll("\n", "<br/>");
+					datamodel.put("aiccPaup", pblock);
+				} catch (UnsupportedEncodingException e) {
+				}
+				
+			}
+			buildChart(outputFile, ModelTest.getMyAICc());
+			datamodel.put("aiccEuImagePath",IMAGES_DIR.getName() + File.separator + outputFile.getName() + "_eu_AICc.png");
+			datamodel.put("aiccRfImagePath",IMAGES_DIR.getName() + File.separator + outputFile.getName() + "_rf_AICc.png");
+		}
+
+		if (options.doBIC) {
+			Collection<Map<String, String>> bicModels = new ArrayList<Map<String, String>>();
+			Map<String, String> bestBicModel = new HashMap<String, String>();
+			fillInWIthInformationCriterion(ModelTest.getMyBIC(), bicModels,
+					bestBicModel);
+			datamodel.put("bicModels", bicModels);
+			datamodel.put("bestBicModel", bestBicModel);
+			datamodel.put("bicConfidenceCount", ModelTest.getMyBIC()
+					.getConfidenceModels().size());
+			StringBuffer bicConfModels = new StringBuffer();
+			for (Model model : ModelTest.getMyBIC().getConfidenceModels())
+				bicConfModels.append(model.getName() + " ");
+			datamodel.put("bicConfidenceList", bicConfModels.toString());
+			if (options.writePAUPblock) {
+				ByteArrayOutputStream baos = new ByteArrayOutputStream();
+				PrintStream ps = new PrintStream(baos);
+				TextOutputStream strOutput = new TextOutputStream(ps);
+			    ModelTest.WritePaupBlock(strOutput, "BIC", ModelTest.getMyBIC().getMinModel());
+			    try {
+			    	String pblock = baos.toString("UTF8");
+			    	pblock = pblock.replaceAll("\n", "<br/>");
+					datamodel.put("bicPaup", pblock);
+				} catch (UnsupportedEncodingException e) {
+				}
+				
+			}
+			buildChart(outputFile, ModelTest.getMyBIC());
+			datamodel.put("bicEuImagePath",IMAGES_DIR.getName() + File.separator + outputFile.getName() + "_eu_BIC.png");
+			datamodel.put("bicRfImagePath",IMAGES_DIR.getName() + File.separator + outputFile.getName() + "_rf_BIC.png");
+		}
+
+		if (options.doDT) {
+			Collection<Map<String, String>> dtModels = new ArrayList<Map<String, String>>();
+			Map<String, String> bestDtModel = new HashMap<String, String>();
+			fillInWIthInformationCriterion(ModelTest.getMyDT(), dtModels,
+					bestDtModel);
+			datamodel.put("dtModels", dtModels);
+			datamodel.put("bestDtModel", bestDtModel);
+			datamodel.put("dtConfidenceCount", ModelTest.getMyDT()
+					.getConfidenceModels().size());
+			StringBuffer dtConfModels = new StringBuffer();
+			for (Model model : ModelTest.getMyDT().getConfidenceModels())
+				dtConfModels.append(model.getName() + " ");
+			datamodel.put("dtConfidenceList", dtConfModels.toString());
+			if (options.writePAUPblock) {
+				ByteArrayOutputStream baos = new ByteArrayOutputStream();
+				PrintStream ps = new PrintStream(baos);
+				TextOutputStream strOutput = new TextOutputStream(ps);
+			    ModelTest.WritePaupBlock(strOutput, "DT", ModelTest.getMyDT().getMinModel());
+			    try {
+			    	String pblock = baos.toString("UTF8");
+			    	pblock = pblock.replaceAll("\n", "<br/>");
+					datamodel.put("dtPaup", pblock);
+				} catch (UnsupportedEncodingException e) {
+				}
+				
+			}
+			buildChart(outputFile, ModelTest.getMyDT());
+			datamodel.put("dtEuImagePath",IMAGES_DIR.getName() + File.separator + outputFile.getName() + "_eu_DT.png");
+			datamodel.put("dtRfImagePath",IMAGES_DIR.getName() + File.separator + outputFile.getName() + "_rf_DT.png");
+		}
+
+		datamodel.put("doAICAveragedPhylogeny",
+				ModelTest.getConsensusAIC() != null ? new Integer(1)
+						: new Integer(0));
+		if (ModelTest.getConsensusAIC() != null) {
+			datamodel.put("aicConsensusTree", treeFacade.toNewick(ModelTest
+					.getConsensusAIC().getConsensus(), true, true, true));
+			datamodel.put("consensusType", ModelTest.getConsensusAIC()
+					.getConsensusType());
+		}
+		datamodel.put("doAICcAveragedPhylogeny",
+				ModelTest.getConsensusAICc() != null ? new Integer(1)
+						: new Integer(0));
+		if (ModelTest.getConsensusAICc() != null) {
+			datamodel.put("aiccConsensusTree", treeFacade.toNewick(ModelTest
+					.getConsensusAICc().getConsensus(), true, true, true));
+			datamodel.put("consensusType", ModelTest.getConsensusAICc()
+					.getConsensusType());
+		}
+		datamodel.put("doBICAveragedPhylogeny",
+				ModelTest.getConsensusBIC() != null ? new Integer(1)
+						: new Integer(0));
+		if (ModelTest.getConsensusBIC() != null) {
+			datamodel.put("bicConsensusTree", treeFacade.toNewick(ModelTest
+					.getConsensusBIC().getConsensus(), true, true, true));
+			datamodel.put("consensusType", ModelTest.getConsensusBIC()
+					.getConsensusType());
+		}
+		datamodel.put("doDTAveragedPhylogeny",
+				ModelTest.getConsensusDT() != null ? new Integer(1)
+						: new Integer(0));
+		if (ModelTest.getConsensusDT() != null) {
+			datamodel.put("dtConsensusTree", treeFacade.toNewick(ModelTest
+					.getConsensusDT().getConsensus(), true, true, true));
+			datamodel.put("consensusType", ModelTest.getConsensusDT()
+					.getConsensusType());
+		}
+
+		// Process the template using FreeMarker
+		try {
+			freemarkerDo(datamodel, "index.html", outputFile);
+		} catch (Exception e) {
+			System.out
+					.println("There was a problem building the html log files: "
+							+ e.getLocalizedMessage());
+		}
+		
+	}
+
+	// Process a template using FreeMarker and print the results
+	static void freemarkerDo(Map<String, Object> datamodel, String template,
+			File outputFile) throws Exception {
+		if (!LOG_DIR.exists() || !LOG_DIR.isDirectory()) {
+			LOG_DIR.delete();
+			LOG_DIR.mkdir();
+		}
+		if (!IMAGES_DIR.exists() || !IMAGES_DIR.isDirectory()) {
+			IMAGES_DIR.delete();
+			IMAGES_DIR.mkdir();
+		}
+		
+		// Check auxiliary files
+		for (String file : TEMPLATE_DIRS) {
+			File auxDir = new File(LOG_DIR.getPath() + File.separator + file);
+			if (!auxDir.exists()) {
+				auxDir.mkdirs();
+			}
+		}
+
+		for (String file : TEMPLATE_FILES) {
+			File auxFile = new File(LOG_DIR.getPath() + File.separator + file);
+			if (!auxFile.exists()) {
+				File inFile = new File(RESOURCES_DIR + File.separator
+						+ file);
+				if (inFile.exists()) {
+					copyFile(inFile, auxFile);
+				}
+			}
+		}
+		
+		Configuration cfg = new Configuration();
+
+		cfg.setDirectoryForTemplateLoading(new File(RESOURCES_DIR));
+
+		Template tpl = cfg.getTemplate(template);
+		OutputStreamWriter output = new FileWriter(outputFile);
+
+		tpl.process(datamodel, output);
+	}
+
+	private static void fillInWithOptions(ApplicationOptions options) {
+
+		StringBuffer arguments = new StringBuffer();
+		for (String argument : ModelTest.arguments)
+			arguments.append(argument + " ");
+		datamodel.put("arguments", arguments);
+		datamodel.put("alignName", options.getInputFile());
+		datamodel.put("numTaxa", options.getNumTaxa());
+		datamodel.put("seqLength", options.getNumSites());
+		datamodel.put("phymlVersion", RunPhyml.PHYML_VERSION);
+		datamodel.put("phymlBinary", Utilities.getBinaryVersion());
+		datamodel.put("candidateModels", ModelTest.getCandidateModels().length);
+		if (options.getSubstTypeCode() == 0)
+			datamodel.put("substSchemes", "3");
+		else if (options.getSubstTypeCode() == 1)
+			datamodel.put("substSchemes", "5");
+		else if (options.getSubstTypeCode() == 2)
+			datamodel.put("substSchemes", "7");
+		else
+			datamodel.put("substSchemes", "11");
+
+		datamodel
+				.put("includeF", options.doF ? new Integer(1) : new Integer(0));
+		datamodel
+				.put("includeG", options.doG ? new Integer(1) : new Integer(0));
+		datamodel
+				.put("includeI", options.doI ? new Integer(1) : new Integer(0));
+		datamodel.put("isAIC", options.doAIC ? new Integer(1) : new Integer(0));
+		datamodel.put("isAICc", options.doAICc ? new Integer(1)
+				: new Integer(0));
+		datamodel.put("isBIC", options.doBIC ? new Integer(1) : new Integer(0));
+		datamodel.put("isDT", options.doDT ? new Integer(1) : new Integer(0));
+		datamodel.put("numCat", options.numGammaCat);
+		datamodel.put("isPAUP", options.writePAUPblock ? new Integer(1) : new Integer(0));
+
+		StringBuffer optimizedParameters = new StringBuffer(
+				"Substitution parameters ");
+		if (options.countBLasParameters)
+			optimizedParameters.append("+ " + options.getNumBranches()
+					+ " branch lengths ");
+		if (options.optimizeMLTopology)
+			optimizedParameters.append("+ topology");
+		datamodel.put("freeParameters", optimizedParameters.toString());
+
+		datamodel.put("userTreeDef",
+				options.userTopologyExists ? new Integer(1) : new Integer(0));
+		if (options.fixedTopology)
+			datamodel.put("baseTree", "Fixed BioNJ");
+		else if (options.optimizeMLTopology)
+			datamodel.put("baseTree", "Maximum Likelihood");
+		else if (options.userTopologyExists) {
+			datamodel.put("baseTree", "Fixed user tree topology");
+			datamodel.put("userTreeFilename", options.getInputTreeFile()
+					.getName());
+			datamodel.put("userTree", options.getUserTree());
+		} else
+			datamodel.put("baseTree", "BioNJ");
+
+		switch (options.treeSearchOperations) {
+		case NNI:
+			datamodel.put("searchAlgorithm", "NNI");
+			break;
+		case SPR:
+			datamodel.put("searchAlgorithm", "SPR");
+			break;
+		case BEST:
+			datamodel.put("searchAlgorithm", "Best of {NNI, SPR}");
+			break;
+		}
+
+		datamodel.put("confidenceInterval", String.format(Locale.ENGLISH,
+				"%5.2f", options.confidenceInterval * 100));
+	}
+
+	private static void fillInWithSortedModels(Model[] models) {
+
+		Collection<Map<String, String>> sortedModels = new ArrayList<Map<String, String>>();
+		int index = 1;
+		for (Model model : models) {
+			Map<String, String> modelMap = new HashMap<String, String>();
+			modelMap.put("index", String.valueOf(index++));
+			modelMap.put("name", model.getName());
+			modelMap.put("partition", model.getPartition());
+			modelMap.put("lnl",
+					String.format(Locale.ENGLISH, "%5.4f", model.getLnL()));
+			modelMap.put("k", String.valueOf(model.getK()));
+			modelMap.put(
+					"fA",
+					model.ispF() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getfA()) : "-");
+			modelMap.put(
+					"fC",
+					model.ispF() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getfC()) : "-");
+			modelMap.put(
+					"fG",
+					model.ispF() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getfG()) : "-");
+			modelMap.put(
+					"fT",
+					model.ispF() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getfT()) : "-");
+			modelMap.put(
+					"titv",
+					model.ispT() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getTitv()) : "-");
+			modelMap.put(
+					"rA",
+					model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getRa()) : "-");
+			modelMap.put(
+					"rB",
+					model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getRb()) : "-");
+			modelMap.put(
+					"rC",
+					model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getRc()) : "-");
+			modelMap.put(
+					"rD",
+					model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getRd()) : "-");
+			modelMap.put(
+					"rE",
+					model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getRe()) : "-");
+			modelMap.put(
+					"rF",
+					model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getRf()) : "-");
+			modelMap.put(
+					"pInv",
+					model.ispI() ? String.format(Locale.ENGLISH, "%5.4f",
+							model.getPinv()) : "-");
+			modelMap.put(
+					"shape",
+					model.ispG() ? String.format(Locale.ENGLISH, "%6.4f",
+							model.getShape()) : "-");
+			modelMap.put("tree", model.getTreeString());
+			sortedModels.add(modelMap);
+		}
+
+		datamodel.put("sortedModels", sortedModels);
+	}
+
+	private static void fillInWithTopologies(TreeSummary summary, ApplicationOptions options) {
+		datamodel.put("numberOfTopologies", summary.getNumberOfTopologies());
+		Collection<Map<String, String>> sortedTopologies = new ArrayList<Map<String, String>>();
+		for (int index=0; index<summary.getNumberOfTopologies(); index++) {
+			Map<String, String> topologyMap = new HashMap<String, String>();
+			topologyMap.put("index", String.valueOf(index));
+			Tree topology = summary.getTopology(index);
+			topologyMap.put("tree", TreeUtilities.toNewick(topology, false, false, false));
+			List<Model> models = summary.getModelsByTopology(index);
+			StringBuilder sb = new StringBuilder();
+			for (Model model : models) {
+				sb.append(model.getName() + " ");
+			}
+			topologyMap.put("models", sb.toString());
+			topologyMap.put("models", sb.toString());
+			
+			if (options.doAIC) {
+				topologyMap.put("aicRank", String.valueOf(summary.aicIndexOf(topology)));
+				topologyMap.put("aicRF", String.valueOf(summary.aicRfOf(topology)));
+				topologyMap.put("aicAvgDistance", Utilities.format(summary.aicAvgDistance(topology), 6, 4, true));
+				topologyMap.put("aicVarDistance", Utilities.format(summary.aicVarDistance(topology), 6, 4, true));
+				topologyMap.put("aicWeight", Utilities.format(summary.aicWeight(topology), 6, 4, false));
+			}
+			
+			if (options.doAICc) {
+				topologyMap.put("aiccRank", String.valueOf(summary.aiccIndexOf(topology)));
+				topologyMap.put("aiccRF", String.valueOf(summary.aiccRfOf(topology)));
+				topologyMap.put("aiccAvgDistance", Utilities.format(summary.aiccAvgDistance(topology), 6, 4, true));
+				topologyMap.put("aiccVarDistance", Utilities.format(summary.aiccVarDistance(topology), 6, 4, true));
+				topologyMap.put("aiccWeight", Utilities.format(summary.aiccWeight(topology), 6, 4, false));
+			}
+			
+			if (options.doBIC) {
+				topologyMap.put("bicRank", String.valueOf(summary.bicIndexOf(topology)));
+				topologyMap.put("bicRF", String.valueOf(summary.bicRfOf(topology)));
+				topologyMap.put("bicAvgDistance", Utilities.format(summary.bicAvgDistance(topology), 6, 4, true));
+				topologyMap.put("bicVarDistance", Utilities.format(summary.bicVarDistance(topology), 6, 4, true));
+				topologyMap.put("bicWeight", Utilities.format(summary.bicWeight(topology), 6, 4, false));
+			}
+			
+			if (options.doDT) {
+				topologyMap.put("dtRank", String.valueOf(summary.dtIndexOf(topology)));
+				topologyMap.put("dtRF", String.valueOf(summary.dtRfOf(topology)));
+				topologyMap.put("dtAvgDistance", Utilities.format(summary.dtAvgDistance(topology), 6, 4, true));
+				topologyMap.put("dtVarDistance", Utilities.format(summary.dtVarDistance(topology), 6, 4, true));
+				topologyMap.put("dtWeight", Utilities.format(summary.dtWeight(topology), 6, 4, false));
+			}
+			
+			sortedTopologies.add(topologyMap);
+		}
+		
+		datamodel.put("sortedTopologies", sortedTopologies);
+	}
+	
+	private static void fillInWIthInformationCriterion(InformationCriterion ic,
+			Collection<Map<String, String>> sortedModels,
+			Map<String, String> bestModel) {
+
+		Model model = ic.getModel(0);
+		bestModel.put("index", String.valueOf(1));
+		bestModel.put("name", model.getName());
+		bestModel.put("partition", model.getPartition());
+		bestModel.put("lnl",
+				String.format(Locale.ENGLISH, "%5.4f", model.getLnL()));
+		bestModel.put("k", String.valueOf(model.getK()));
+		bestModel.put(
+				"fA",
+				model.ispF() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getfA()) : "-");
+		bestModel.put(
+				"fC",
+				model.ispF() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getfC()) : "-");
+		bestModel.put(
+				"fG",
+				model.ispF() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getfG()) : "-");
+		bestModel.put(
+				"fT",
+				model.ispF() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getfT()) : "-");
+		bestModel.put(
+				"titv",
+				model.ispT() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getTitv()) : "-");
+		bestModel.put(
+				"rA",
+				model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getRa()) : "-");
+		bestModel.put(
+				"rB",
+				model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getRb()) : "-");
+		bestModel.put(
+				"rC",
+				model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getRc()) : "-");
+		bestModel.put(
+				"rD",
+				model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getRd()) : "-");
+		bestModel.put(
+				"rE",
+				model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getRe()) : "-");
+		bestModel.put(
+				"rF",
+				model.ispR() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getRf()) : "-");
+		bestModel.put(
+				"pInv",
+				model.ispI() ? String.format(Locale.ENGLISH, "%5.4f",
+						model.getPinv()) : "-");
+		bestModel.put(
+				"shape",
+				model.ispG() ? String.format(Locale.ENGLISH, "%6.4f",
+						model.getShape()) : "-");
+		bestModel.put("value",
+				String.format(Locale.ENGLISH, "%5.4f", ic.getValue(model)));
+		bestModel.put("delta",
+				String.format(Locale.ENGLISH, "%5.4f", ic.getDelta(model)));
+		bestModel.put("weight",
+				String.format(Locale.ENGLISH, "%5.4f", ic.getWeight(model)));
+		bestModel.put("tree", model.getTreeString());
+		bestModel.put("cumWeight",
+				String.format(Locale.ENGLISH, "%5.4f", ic.getCumWeight(model)));
+		sortedModels.add(bestModel);
+		for (int i = 1; i < ic.getNumModels(); i++) {
+			model = ic.getModel(i);
+			Map<String, String> modelMap = new HashMap<String, String>();
+			modelMap.put("index", String.valueOf(i + 1));
+			modelMap.put("name", model.getName());
+			modelMap.put("partition", model.getPartition());
+			modelMap.put("lnl",
+					String.format(Locale.ENGLISH, "%5.4f", model.getLnL()));
+			modelMap.put("k", String.valueOf(model.getK()));
+			modelMap.put("value",
+					String.format(Locale.ENGLISH, "%5.4f", ic.getValue(model)));
+			modelMap.put("delta",
+					String.format(Locale.ENGLISH, "%5.4f", ic.getDelta(model)));
+			modelMap.put("weight",
+					String.format(Locale.ENGLISH, "%5.4f", ic.getWeight(model)));
+			modelMap.put(
+					"cumWeight",
+					String.format(Locale.ENGLISH, "%5.4f",
+							ic.getCumWeight(model)));
+			modelMap.put("tree", model.getTreeString());
+			sortedModels.add(modelMap);
+		}
+	}
+
+	public static void copyFile(File in, File out) throws IOException {
+		FileChannel inChannel = new FileInputStream(in).getChannel();
+		FileChannel outChannel = new FileOutputStream(out).getChannel();
+		try {
+			inChannel.transferTo(0, inChannel.size(), outChannel);
+		} catch (IOException e) {
+			throw e;
+		} finally {
+			if (inChannel != null)
+				inChannel.close();
+			if (outChannel != null)
+				outChannel.close();
+		}
+	}
+
+	private static void buildChart(File mOutputFile, InformationCriterion ic) {
+		
+		/* This line prevents Swing exceptions on headless environments */
+		if (GraphicsEnvironment.isHeadless()) { return; }
+		
+		int width = 500;
+		int height = 300;
+		try {
+			if (!IMAGES_DIR.exists()) {
+				IMAGES_DIR.mkdir();
+			}
+			ChartUtilities.saveChartAsPNG(new File(IMAGES_DIR.getPath() + File.separator + mOutputFile.getName() + "_rf_" + ic + ".png"), 
+					RFHistogram.buildRFHistogram(ic),
+					width, height);
+			ChartUtilities.saveChartAsPNG(new File(IMAGES_DIR.getPath() + File.separator + mOutputFile.getName() + "_eu_" + ic + ".png"), 
+					RFHistogram.buildEuclideanHistogram(ic),
+					width, height);
+		} catch (IOException e) {
+//			e.printStackTrace();
+		}
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/io/NullPrintStream.java b/src/main/java/es/uvigo/darwin/jmodeltest/io/NullPrintStream.java
new file mode 100644
index 0000000..c0e62dc
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/io/NullPrintStream.java
@@ -0,0 +1,31 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.io;
+
+import java.io.OutputStream;
+
+public class NullPrintStream extends OutputStream {
+	public void write(byte[] buf, int off, int len) {
+	}
+
+	public void write(int b) {
+	}
+
+	public void write(byte[] b) {
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/io/RFHistogram.java b/src/main/java/es/uvigo/darwin/jmodeltest/io/RFHistogram.java
new file mode 100644
index 0000000..a2970f4
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/io/RFHistogram.java
@@ -0,0 +1,99 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.io;
+
+import java.util.List;
+import java.util.Random;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.data.statistics.HistogramDataset;
+import org.jfree.data.statistics.HistogramType;
+
+import pal.tree.Tree;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+import es.uvigo.darwin.jmodeltest.tree.TreeDistancesCache;
+import es.uvigo.darwin.jmodeltest.tree.TreeEuclideanDistancesCache;
+import es.uvigo.darwin.jmodeltest.tree.TreeRFDistancesCache;
+
+public class RFHistogram {
+
+	private static JFreeChart buildHistogram(double[] values, int steps,
+			String plotTitle, String xAxis, String yAxis) {
+		HistogramDataset hds = new HistogramDataset();
+		hds.setType(HistogramType.RELATIVE_FREQUENCY);
+		hds.addSeries(1, values, steps);
+		PlotOrientation orientation = PlotOrientation.VERTICAL;
+		boolean show = false;
+		boolean toolTips = false;
+		boolean urls = false;
+		JFreeChart chart = ChartFactory.createHistogram(plotTitle, xAxis,
+				yAxis, hds, orientation, show, toolTips, urls);
+		return chart;
+	}
+	
+	
+	public static JFreeChart buildDistancesHistogram(InformationCriterion ic, TreeDistancesCache distances, String plotTitle) {
+		List<Model> models = ic.getConfidenceModels();
+		
+		Tree bestTree = ic.getMinModel().getTree();
+		double values[] = new double[models.size()-1];
+		int i = 0;
+		for (Model model : models) {
+			if (!model.equals(ic.getMinModel())) {
+				double distance = distances.getDistance(bestTree, model.getTree());
+				values[i] = distance;
+				i++;
+			}
+		}
+		String xaxis = "distance";
+		String yaxis = "count";
+		int steps = 10;
+		JFreeChart chart = buildHistogram(values, steps,
+				plotTitle, xaxis, yaxis);
+		
+		return chart;
+	}
+
+	public static JFreeChart buildRFHistogram(InformationCriterion ic) {
+		return buildDistancesHistogram(ic, TreeRFDistancesCache.getInstance(),
+				ic + " RF distances histogram");
+	}
+	
+	public static JFreeChart buildEuclideanHistogram(InformationCriterion ic) {
+		return buildDistancesHistogram(ic, TreeEuclideanDistancesCache.getInstance(),
+				ic + " euclidean distances histogram");
+	}
+	
+	public static JFreeChart buildRandomHistogram() {
+		Random generator = new Random();
+		double[] value = new double[100];
+		for (int i = 1; i < 100; i++) {
+			value[i] = generator.nextDouble();
+		}
+		int number = 10;
+		String plotTitle = "Histogram";
+		String xaxis = "number";
+		String yaxis = "value";
+		JFreeChart chart = buildHistogram(value, number, plotTitle, xaxis,
+				yaxis);
+		return chart;
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/io/TextInputStream.java b/src/main/java/es/uvigo/darwin/jmodeltest/io/TextInputStream.java
new file mode 100755
index 0000000..cbc93d5
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/io/TextInputStream.java
@@ -0,0 +1 @@
+/*
Copyright (C) 1997 Quinn Snell

This program 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.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package es.uvigo.darwin.jmodeltest.io;

import java.io.BufferedReader;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

public class TextInputStream {
	private BufferedReader stdin;
	char missed, currchar;
	boolean EOF;

	public TextInputStream() {
		stdin = new BufferedReader(new InputStreamReader(System.in));
		missed = '\0';
		currchar = '\0';
		EOF = false;
	}

	/**
	 * Constructs a TextInputStream for input from a text file
	 * 
	 * @param s
	 *            the text filename
	 */

	public TextInputStream(String s) throws FileNotFoundException {
		stdin = new BufferedReader(
				new InputStreamReader(new FileInputStream(s)));
		missed = '\0';
		currchar = '\0';
		EOF = false;
	}

	int readIntString(char[] s) throws IOException {
		int i;
		int state = 0;

		s[0] = missed;

		// Skip Whitespace
		while (Character.isWhitespace(s[0]) || s[0] == '\0') {
			s[0] = readChar();
			if (EOF)
				throw new EOFException();
		}

		// Use a finite automaton to check the integer number
		for (i = 1; !Character.isWhitespace(s[i - 1]); i++) {
			switch (s[i - 1]) {
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				switch (state) {
				case 0:
				case 1:
				case 2:
				case 3:
					state = 3;
					break;
				default:
					throw new IOException("Integer format:Bad Start");
				}
				break;
			case '+':
				switch (state) {
				case 0:
					i--; // Throw away the + sign
					state = 1;
					break;
				default:
					throw new IOException("Integer format:+ sign wrong");
				}
				break;
			case '-':
				switch (state) {
				case 0:
					state = 2;
					break;
				default:
					throw new IOException("Integer format:- sign wrong");
				}
				break;
			default:
				throw new IOException("Integer format error");
			}
			s[i] = readChar();
		}
		missed = s[i - 1];
		return i - 1;
	}

	int readFloatString(char[] s) throws IOException {
		int i;
		int state = 0;

		s[0] = missed;

		// Skip Whitespace
		while (Character.isWhitespace(s[0]) || s[0] == '\0') {
			s[0] = readChar();
			if (EOF)
				throw new EOFException();
		}

		// Use a finite automaton to check the floating point number
		for (i = 1; !Character.isWhitespace(s[i - 1]); i++) {
			switch (s[i - 1]) {
			case '0':
			case '1':
			case '2':
			case '3':
			case '4':
			case '5':
			case '6':
			case '7':
			case '8':
			case '9':
				switch (state) {
				case 0:
				case 1:
				case 2:
				case 4:
					state = 4;
					break;
				case 3:
				case 5:
					state = 5;
					break;
				case 6:
				case 7:
				case 8:
				case 9:
					state = 9;
					break;
				default:
					throw new IOException("Floating point format error1");
				}
				break;
			case '+':
				switch (state) {
				case 0:
					i--; // Throw away the initial + sign
					state = 1;
					break;
				case 6:
					state = 8;
					break;
				default:
					throw new IOException("Floating point format error2");
				}
				break;
			case '-':
				switch (state) {
				case 0:
					state = 2;
					break;
				case 6:
					state = 7;
					break;
				default:
					throw new IOException("Floating point format error3");
				}
				break;
			case '.':
				switch (state) {
				case 0:
				case 1:
				case 2:
				case 4:
					state = 3;
					break;
				default:
					throw new IOException("Floating point format error4");
				}
				break;
			case 'e':
				switch (state) {
				case 4:
				case 5:
					state = 6;
					break;
				default:
					throw new IOException("Floating point format error5");
				}
				break;
			default:
				throw new IOException("Floating point format error6");
			}
			s[i] = readChar();
		}
		missed = s[i - 1];
		return i - 1;
	}

	/**
	 * Reads and returns the next integer in the stream
	 * 
	 * @return the integer
	 */
	public int readInt() {
		char[] s = new char[255];
		int length;

		try {
			length = readIntString(s);
			return Integer.valueOf(String.valueOf(s, 0, length)).intValue();
		} catch (IOException e) {/* System.err.println("Caught " + e); */
		}
		return Integer.MIN_VALUE;
	}

	/**
	 * Reads and returns the next float in the stream
	 * 
	 * @return the float
	 */
	public float readFloat() {
		char[] s = new char[255];
		int length;

		try {
			length = readFloatString(s);
			return Float.valueOf(String.valueOf(s, 0, length)).floatValue();
		} catch (IOException e) {
			;
		}
		return Float.NaN;
	}

	/**
	 * Reads and returns the next double in the stream
	 * 
	 * @return the double
	 */
	public double readDouble() {
		char[] s = new char[255];
		int length;

		try {
			length = readFloatString(s);
			return Double.valueOf(String.valueOf(s, 0, length)).doubleValue();
		} catch (IOException e) {
			;
		}
		return Double.NaN;
	}

	/**
	 * Reads and returns the next double in the stream
	 * 
	 * @return the double
	 */
	public char readChar() {
		char[] s = new char[2];
		if (missed == '\0') {
			try {
				if (stdin.read(s, 0, 1) == -1)
					EOF = true;
			} catch (IOException e) {
				;
			}
		} else {
			s[0] = missed;
			missed = '\0';
		}
		currchar = s[0];
		return s[0];
	}

	/**
	 * Reads and returns the next word in the stream
	 * 
	 * @return the word as a String
	 */
	public String readWord() {
		char[] s = new char[255];
		int i;

		s[0] = missed;

		// Skip Whitespace
		while (Character.isWhitespace(s[0]) || s[0] == '\0') {
			s[0] = readChar();
			if (EOF)
				return null;
		}

		for (i = 1; !Character.isWhitespace(s[i - 1]); i++)
			s[i] = readChar();

		missed = s[i - 1];
		return String.valueOf(s, 0, i - 1);
	}

	/**
	 * Reads and returns the next line in the stream
	 * 
	 * @return the line as a String without the return character
	 */
	public String readLine() {
		try {
			String s = stdin.readLine();
			missed = '\0';
			if (s == null) {
				EOF = true;
				// throw new EOFException();
			}
			return s;
		} catch (IOException e) {
			return null;
		}
	}

	/**
	 * Returns true if the end of the file has been reached, false otherwise.
	 */
	public boolean EOF() {
		return (EOF);
	}

	/**
	 * Closes the input stream
	 */
	public void close() {
		try {
			stdin.close();
		} catch (IOException e) {
			;
		}
	}
}
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/io/TextOutputStream.java b/src/main/java/es/uvigo/darwin/jmodeltest/io/TextOutputStream.java
new file mode 100755
index 0000000..a04a3cc
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/io/TextOutputStream.java
@@ -0,0 +1,612 @@
+/*
+Copyright (C) 1997 Cay Horstmann, Quinn Snell
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/**
+ * An output stream that can write formatted text
+ * @version 1.00 11 Apr 1997
+ * @author Cay Horstmann
+ * @author Quinn Snell (BYU)
+
+modified 21Feb05 by DP
+modified 15May06 by DP
+ */
+
+package es.uvigo.darwin.jmodeltest.io;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+public class TextOutputStream extends OutputStream
+{  
+
+   public TextOutputStream(String s, boolean append)
+   {
+          try
+          {
+			out = new PrintWriter(new FileOutputStream(s,append));
+          }
+          catch(IOException e)
+          {
+                  out = null;
+          }
+   }
+
+   public TextOutputStream(PrintStream s)
+   {  out = new PrintWriter(s);
+   }
+
+   /**
+    * Constructs a text output stream that sends its output to a file 
+    * @param s the file name
+    */
+
+   public TextOutputStream(String s)
+   {  try
+      {  out = new PrintWriter(new FileOutputStream(s));
+      }
+      catch(IOException e)
+      {  out = null;
+      }
+   }
+
+
+   /**
+    * Tests if the output stream is no longer valid
+    * @return <tt>true</tt> if the stream has failed
+    */
+
+   public boolean fail()
+   {  return out == null;
+   }
+
+   public boolean checkError()
+   {
+          return out.checkError();
+   }
+
+   public void flush()
+   {
+          out.flush();
+   }
+
+   /**
+    * Closes the stream 
+    */
+
+   public void close()
+   {  out.close();
+   }
+
+   /**
+    * Writes one byte to the stream
+    * @param b the byte to write
+    */
+
+   public void write(int b)
+   {  out.write(b);
+   }
+
+   /**
+    * Prints a string to a stream
+    * @param s the string to print
+    */
+
+   public void print(String s) 
+   { 
+          out.print(s); 
+          flush();
+   }
+
+   /**
+    * Prints a character to a stream
+    * @param c the character to print
+    */
+
+   public void print(char c) { out.print(c); flush(); }
+
+   /**
+    * Prints an object to a stream. The <tt>toString</tt> method of the object is invoked
+    * @param o the object to print
+    */
+
+   public void print(Object o) { out.print(o);  flush();}
+
+   /**
+    * Prints a long integer to a stream
+    * @param l the number to print
+    */
+
+   public void print(long l) { out.print(l); flush(); }
+
+   /**
+    * Prints a double precision floating point number to a stream
+    * @param l the number to print
+    */
+
+   public void print(double x) { out.print(x);  flush();}
+
+   /**
+    * Prints a string to a stream, followed by a newline
+    * @param s the string to print
+    */
+
+   public void println(String s) 
+   { 
+      out.println(s);
+          flush();
+   }
+
+   /**
+    * Prints a character to a stream, followed by a newline
+    * @param c the character to print
+    */
+
+   public void println(char c) { out.println(c); flush(); }
+
+   /**
+    * Prints an object to a stream, followed by a newline. The <tt>toString</tt> method of the object is invoked
+    * @param o the object to print
+    */
+
+   public void println(Object o) { out.println(o); flush(); }
+
+   /**
+    * Prints a long integer to a stream, followed by a newline
+    * @param l the number to print
+    */
+
+   public void println(long l) { out.println(l); flush(); }
+
+   /**
+    * Prints a double precision floating point number to a stream, followed by a newline
+    * @param l the number to print
+    */
+
+   public void println(double x) { out.println(x); flush(); }
+
+   /**
+    * Prints a newline
+    */
+
+   public void println() { out.println(); flush(); }
+
+   private void parseFormat(String s)
+   {  width = 0;
+      precision = -1;
+      pre = "";
+      post = "";
+      leading_zeroes = false;
+      show_plus = false;
+      alternate = false;
+      show_space = false;
+      left_align = false;
+      fmt = ' ';
+
+      int length = s.length();
+      int parse_state = 0;
+      // 0 = prefix, 1 = flags, 2 = width, 3 = precision,
+      // 4 = format, 5 = end
+      int i = 0;
+
+      while (parse_state == 0)
+      {  if (i >= length) parse_state = 5;
+         else if (s.charAt(i) == '%')
+         {  if (i < length - 1)
+            {  if (s.charAt(i + 1) == '%')
+               {  pre = pre + '%';
+                  i++;
+               }
+               else
+                  parse_state = 1;
+            }
+            else throw new java.lang.IllegalArgumentException();
+         }
+         else
+            pre = pre + s.charAt(i);
+         i++;
+      }
+      while (parse_state == 1)
+      {  if (i >= length) parse_state = 5;
+         else if (s.charAt(i) == ' ') show_space = true;
+         else if (s.charAt(i) == '-') left_align = true;
+         else if (s.charAt(i) == '+') show_plus = true;
+         else if (s.charAt(i) == '0') leading_zeroes = true;
+         else if (s.charAt(i) == '#') alternate = true;
+         else { parse_state = 2; i--; }
+         i++;
+      }
+      while (parse_state == 2)
+      {  if (i >= length) parse_state = 5;
+         else if ('0' <= s.charAt(i) && s.charAt(i) <= '9')
+         {  width = width * 10 + s.charAt(i) - '0';
+            i++;
+         }
+         else if (s.charAt(i) == '.')
+         {  parse_state = 3;
+            precision = 0;
+            i++;
+         }
+         else
+            parse_state = 4;
+      }
+      while (parse_state == 3)
+      {  if (i >= length) parse_state = 5;
+         else if ('0' <= s.charAt(i) && s.charAt(i) <= '9')
+         {  precision = precision * 10 + s.charAt(i) - '0';
+            i++;
+         }
+         else
+            parse_state = 4;
+      }
+      if (parse_state == 4)
+      {  if (i >= length) parse_state = 5;
+         else fmt = s.charAt(i);
+         i++;
+      }
+      if (i < length)
+         post = s.substring(i, length);
+   
+   
+   }
+
+   /**
+    * Prints a double precision floating point number to a stream, with formatting instructions
+    * @param fmt the formatting instruction string. 
+    * The string has a prefix, a format code and a suffix. The prefix and suffix
+    * become part of the formatted output. The format code directs the
+    * formatting of the parameter to be formatted. The code has the
+    * following structure
+    * <ul>
+    * <li> a % (required)
+    * <li> a modifier (optional)
+    * <dl>
+    * <dt> + <dd> forces display of + for positive numbers
+    * <dt> 0 <dd> show leading zeroes
+    * <dt> - <dd> align left in the field
+    * <dt> space <dd> prepend a space in front of positive numbers
+    * <dt> # <dd> use "alternate" format: Don't suppress trailing zeroes in general floating point format.
+    * </dl>
+    * <li> an integer denoting field width (optional)
+    * <li> a period followed by an integer denoting precision (optional)
+    * <li> a format descriptor (required)
+    * <dl>
+    * <dt>f <dd> floating point number in fixed format
+    * <dt>e, E <dd> floating point number in exponential notation (scientific format). The E format results in an uppercase E for the exponent (1.14130E+003), the e format in a lowercase e.
+    * <dt>g, G <dd> floating point number in general format (fixed format for small numbers, exponential format for large numbers). Trailing zeroes are suppressed. The G format results in an uppercase E for the exponent (if any), the g format in a lowercase e.
+    * </dl>
+    * </ul>
+    * @param l the number to print
+    */
+
+   public void printf(String fmt, double x)
+   {
+ 
+      parseFormat(fmt);
+      print(form(x));
+ 
+   }
+
+   /**
+    * Prints a long integer to a stream, with formatting instructions
+    * @param fmt the formatting instruction string. 
+    * The string has a prefix, a format code and a suffix. The prefix and suffix
+    * become part of the formatted output. The format code directs the
+    * formatting of the parameter to be formatted. The code has the
+    * following structure
+    * <ul>
+    * <li> a % (required)
+    * <li> a modifier (optional)
+    * <dl>
+    * <dt> + <dd> forces display of + for positive numbers
+    * <dt> 0 <dd> show leading zeroes
+    * <dt> - <dd> align left in the field
+    * <dt> space <dd> prepend a space in front of positive numbers
+    * <dt> # <dd> use "alternate" format: Add 0 or 0x for octal or hexadecimal numbers. 
+    * </dl>
+    * <li> an integer denoting field width (optional)
+    * <li> a format descriptor (required)
+    * <dl>
+    * <dt>d, i <dd> integer in decimal
+    * <dt>x <dd> integer in hexadecimal
+    * <dt>o <dd> integer in octal
+    * </dl>
+    * </ul>
+    * @param x the number to print
+    */
+
+   public void printf(String fmt, long x)
+   {  parseFormat(fmt);
+      print(form(x));
+   }
+
+   /**
+    * Prints a character to a stream, with formatting instructions
+    * @param fmt the formatting instruction string. 
+    * The string has a prefix, a format code and a suffix. The prefix and suffix
+    * become part of the formatted output. The format code directs the
+    * formatting of the parameter to be formatted. The code has the
+    * following structure
+    * <ul>
+    * <li> a % (required)
+    * <li> a modifier (optional)
+    * <dl>
+    * <dt> + <dd> forces display of + for positive numbers
+    * <dt> 0 <dd> show leading zeroes
+    * <dt> - <dd> align left in the field
+    * <dt> space <dd> prepend a space in front of positive numbers
+    * <dt> # <dd> use "alternate" format: Add 0 or 0x for octal or hexadecimal numbers. 
+    * </dl>
+    * <li> an integer denoting field width (optional)
+    * <li> a format descriptor (required)
+    * <dl>
+    * <dt>d, i <dd> integer in decimal
+    * <dt>x <dd> integer in hexadecimal
+    * <dt>o <dd> integer in octal
+    * <dt>c <dd> character
+    * </dl>
+    * </ul>
+    * @param x the character to print
+    */
+
+   public void printf(String fmt, char x)
+   {  parseFormat(fmt);
+      print(form(x));
+   }
+
+   /**
+    * Prints a string to a stream, with formatting instructions
+    * @param fmt the formatting instruction string. 
+    * The string has a prefix, a format code and a suffix. The prefix and suffix
+    * become part of the formatted output. The format code directs the
+    * formatting of the parameter to be formatted. The code has the
+    * following structure
+    * <ul>
+    * <li> a % (required)
+    * <li> a modifier (optional)
+    * <dl>
+    * <dt> - <dd> align left in the field
+    * </dl>
+    * <li> an integer denoting field width (optional)
+    * <li> a format descriptor (required)
+    * <dl>
+    * <dt>s <dd> string
+    * </dl>
+    * </ul>
+    * @param x the character to print
+    */
+
+   public void printf(String fmt, String x)
+   {  parseFormat(fmt);
+      print(form(x));
+   }
+
+   private static String repeat(char c, int n)
+   {  if (n <= 0) return "";
+      StringBuffer s = new StringBuffer(n);
+      for (int i = 0; i < n; i++) s.append(c);
+      return s.toString();
+   }
+
+   private static String convert(long x, int n, int m, String d)
+   {  if (x == 0) return "0";
+      String r = "";
+      while (x != 0)
+      {  r = d.charAt((int)(x & m)) + r;
+         x = x >>> n;
+      }
+      return r;
+   }
+
+   private String pad(String r)
+   {  String p = repeat(' ', width - r.length());
+      if (left_align) return pre + r + p + post;
+      else return pre + p + r + post;
+   }
+
+   private String sign(int s, String r)
+   {  String p = "";
+      if (s < 0) p = "-";
+      else if (s > 0)
+      {  if (show_plus) p = "+";
+         else if (show_space) p = " ";
+      }
+      else
+      {  if (fmt == 'o' && alternate && r.length() > 0 && r.charAt(0) != '0') p = "0";
+         else if (fmt == 'x' && alternate) p = "0x";
+         else if (fmt == 'X' && alternate) p = "0X";
+      }
+      int w = 0;
+      if (leading_zeroes)
+         w = width;
+      else if ((fmt == 'd' || fmt == 'i' || fmt == 'x' || fmt == 'X' || fmt == 'o')
+         && precision > 0) w = precision;
+
+      return p + repeat('0', w - p.length() - r.length()) + r;
+   }
+
+
+   private String fixed_format(double d)
+   {  String f = "";
+      if (d > 0x7FFFFFFFFFFFFFFFL) return exp_format(d);
+
+      long l = (long)(precision == 0 ? d + 0.5 : d);
+      f = f + l;
+
+      double fr = d - l; // fractional part
+      if (fr >= 1 || fr < 0) return exp_format(d);
+
+
+	/* DP change 210205 */
+	String fraction =  frac_part(fr);
+	if (fraction == "0")
+	{
+	int myInteger = (int) d + 1;
+	String trailing_zeroes = "";
+    for (int i = 1; i <= precision; i++)
+        trailing_zeroes = trailing_zeroes + "0";
+	// return "1." + trailing_zeroes; /* DP 150506 error here, it would print 12.99999 as 1.0!*/
+		return myInteger + "." + trailing_zeroes;
+	  }
+	else	
+    	return f + fraction;
+
+// return f + frac_part(fr);
+
+	/* DP */
+     	
+   }
+
+
+/* DP 210205 : there was a problem when the precision should round to 1.0. Instead it would print 0
+i.e.,	printf("%10.4f",0.99998) would print 0.0000
+*/
+
+   private String frac_part(double fr)
+   // precondition: 0 <= fr < 1
+   {  String z = "";
+      if (precision > 0)
+      {  double factor = 1;
+         String leading_zeroes = "";
+         for (int i = 1; i <= precision && factor <= 0x7FFFFFFFFFFFFFFFL; i++)
+         {  factor *= 10;
+            leading_zeroes = leading_zeroes + "0";
+         }
+  
+        long l = (long) (factor * fr + 0.5);
+    
+	/* DP 210205 added */
+		if (l == factor)
+			return "0";
+
+  	     z = leading_zeroes + l;
+         z = z.substring(z.length() - precision, z.length());
+
+      }
+
+      if (precision > 0 || alternate) z = "." + z;
+      
+      if ((fmt == 'G' || fmt == 'g') && !alternate)
+      // remove trailing zeroes and decimal point
+      {  int t = z.length() - 1;
+         while (t >= 0 && z.charAt(t) == '0') t--;
+         if (t >= 0 && z.charAt(t) == '.') t--;
+         z = z.substring(0, t + 1);
+      }
+      return z;
+   }
+
+   private String exp_format(double d)
+   {  String f = "";
+      int e = 0;
+      double dd = d;
+      double factor = 1;
+      if (d != 0)
+      {  while (dd > 10) { e++; factor /= 10; dd = dd / 10; }
+         while (dd < 1) { e--; factor *= 10; dd = dd * 10; }
+      }
+      if ((fmt == 'g' || fmt == 'G') && e >= -4 && e < precision)
+         return fixed_format(d);
+
+      d = d * factor;
+      f = f + fixed_format(d);
+
+      if (fmt == 'e' || fmt == 'g')
+         f = f + "e";
+      else
+         f = f + "E";
+
+      String p = "000";
+      if (e >= 0)
+      {  f = f + "+";
+         p = p + e;
+      }
+      else
+      {  f = f + "-";
+         p = p + (-e);
+      }
+
+      return f + p.substring(p.length() - 3, p.length());
+   }
+
+   private String form(double x)
+   {  String r;
+      if (precision < 0) precision = 6;
+      int s = 1;
+      if (x < 0) { x = -x; s = -1; }
+      if (fmt == 'f')
+         r = fixed_format(x);
+      else if (fmt == 'e' || fmt == 'E' || fmt == 'g' || fmt == 'G')
+         r = exp_format(x);
+      else throw new java.lang.IllegalArgumentException();
+
+      return pad(sign(s, r));
+   }
+
+   private String form(long x)
+   {  String r;
+      int s = 0;
+      if (fmt == 'd' || fmt == 'i')
+      {  if (x < 0) 
+         {  r = ("" + x).substring(1);
+            s = -1; 
+         }
+         else 
+         {  r = "" + x; 
+            s = 1;
+         }
+      }
+      else if (fmt == 'o')
+         r = convert(x, 3, 7, "01234567");
+      else if (fmt == 'x')
+         r = convert(x, 4, 15, "0123456789abcdef");
+      else if (fmt == 'X')
+         r = convert(x, 4, 15, "0123456789ABCDEF");
+      else throw new java.lang.IllegalArgumentException();
+
+      return pad(sign(s, r));
+   }
+
+   private String form(char c)
+   {  if (fmt != 'c')
+         throw new java.lang.IllegalArgumentException();
+
+      String r = "" + c;
+      return pad(r);
+   }
+
+   private String form(String s)
+   {  if (fmt != 's')
+         throw new java.lang.IllegalArgumentException();
+      if (precision >= 0) s = s.substring(0, precision);
+      return pad(s);
+   }
+
+   private PrintWriter out;
+
+   private int width;
+   private int precision;
+   private String pre;
+   private String post;
+   private boolean leading_zeroes;
+   private boolean show_plus;
+   private boolean alternate;
+   private boolean show_space;
+   private boolean left_align;
+   private char fmt; // one of cdeEfgGiosxXos
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/model/Model.java b/src/main/java/es/uvigo/darwin/jmodeltest/model/Model.java
new file mode 100644
index 0000000..2203404
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/model/Model.java
@@ -0,0 +1,625 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.model;
+
+import java.io.PushbackReader;
+import java.io.Serializable;
+import java.io.StringReader;
+
+import pal.tree.ReadTree;
+import pal.tree.Tree;
+import pal.tree.TreeParseException;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+
+public class Model implements Serializable {
+
+	private static final long serialVersionUID = 4173257281316945987L;
+
+	private String name, partition, treeString;
+	private Tree tree;
+
+	private int id;
+	private int K;
+	private int numTi;
+	private int numTv;
+	private int numGammaCat;
+
+	private boolean pF, pT, pR, pI, pG, pV;
+
+	private boolean isInAICinterval, isInAICcinterval, isInBICinterval,
+			isInDTinterval;
+
+	private double lnL;
+	/* Unconstrained LK */
+	private double unconstrainedLnL;
+	private double lnLIgnoringGaps;
+
+	/* statistical */
+	private double AIC, AICd, AICw, cumAICw, uAICd;
+	private double AICc, AICcd, AICcw, cumAICcw, uAICcd;
+	private double BIC, BICd, BICw, cumBICw, uBICd;
+	private double DT, DTd, DTw, cumDTw;
+
+	private double fA, fG, fC, fT, titv, kappa;
+	private double Ra, Rb, Rc, Rd, Re, Rf, pinv, shape;
+
+	private long computationTime;
+
+	public Model(int mid, String mname, String mpartition, int mparameters,
+			boolean mpF, boolean mpT, boolean mpV, boolean mpR, boolean mpI,
+			boolean mpG, int mTi, int mTv) {
+
+		id = mid;
+		name = mname;
+		partition = mpartition; // model substitution specification (e.g. GTR =
+								// 012345)
+		K = mparameters;
+		pF = mpF; // includes unequal base frequencies
+		pT = mpT; // includes ti/tv
+		pV = mpV; // only for phyml: includes a Ti/Tv, apart from R(x)
+		pR = mpR; // includes Rates R(x)
+		pI = mpI; // includes p-inv
+		pG = mpG; // includes gamma
+		numTi = mTi; // number of transition rates
+		numTv = mTv; // number of transversion rates
+
+		lnL = 0.0;
+		pinv = 0.0;
+		shape = ModelTest.INFINITY;
+	}
+
+	public Model(int mid, String mname, String mpartition, int mparameters) {
+
+		id = mid;
+		name = mname;
+		partition = mpartition; // model substitution specification (e.g. GTR =
+								// 012345)
+		K = mparameters;
+		pF = false; // includes unequal base frequencies
+		pT = false; // includes ti/tv
+		pV = false; // only for phyml: includes a Ti/Tv, apart from R(x)
+		pR = false; // includes Rates R(x)
+		pI = false; // includes p-inv
+		pG = false; // includes gamma
+		numTi = 0; // number of transition rates
+		numTv = 0; // number of transversion rates
+
+		lnL = 0.0;
+		pinv = 0.0;
+		shape = ModelTest.INFINITY;
+	}
+
+	/****************************
+	 * print ************************************ * Print model components * *
+	 ************************************************************************/
+
+	public void print(TextOutputStream stream) {
+
+		stream.println("   Model = " + getName());
+		stream.println("   partition = " + getPartition());
+
+		if (getLnL() == 0) {
+			stream.println(" OPTIMIZATION FAILED!");
+		} else {
+			stream.printf("   -lnL = %.4f", getLnL());
+			stream.printf("\n   K = %d", getK());
+			/*
+			 * stream.printf ("\n     optimized substitution parameters = %d",
+			 * Model.freeParameters[id]); if (ModelTest.countBLasParameters ==
+			 * true) stream.printf ("\n     optimized branch lengths = %d",
+			 * ModelTest.numBranches); if (ModelTest.optimizeMLTopology)
+			 * stream.printf ("\n     optimized topology = %d", 1);
+			 */
+			if (ispF()) {
+				stream.printf("\n   freqA = %5.4f ", getfA());
+				stream.printf("\n   freqC = %5.4f ", getfC());
+				stream.printf("\n   freqG = %5.4f ", getfG());
+				stream.printf("\n   freqT = %5.4f ", getfT());
+			}
+			if (ispT()) {
+				stream.printf("\n   kappa = %.4f", getKappa());
+				stream.printf(" (ti/tv = %.4f)", getTitv());
+			}
+			if (ispR()) {
+				stream.printf("\n   R(a) [AC] =  %.4f", getRa());
+				stream.printf("\n   R(b) [AG] =  %.4f", getRb());
+				stream.printf("\n   R(c) [AT] =  %.4f", getRc());
+				stream.printf("\n   R(d) [CG] =  %.4f", getRd());
+				stream.printf("\n   R(e) [CT] =  %.4f", getRe());
+				stream.printf("\n   R(f) [GT] =  %.4f", 1.0);
+			}
+			if (ispI())
+				stream.printf("\n   p-inv = %5.4f", getPinv());
+			if (ispG()) {
+				stream.printf("\n   gamma shape = %6.4f", getShape());
+			}
+			stream.println(" ");
+		}
+	}
+
+	public String printForTesting() {
+		StringBuilder str = new StringBuilder();
+		str.append(getName() + " ");
+		str.append(ispF() ? (getfA() + " " + getfC() + " " + getfG() + " "
+				+ getfT() + " ") : ("NA NA NA NA "));
+		str.append(ispT() ? (getKappa() + " " + getTitv() + " ") : ("NA NA "));
+
+		str.append(ispR() ? (getRa() + " " + getRb() + " " + getRc() + " "
+				+ getRd() + " " + getRe() + " " + getRf() + " ")
+				: ("NA NA NA NA NA NA "));
+		str.append(ispI() ? (getPinv() + " ") : ("NA "));
+		str.append(ispG() ? (getShape() + " ") : ("NA "));
+		str.append(getPartition());
+		return str.toString();
+	}
+
+	public void setCumBICw(double cumBICw) {
+		this.cumBICw = cumBICw;
+	}
+
+	public double getCumBICw() {
+		return cumBICw;
+	}
+
+	public void setLnL(double lnL) {
+		this.lnL = lnL;
+	}
+
+	public double getLnL() {
+		return lnL;
+	}
+
+	public void setLnLIgnoringGaps(double lnLIgnoringGaps) {
+		this.lnLIgnoringGaps = lnLIgnoringGaps;
+	}
+
+	public double getLnLIgnoringGaps() {
+		return lnLIgnoringGaps;
+	}
+
+	public double getUnconstrainedLnL() {
+		return unconstrainedLnL;
+	}
+
+	public void setUnconstrainedLnL(double unconstrainedLnL) {
+		this.unconstrainedLnL = unconstrainedLnL;
+	}
+
+	public void setAIC(double aIC) {
+		AIC = aIC;
+	}
+
+	public double getAIC() {
+		return AIC;
+	}
+
+	public void setAICd(double aICd) {
+		AICd = aICd;
+	}
+
+	public double getAICd() {
+		return AICd;
+	}
+
+	public void setAICw(double aICw) {
+		AICw = aICw;
+	}
+
+	public double getAICw() {
+		return AICw;
+	}
+
+	public void setUAICd(double uAICd) {
+		this.uAICd = uAICd;
+	}
+
+	public double getUAICd() {
+		return uAICd;
+	}
+
+	public void setCumAICw(double cumAICw) {
+		this.cumAICw = cumAICw;
+	}
+
+	public double getCumAICw() {
+		return cumAICw;
+	}
+
+	public void setAICc(double aICc) {
+		AICc = aICc;
+	}
+
+	public double getAICc() {
+		return AICc;
+	}
+
+	public void setAICcd(double aICcd) {
+		AICcd = aICcd;
+	}
+
+	public double getAICcd() {
+		return AICcd;
+	}
+
+	public void setAICcw(double aICcw) {
+		AICcw = aICcw;
+	}
+
+	public double getAICcw() {
+		return AICcw;
+	}
+
+	public void setCumAICcw(double cumAICcw) {
+		this.cumAICcw = cumAICcw;
+	}
+
+	public void setUAICcd(double uAICcd) {
+		this.uAICcd = uAICcd;
+	}
+
+	public double getUAICcd() {
+		return uAICcd;
+	}
+
+	public double getCumAICcw() {
+		return cumAICcw;
+	}
+
+	public void setBICd(double bICd) {
+		BICd = bICd;
+	}
+
+	public double getBICd() {
+		return BICd;
+	}
+
+	public void setBIC(double bIC) {
+		BIC = bIC;
+	}
+
+	public double getBIC() {
+		return BIC;
+	}
+
+	public void setBICw(double bICw) {
+		BICw = bICw;
+	}
+
+	public double getBICw() {
+		return BICw;
+	}
+
+	public void setUBICd(double uBICd) {
+		this.uBICd = uBICd;
+	}
+
+	public double getUBICd() {
+		return uBICd;
+	}
+
+	public void setDT(double dT) {
+		DT = dT;
+	}
+
+	public double getDT() {
+		return DT;
+	}
+
+	public void setCumDTw(double cumDTw) {
+		this.cumDTw = cumDTw;
+	}
+
+	public double getCumDTw() {
+		return cumDTw;
+	}
+
+	public void setDTw(double dTw) {
+		DTw = dTw;
+	}
+
+	public double getDTw() {
+		return DTw;
+	}
+
+	public void setDTd(double dTd) {
+		DTd = dTd;
+	}
+
+	public double getDTd() {
+		return DTd;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setPartition(String partition) {
+		this.partition = partition;
+	}
+
+	public String getPartition() {
+		return partition;
+	}
+
+	public Tree getTree() {
+		return tree;
+	}
+
+	public void setTreeString(String tree) throws TreeParseException {
+		this.treeString = tree;
+
+		if (tree == null)
+			throw new TreeParseException("Attempting to set a null tree");
+		StringReader sr = new StringReader(tree);
+		this.tree = new ReadTree(new PushbackReader(sr));
+	}
+
+	public String getTreeString() {
+		return treeString;
+	}
+
+	public void setfG(double fG) {
+		this.fG = fG;
+	}
+
+	public double getfG() {
+		return fG;
+	}
+
+	public void setfA(double fA) {
+		this.fA = fA;
+	}
+
+	public double getfA() {
+		return fA;
+	}
+
+	public void setfC(double fC) {
+		this.fC = fC;
+	}
+
+	public double getfC() {
+		return fC;
+	}
+
+	public void setfT(double fT) {
+		this.fT = fT;
+	}
+
+	public double getfT() {
+		return fT;
+	}
+
+	public void setTitv(double titv) {
+		this.titv = titv;
+	}
+
+	public double getTitv() {
+		return titv;
+	}
+
+	public void setKappa(double kappa) {
+		this.kappa = kappa;
+	}
+
+	public double getKappa() {
+		return kappa;
+	}
+
+	public void setRa(double ra) {
+		Ra = ra;
+	}
+
+	public double getRa() {
+		return Ra;
+	}
+
+	public void setShape(double shape) {
+		this.shape = shape;
+	}
+
+	public double getShape() {
+		return shape;
+	}
+
+	public void setPinv(double pinv) {
+		this.pinv = pinv;
+	}
+
+	public double getPinv() {
+		return pinv;
+	}
+
+	public void setRf(double rf) {
+		Rf = rf;
+	}
+
+	public double getRf() {
+		return Rf;
+	}
+
+	public void setRe(double re) {
+		Re = re;
+	}
+
+	public double getRe() {
+		return Re;
+	}
+
+	public void setRd(double rd) {
+		Rd = rd;
+	}
+
+	public double getRd() {
+		return Rd;
+	}
+
+	public void setRc(double rc) {
+		Rc = rc;
+	}
+
+	public double getRc() {
+		return Rc;
+	}
+
+	public void setRb(double rb) {
+		Rb = rb;
+	}
+
+	public double getRb() {
+		return Rb;
+	}
+
+	public int getId() {
+		return id;
+	}
+
+	public void setNumGammaCat(int numGammaCat) {
+		this.numGammaCat = numGammaCat;
+	}
+
+	public int getNumGammaCat() {
+		return numGammaCat;
+	}
+
+	public int getK() {
+		return K;
+	}
+
+	public int getNumTi() {
+		return numTi;
+	}
+
+	public boolean ispV() {
+		return pV;
+	}
+
+	public boolean ispG() {
+		return pG;
+	}
+
+	public boolean ispI() {
+		return pI;
+	}
+
+	public boolean ispR() {
+		return pR;
+	}
+
+	public boolean ispT() {
+		return pT;
+	}
+
+	public boolean ispF() {
+		return pF;
+	}
+
+	public void setInDTinterval(boolean isInDTinterval) {
+		this.isInDTinterval = isInDTinterval;
+	}
+
+	public boolean isInDTinterval() {
+		return isInDTinterval;
+	}
+
+	public void setInBICinterval(boolean isInBICinterval) {
+		this.isInBICinterval = isInBICinterval;
+	}
+
+	public boolean isInBICinterval() {
+		return isInBICinterval;
+	}
+
+	public void setInAICcinterval(boolean isInAICcinterval) {
+		this.isInAICcinterval = isInAICcinterval;
+	}
+
+	public boolean isInAICcinterval() {
+		return isInAICcinterval;
+	}
+
+	public void setInAICinterval(boolean isInAICinterval) {
+		this.isInAICinterval = isInAICinterval;
+	}
+
+	public boolean isInAICinterval() {
+		return isInAICinterval;
+	}
+
+	public int getNumTv() {
+		return numTv;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + (pF ? 1231 : 1237);
+		result = prime * result + (pG ? 1231 : 1237);
+		result = prime * result + (pI ? 1231 : 1237);
+		result = prime * result
+				+ ((partition == null) ? 0 : partition.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		Model other = (Model) obj;
+		if (pF != other.pF)
+			return false;
+		if (pG != other.pG)
+			return false;
+		if (pI != other.pI)
+			return false;
+		if (partition == null) {
+			if (other.partition != null)
+				return false;
+		} else if (!partition.equals(other.partition))
+			return false;
+		return true;
+	}
+
+	public long getComputationTime() {
+		return computationTime;
+	}
+
+	public void setComputationTime(long computationTime) {
+		this.computationTime = computationTime;
+	}
+
+	public void update(Model model) {
+		if (this.equals(model)) {
+			lnL = model.lnL;
+			numGammaCat = model.numGammaCat;
+			shape = model.shape;
+			pinv = model.pinv;
+			kappa = model.kappa;
+			treeString = model.treeString;
+			tree = model.tree;
+			computationTime = model.computationTime;
+		}
+	}
+} // class Model
+
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/model/ModelComparator.java b/src/main/java/es/uvigo/darwin/jmodeltest/model/ModelComparator.java
new file mode 100644
index 0000000..88cf62c
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/model/ModelComparator.java
@@ -0,0 +1,46 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.model;
+
+import java.util.Comparator;
+
+public class ModelComparator implements Comparator<Model> {
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+	 */
+	public int compare(Model model1, Model model2) {
+		int value = 0;
+		if (model1 != null && model2 != null)
+			value = getWeight(model2) - getWeight(model1);
+		return value;
+	}
+
+	private int getWeight(Model model) {
+		int weight = 0;
+		if (model.ispG())
+			weight += 4;
+		if (model.ispI())
+			weight += 2;
+		if (model.ispF())
+			weight += 1;
+		return weight;
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/model/ModelConstants.java b/src/main/java/es/uvigo/darwin/jmodeltest/model/ModelConstants.java
new file mode 100644
index 0000000..f777856
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/model/ModelConstants.java
@@ -0,0 +1,297 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.model;
+
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.List;
+
+public abstract class ModelConstants {
+	// Model names
+	public static final String[] modelName = { "JC", "JC+I", "JC+G", "JC+I+G",
+			"F81", "F81+I", "F81+G", "F81+I+G", "K80", "K80+I", "K80+G",
+			"K80+I+G", "HKY", "HKY+I", "HKY+G", "HKY+I+G", "TrNef", "TrNef+I",
+			"TrNef+G", "TrNef+I+G", "TrN", "TrN+I", "TrN+G", "TrN+I+G", "TPM1",
+			"TPM1+I", "TPM1+G", "TPM1+I+G", "TPM1uf", "TPM1uf+I", "TPM1uf+G",
+			"TPM1uf+I+G", "TPM2", "TPM2+I", "TPM2+G", "TPM2+I+G", "TPM2uf",
+			"TPM2uf+I", "TPM2uf+G", "TPM2uf+I+G", "TPM3", "TPM3+I", "TPM3+G",
+			"TPM3+I+G", "TPM3uf", "TPM3uf+I", "TPM3uf+G", "TPM3uf+I+G",
+			"TIM1ef", "TIM1ef+I", "TIM1ef+G", "TIM1ef+I+G", "TIM1", "TIM1+I",
+			"TIM1+G", "TIM1+I+G", "TIM2ef", "TIM2ef+I", "TIM2ef+G",
+			"TIM2ef+I+G", "TIM2", "TIM2+I", "TIM2+G", "TIM2+I+G", "TIM3ef",
+			"TIM3ef+I", "TIM3ef+G", "TIM3ef+I+G", "TIM3", "TIM3+I", "TIM3+G",
+			"TIM3+I+G", "TVMef", "TVMef+I", "TVMef+G", "TVMef+I+G", "TVM",
+			"TVM+I", "TVM+G", "TVM+I+G", "SYM", "SYM+I", "SYM+G", "SYM+I+G",
+			"GTR", "GTR+I", "GTR+G", "GTR+I+G" };
+
+	// custom String for substitution types
+	public static final String[] modelCode = { "000000", "000000", "000000",
+			"000000", // JC
+			"000000", "000000", "000000", "000000", // F81
+			"010010", "010010", "010010", "010010", // K80
+			"010010", "010010", "010010", "010010", // HKY
+			"010020", "010020", "010020", "010020", // TrNef
+			"010020", "010020", "010020", "010020", // TrN
+			"012210", "012210", "012210", "012210", // TPM1=K81
+			"012210", "012210", "012210", "012210", // TPM1uf=K81uf
+			"010212", "010212", "010212", "010212", // TPM2
+			"010212", "010212", "010212", "010212", // TPM2uf
+			"012012", "012012", "012012", "012012", // TPM3
+			"012012", "012012", "012012", "012012", // TPM3uf
+			"012230", "012230", "012230", "012230", // TIM1ef
+			"012230", "012230", "012230", "012230", // TIM1
+			"010232", "010232", "010232", "010232", // TIM2ef
+			"010232", "010232", "010232", "010232", // TIM2
+			"012032", "012032", "012032", "012032", // TIM3ef
+			"012032", "012032", "012032", "012032", // TIM3
+			"012314", "012314", "012314", "012314", // TVMef
+			"012314", "012314", "012314", "012314", // TVM
+			"012345", "012345", "012345", "012345", // SYM
+			"012345", "012345", "012345", "012345", // GTR
+	};
+	public static final List<String> codeList = Arrays
+			.asList(ModelConstants.modelCode);
+
+	// custom String for substitution types
+	public static final Hashtable<Integer, String[]> fullModelSet;
+
+	static {
+		fullModelSet = new Hashtable<Integer, String[]>();
+		fullModelSet.put(6, new String[] { "012345" });
+		fullModelSet.put(5, new String[] { "001234", "010234", "011234",
+				"012034", "012134", "012234", "012304", "012314", "012324",
+				"012334", "012340", "012341", "012342", "012343", "012344" });
+		fullModelSet.put(4, new String[] { "000123", "001023", "001123",
+				"001203", "001213", "001223", "001230", "001231", "001232",
+				"001233", "010023", "010123", "010203", "010213", "010223",
+				"010230", "010231", "010232", "010233", "011023", "011123",
+				"011203", "011213", "011223", "011230", "011231", "011232",
+				"011233", "012003", "012013", "012023", "012030", "012031",
+				"012032", "012033", "012103", "012113", "012123", "012130",
+				"012131", "012132", "012133", "012203", "012213", "012223",
+				"012230", "012231", "012232", "012233", "012300", "012301",
+				"012302", "012303", "012310", "012311", "012312", "012313",
+				"012320", "012321", "012322", "012323", "012330", "012331",
+				"012332", "012333" });
+		fullModelSet.put(3, new String[] { "000012", "000102", "000112",
+				"000120", "000121", "000122", "001002", "001012", "001020",
+				"001021", "001022", "001102", "001112", "001120", "001121",
+				"001122", "001200", "001201", "001202", "001210", "001211",
+				"001212", "001220", "001221", "001222", "010002", "010012",
+				"010020", "010021", "010022", "010102", "010112", "010120",
+				"010121", "010122", "010200", "010201", "010202", "010210",
+				"010211", "010212", "010220", "010221", "010222", "011002",
+				"011012", "011020", "011021", "011022", "011102", "011112",
+				"011120", "011121", "011122", "011200", "011201", "011202",
+				"011210", "011211", "011212", "011220", "011221", "011222",
+				"012000", "012001", "012002", "012010", "012011", "012012",
+				"012020", "012021", "012022", "012100", "012101", "012102",
+				"012110", "012111", "012112", "012120", "012121", "012122",
+				"012200", "012201", "012202", "012210", "012211", "012212",
+				"012220", "012221", "012222" });
+		fullModelSet.put(2, new String[] { "000001", "000010", "000011",
+				"000100", "000101", "000110", "000111", "001000", "001001",
+				"001010", "001011", "001100", "001101", "001110", "001111",
+				"010000", "010001", "010010", "010011", "010100", "010101",
+				"010110", "010111", "011000", "011001", "011010", "011011",
+				"011100", "011101", "011110", "011111" });
+		fullModelSet.put(1, new String[] { "000000" });
+	}
+
+	// number of free parameters for each model
+	public static final int[] freeParameters = { 0, 1, 1, 2, // JC
+			3, 4, 4, 5, // F81
+			1, 2, 2, 3, // K80
+			4, 5, 5, 6, // HKY
+			2, 3, 3, 4, // TrNef
+			5, 6, 6, 7, // TrN
+			2, 3, 3, 4, // TPM1=K81
+			5, 6, 6, 7, // TPM1uf=K81uf
+			2, 3, 3, 4, // TPM2
+			5, 6, 6, 7, // TPM2uf
+			2, 3, 3, 4, // TPM3
+			5, 6, 6, 7, // TPM3uf
+			3, 4, 4, 5, // TIM1ef
+			6, 7, 7, 8, // TIM1
+			3, 4, 4, 5, // TIM2ef
+			6, 7, 7, 8, // TIM2
+			3, 4, 4, 5, // TIM3ef
+			6, 7, 7, 8, // TIM3
+			4, 5, 5, 6, // TVMef
+			7, 8, 8, 9, // TVM
+			5, 6, 6, 7, // SYM
+			8, 9, 9, 10 // GTR
+	};
+
+	// different types of transition rates
+	public static final int[] numTransitions = { 0, 0, 0, 0, // JC
+			0, 0, 0, 0, // F81
+			1, 1, 1, 1, // K80
+			1, 1, 1, 1, // HKY
+			2, 2, 2, 2, // TrNef
+			2, 2, 2, 2, // TrN
+			1, 1, 1, 1, // TPM1=K81
+			1, 1, 1, 1, // TPM1uf=K81uf
+			1, 1, 1, 1, // TPM2
+			1, 1, 1, 1, // TPM2uf
+			1, 1, 1, 1, // TPM3
+			1, 1, 1, 1, // TPM3uf
+			2, 2, 2, 2, // TIM1ef
+			2, 2, 2, 2, // TIM1
+			2, 2, 2, 2, // TIM2ef
+			2, 2, 2, 2, // TIM2
+			2, 2, 2, 2, // TIM3ef
+			2, 2, 2, 2, // TIM3
+			1, 1, 1, 1, // TVMef
+			1, 1, 1, 1, // TVM
+			2, 2, 2, 2, // SYM
+			2, 2, 2, 2 // GTR
+	};
+
+	// different types of transversion rates
+	public static final int[] numTransversions = { 0, 0, 0, 0, // JC
+			0, 0, 0, 0, // F81
+			1, 1, 1, 1, // K80
+			1, 1, 1, 1, // HKY
+			1, 1, 1, 1, // TrNef
+			1, 1, 1, 1, // TrN
+			2, 2, 2, 2, // TPM1=K81
+			2, 2, 2, 2, // TPM1uf=K81uf
+			2, 2, 2, 2, // TPM2
+			2, 2, 2, 2, // TPM2uf
+			2, 2, 2, 2, // TPM3
+			2, 2, 2, 2, // TPM3uf
+			2, 2, 2, 2, // TIM1ef
+			2, 2, 2, 2, // TIM1
+			2, 2, 2, 2, // TIM2ef
+			2, 2, 2, 2, // TIM2
+			2, 2, 2, 2, // TIM3ef
+			2, 2, 2, 2, // TIM3
+			4, 4, 4, 4, // TVMef
+			4, 4, 4, 4, // TVM
+			4, 4, 4, 4, // SYM
+			4, 4, 4, 4 // GTR
+	};
+
+//	public static final int getNumberOfTransitions(String partition) {
+//		System.out.println(" CHECKING " + partition);
+//		Integer ti0 = Integer.parseInt(partition.substring(1, 2));
+//		Integer ti1 = Integer.parseInt(partition.substring(4, 5));
+//		System.out.println(" CHECKING " + ti0 + " and " +  ti1);
+//		if (ti0 == ti1) {
+//			return 1;
+//		} else {
+//			return 2;
+//		}
+//	}
+//
+//	public static final int getNumberOfTransversions(String partition) {
+//		List<Integer> parts = new ArrayList<Integer>();
+//		int[] transitions = { 0, 2, 3, 5 };
+//		for (int i : transitions) {
+//			Integer current_part = Integer.parseInt(partition.substring(i, i+1));
+//			if (!parts.contains(current_part)) {
+//				parts.add(current_part);
+//			}
+//		}
+//		return parts.size();
+//	}
+
+	// base frequencies restrictions
+	public static final boolean[] equalBaseFrequencies = { true, true, true,
+			true, // JC
+			false, false, false, false, // F81
+			true, true, true, true, // K81
+			false, false, false, false, // HKY
+			true, true, true, true, // TrNef
+			false, false, false, false, // TrN
+			true, true, true, true, // TPM1=K81
+			false, false, false, false, // TPM1uf=K81uf
+			true, true, true, true, // TPM2
+			false, false, false, false, // TPM2uf
+			true, true, true, true, // TPM3
+			false, false, false, false, // TPM3uf
+			true, true, true, true, // TIM1ef
+			false, false, false, false, // TIM1
+			true, true, true, true, // TIM2ef
+			false, false, false, false, // TIM2
+			true, true, true, true, // TIM3ef
+			false, false, false, false, // TIM3
+			true, true, true, true, // TVMef
+			false, false, false, false, // TVM
+			true, true, true, true, // SYM
+			false, false, false, false // GTR
+	};
+
+	// base frequencies restrictions (0=none 1=+I 2=+G 3=+I+G)
+	public static final int[] rateVariation = { 0, 1, 2, 3, // JC
+			0, 1, 2, 3, // F81
+			0, 1, 2, 3, // K80
+			0, 1, 2, 3, // HKY
+			0, 1, 2, 3, // TrNef
+			0, 1, 2, 3, // TrN
+			0, 1, 2, 3, // TPM1=K81
+			0, 1, 2, 3, // TPM1uf=K81uf
+			0, 1, 2, 3, // TPM2
+			0, 1, 2, 3, // TPM2uf
+			0, 1, 2, 3, // TPM3
+			0, 1, 2, 3, // TPM3uf
+			0, 1, 2, 3, // TIM1ef
+			0, 1, 2, 3, // TIM1
+			0, 1, 2, 3, // TIM2ef
+			0, 1, 2, 3, // TIM2
+			0, 1, 2, 3, // TIM3ef
+			0, 1, 2, 3, // TIM3
+			0, 1, 2, 3, // TVMef
+			0, 1, 2, 3, // TVM
+			0, 1, 2, 3, // SYM
+			0, 1, 2, 3 // GTR
+	};
+
+	// 0 = part of the 3 substitution schemes = standard 24-model set (ModelTest
+	// 1.0)
+	// 1 = part of the 5 substitution schemes = standard 40-model set (ModelTest
+	// 2.0)
+	// 2 = part of the 7 substitution schemes = standard 56-model set (ModelTest
+	// 3.0)
+	// 3 = part of the 11 substitution schemes = standard 88-model set
+	// (jModeltest)
+	public static final int[] substType = { 0, 0, 0, 0, // JC
+			0, 0, 0, 0, // F81
+			0, 0, 0, 0, // K80
+			0, 0, 0, 0, // HKY
+			1, 1, 1, 1, // TrNef
+			1, 1, 1, 1, // TrN
+			1, 1, 1, 1, // TPM1=K81
+			1, 1, 1, 1, // TPM1uf=K81uf
+			3, 3, 3, 3, // TPM2
+			3, 3, 3, 3, // TPM2uf
+			3, 3, 3, 3, // TPM3
+			3, 3, 3, 3, // TPM3uf
+			2, 2, 2, 2, // TIM1ef
+			2, 2, 2, 2, // TIM1
+			3, 3, 3, 3, // TIM2ef
+			3, 3, 3, 3, // TIM2
+			3, 3, 3, 3, // TIM3ef
+			3, 3, 3, 3, // TIM3
+			2, 2, 2, 2, // TVMef
+			2, 2, 2, 2, // TVM
+			0, 0, 0, 0, // SYM
+			0, 0, 0, 0 // GTR
+	};
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/observer/ConsoleProgressObserver.java b/src/main/java/es/uvigo/darwin/jmodeltest/observer/ConsoleProgressObserver.java
new file mode 100644
index 0000000..6cf4e37
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/observer/ConsoleProgressObserver.java
@@ -0,0 +1,209 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.observer;
+
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.util.Locale;
+import java.util.Observable;
+import java.util.Observer;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.ModelTestConfiguration;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class ConsoleProgressObserver implements Observer {
+
+	private TextOutputStream stream;
+	/** Timer for calculate the elapsed time **/
+	private long startTime;
+	private int totalModels;
+	private int completedModels = 0;
+	private boolean threadScheduling;
+	private ApplicationOptions options;
+
+	public ConsoleProgressObserver(ApplicationOptions options) {
+		this.startTime = System.currentTimeMillis();
+		this.stream = ModelTest.getMainConsole();
+		this.threadScheduling = options.threadScheduling;
+		this.options=options;
+	}
+
+	@Override
+	@SuppressWarnings("fallthrough")
+	public synchronized void update(Observable o, Object arg) {
+
+		if (arg != null) {
+			ProgressInfo info = (ProgressInfo) arg;
+
+			switch (info.getType()) {
+
+			case ProgressInfo.BASE_TREE_INIT:
+				stream.println(" ");
+				stream.println("Estimating a BIONJ-JC tree ... ");
+				break;
+
+			case ProgressInfo.BASE_TREE_COMPUTED:
+				stream.println("OK");
+				stream.println(info.getModel().getName() + " tree: "
+						+ info.getModel().getTreeString());
+				break;
+
+			case ProgressInfo.OPTIMIZATION_INIT:
+				this.totalModels = options.getNumModels();
+				stream.println(" ");stream.println(" ");
+				stream.println("::Progress::");
+				stream.println(" ");
+				stream.println("Model \t\t Exec. Time \t Total Time \t -lnL");
+				stream.println("-------------------------------------------------------------------------");
+				break;
+			
+			case ProgressInfo.GTR_OPTIMIZATION_INIT:
+				stream.println("[Heuristic search] Optimizing " + info.getModel().getName() + " model");
+				break;
+				
+			case ProgressInfo.GTR_OPTIMIZATION_COMPLETED:
+				stream.println("[Heuristic search] Starting model filtering");
+				break;
+				
+			case ProgressInfo.SINGLE_OPTIMIZATION_INIT:
+				break;
+
+			case ProgressInfo.SINGLE_OPTIMIZATION_COMPLETED:
+				completedModels++;
+				stream.print(info.getModel().getName() + "\t");
+				double modelLnL;
+				if (info.getValue() == ProgressInfo.VALUE_REGULAR_OPTIMIZATION) {
+					modelLnL = info.getModel().getLnL(); 
+				} else {
+					modelLnL = info.getModel().getLnLIgnoringGaps();
+				}
+				if (info.getModel().getName().length()<8)
+					stream.print("\t");
+				stream.print(info.getMessage() + "\t" 
+						+ Utilities.calculateRuntime(startTime, System.currentTimeMillis()) + "\t" 
+						+ String.format(Locale.ENGLISH, "%13.4f", modelLnL));
+				if (ModelTest.MPJ_RUN && threadScheduling) {
+					stream.println(" ");
+				} else {
+					if (info.isHeuristicSearch() && info.getValue() == ProgressInfo.VALUE_REGULAR_OPTIMIZATION) {
+						stream.println("\t ["+info.getHeuristicStage()+"/6] (" + completedModels + "/" + info.getNumModelsInStage() + ")");
+						if (completedModels == info.getNumModelsInStage()) {
+							completedModels = 0;
+						}
+					} else {
+						stream.println("\t (" + completedModels + "/" + totalModels + ")");
+					}
+				}
+				
+				if (ModelTestConfiguration.isCkpEnabled()) {
+					try {
+						OutputStream file = new FileOutputStream(
+								options.getCkpFile());
+						OutputStream buffer = new BufferedOutputStream(file);
+						ObjectOutput output = new ObjectOutputStream(buffer);
+						output.writeObject(ModelTest.getCandidateModels());
+						output.close();
+					} catch (IOException ex) {
+						System.err.println("Cannot perform output.");
+					}
+				}
+				
+				break;
+				
+			case ProgressInfo.REOPTIMIZATION_INIT:
+				this.totalModels = info.getValue();
+				this.completedModels = 0;
+				this.startTime = System.currentTimeMillis();
+				stream.println(" ");stream.println(" ");
+				stream.println("Some models should be reoptimized for checking lnL against the unconstrained likelihood");
+				stream.println(" ");
+				stream.println("Model \t\t Exec. Time \t Total Time\t-lnL w/o gaps");
+				stream.println("-------------------------------------------------------------------------");
+				break;
+				
+			case ProgressInfo.REOPTIMIZATION_COMPLETED:
+
+				stream.println(" ");
+
+				stream.println("  Unconstrained -lnL       = " + options.getUnconstrainedLnL());
+				stream.println("  Number of patterns found = " + options.getNumPatterns());
+
+				stream.println(" ");
+				break;
+				
+			case ProgressInfo.INTERRUPTED:
+				stream.println(" ");
+				stream.println("Computation of likelihood scores discontinued ...");
+				break;
+
+			case ProgressInfo.ERROR:
+				stream.println(info.getMessage());
+				stream.println(" ");
+				stream.println("Computation of likelihood scores discontinued ...");
+				System.exit(-1);
+				break;
+			case ProgressInfo.ERROR_BINARY_NOEXISTS:
+				stream.println("");
+				stream.println("ERROR: PhyML binary does not exists: " + info.getMessage());
+				stream.println("");
+				ModelTest.finalize(ProgressInfo.ERROR_BINARY_NOEXISTS);
+				break;
+			case ProgressInfo.ERROR_BINARY_NOEXECUTE:
+				stream.println("");
+				stream.println("ERROR: PhyML binary does not have execution permission: " + info.getMessage());
+				stream.println("");
+				ModelTest.finalize(ProgressInfo.ERROR_BINARY_NOEXECUTE);
+				break;
+			case ProgressInfo.OPTIMIZATION_COMPLETED_OK:
+
+				stream.println(" ");
+				for (Model model : ModelTest.getCandidateModels()) {
+					model.print(ModelTest.getMainConsole());
+					ModelTest.getMainConsole().println(" ");
+				}
+
+				if (options.isAmbiguous()) {
+				stream.println("  Best-fit models should be reoptimized for comparison with unconstrained likelihood");
+				} else {
+					stream.println("  Unconstrained -lnL       = " + options.getUnconstrainedLnL());
+					stream.println("  Number of patterns found = " + options.getNumPatterns());
+				}
+				stream.println(" ");
+				stream.println("Computation of likelihood scores completed. It took "
+						+ Utilities.calculateRuntime(startTime,
+								System.currentTimeMillis()) + ".");
+				stream.println(" ");
+				// continue
+
+			case ProgressInfo.OPTIMIZATION_COMPLETED_INTERRUPTED:
+				// dispose
+				break;
+			}
+		}
+
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/observer/ProgressInfo.java b/src/main/java/es/uvigo/darwin/jmodeltest/observer/ProgressInfo.java
new file mode 100644
index 0000000..1c8a41a
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/observer/ProgressInfo.java
@@ -0,0 +1,97 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.observer;
+
+import es.uvigo.darwin.jmodeltest.model.Model;
+
+public class ProgressInfo {
+
+	public static final int NA = 0;
+	public static final int BASE_TREE_INIT = 1;
+	public static final int BASE_TREE_COMPUTED = 2;
+	public static final int OPTIMIZATION_INIT = 3;
+	public static final int SINGLE_OPTIMIZATION_INIT = 4;
+	public static final int SINGLE_OPTIMIZATION_COMPLETED = 5;
+	public static final int OPTIMIZATION_COMPLETED_OK = 6;
+	public static final int OPTIMIZATION_COMPLETED_INTERRUPTED = 7;
+	public static final int REOPTIMIZATION_INIT = 8;
+	public static final int REOPTIMIZATION_COMPLETED = 9;
+	public static final int GTR_OPTIMIZATION_INIT = 10;
+	public static final int GTR_OPTIMIZATION_COMPLETED = 11;
+	public static final int GTR_NOT_FOUND = 12;
+	public static final int INTERRUPTED = 20;
+	public static final int ERROR = 21;
+	public static final int ERROR_BINARY_NOEXISTS = 22;
+	public static final int ERROR_BINARY_NOEXECUTE = 23;
+	
+	public static final int VALUE_REGULAR_OPTIMIZATION = 1;
+	public static final int VALUE_IGAPS_OPTIMIZATION = 2;
+	
+	
+	private int type;
+	private Model model;
+	private int value;
+	private String message;
+	private boolean doHeuristicSearch = false;
+	private int heuristicStage;
+	private int numModelsInStage;
+	
+	public ProgressInfo(int type, int value, Model model, String message) {
+		this.type = type;
+		this.model = model;
+		this.value = value;
+		this.message = message;
+	}
+
+	public int getType() {
+		return type;
+	}
+	
+	public Model getModel() {
+		return model;
+	}
+
+	public int getValue() {
+		return value;
+	}
+	
+	public String getMessage() {
+		return message;
+	}
+	
+	public boolean isHeuristicSearch() {
+		return doHeuristicSearch;
+	}
+	
+	public int getNumModelsInStage() {
+		return numModelsInStage;
+	}
+	
+	public void setNumModelsInStage(int numModelsInStage) {
+		this.numModelsInStage = numModelsInStage;
+	}
+	
+	public int getHeuristicStage() {
+		return heuristicStage;
+	}
+	
+	public void setHeuristicStage(int heuristicStage) {
+		this.heuristicStage = heuristicStage;
+		this.doHeuristicSearch = (heuristicStage > 0);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/selection/AIC.java b/src/main/java/es/uvigo/darwin/jmodeltest/selection/AIC.java
new file mode 100644
index 0000000..279554b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/selection/AIC.java
@@ -0,0 +1,276 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.selection;
+
+import java.util.Random;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+
+public class AIC extends InformationCriterion {
+
+	// constructor
+	public AIC(boolean mwritePAUPblock, boolean mdoImportances,
+			boolean mdoModelAveraging, double minterval) {
+		super(mwritePAUPblock, mdoImportances, mdoModelAveraging, minterval);
+	}
+
+	/****************************
+	 * compute ********************************** * Computes the Akaike
+	 * Information Criterion (AIC) for every model * and finds out the model
+	 * with the minimum AIC * *
+	 ************************************************************************/
+
+	public void compute() {
+
+		boolean sorted;
+		int i, temp2, pass;
+		double[] tempw = new double[numModels];
+		double min, sumExp, cum, temp1;
+
+		// Calculate AIC and minAIC
+		min = computeAic(models[0], options);
+
+		minModel = models[0];
+
+		if (doCheckAgainstULK) {
+			unconstrainedModel.setAIC(computeSingle(unconstrainedModel));
+		}
+		for (Model model : models) {
+			model.setAIC(computeAic(model, options));
+
+			if (model.getAIC() < min) {
+				min = model.getAIC();
+				minModel = model;
+			}
+			
+			if (doCheckAgainstULK) {
+				model.setUAICd(model.getAIC() - unconstrainedModel.getAIC());
+			}
+		}
+
+		// Calculate Akaike differences
+		sumExp = 0;
+		for (Model model : models) {
+			model.setAICd(model.getAIC() - minModel.getAIC());
+			sumExp += Math.exp(-0.5 * model.getAICd());
+		}
+
+		// Calculate Akaike weights
+		for (i = 0; i < numModels; i++) {
+			if (models[i].getAICd() > 1000)
+				models[i].setAICw(0.0);
+			else
+				models[i].setAICw(Math.exp(-0.5 * models[i].getAICd()) / sumExp);
+			tempw[i] = models[i].getAIC(); // AICw
+			order[i] = i;
+		}
+
+		// Get order for AIC and calculate cumWeigths
+		sorted = false;
+		pass = 1;
+		while (!sorted) {
+			sorted = true;
+			for (i = 0; i < (numModels - pass); i++)
+				if (tempw[i] > tempw[i + 1]) {
+					temp1 = tempw[i + 1];
+					tempw[i + 1] = tempw[i];
+					tempw[i] = temp1;
+
+					temp2 = order[i + 1];
+					order[i + 1] = order[i];
+					order[i] = temp2;
+
+					sorted = false;
+				}
+			pass++;
+		}
+
+		cum = 0;
+		for (i = 0; i < numModels; i++) {
+			cum += models[order[i]].getAICw();
+			models[order[i]].setCumAICw(cum);
+		}
+
+		// confidence interval
+		buildConfidenceInterval();
+
+		// parameter importances
+		if (doImportances || doModelAveraging) {
+			parameterImportance();
+		}
+
+		// model averaging
+		if (doModelAveraging) {
+			averageModels();
+		}
+
+	}
+
+	public double computeSingle(Model model) {
+		return computeAic(model, options);
+	}
+	
+	public static double computeAic(Model model, ApplicationOptions options) {
+		if (options.countBLasParameters)
+			return 2 * (model.getLnL() + model.getK());
+		else
+			return 2 * (model.getLnL() + model.getK() - options.getNumBranches());
+		
+	}
+	
+	public static double computeAic(double lnL, int k, ApplicationOptions options) {
+		if (options.countBLasParameters)
+			return 2 * (lnL + k);
+		else
+			return 2 * (lnL + k - options.getNumBranches());
+		
+	}
+	
+	protected void printHeader(TextOutputStream stream) {
+		stream.println("\n\n\n---------------------------------------------------------------");
+		stream.println("*                                                             *");
+		stream.println("*             AKAIKE INFORMATION CRITERION (AIC)              *");
+		stream.println("*                                                             *");
+		stream.println("---------------------------------------------------------------");
+	}
+	
+	protected void printFooter(TextOutputStream stream) {
+		stream.println("-lnL:\tnegative log likelihod");
+		stream.println(" K:\tnumber of estimated parameters");
+		stream.println(" AIC:\tAkaike Information Criterion");
+		stream.println(" delta:\tAIC difference");
+		stream.println(" weight:\tAIC weight");
+		stream.println(" cumWeight:\tcumulative AIC weight");
+	}
+
+	/**************
+	 * buildConfidenceInterval ************************
+	 * 
+	 * Builts the confidence interval of selected models and their cumulative
+	 * weight
+	 * 
+	 * The model that just passed the confidence will be or not in the interval
+	 * by chance (see below)
+	 ****************************************************************/
+
+	public void buildConfidenceInterval() {
+		int i;
+		Model tmodel = models[0];
+		cumWeight = 0;
+
+		// first construct the confidence interval for models
+		if (confidenceInterval >= 1.0d) {
+			for (i = 0; i < numModels; i++) {
+				tmodel = models[order[i]];
+				tmodel.setInAICinterval(true);
+				confidenceModels.add(tmodel);
+			}
+			cumWeight = 1.0;
+		} else {
+			for (i = 0; i < numModels; i++) {
+				tmodel = models[order[i]];
+				if (tmodel.getCumAICw() <= confidenceInterval) {
+					tmodel.setInAICinterval(true);
+					confidenceModels.add(tmodel);
+					cumWeight += tmodel.getAICw();
+				} else
+					break;
+			}
+
+			// lets decide whether the model that just passed the confidence
+			// interval should be included (suggested by John Huelsenbeck)
+			double probOut = (tmodel.getCumAICw() - confidenceInterval)
+					/ tmodel.getAICw();
+			double probIn = 1.0 - probOut;
+			Random generator = new Random();
+			double randomNumber = generator.nextDouble();
+			if (randomNumber <= probIn) {
+				tmodel.setInAICinterval(true);
+				confidenceModels.add(tmodel);
+				cumWeight += tmodel.getAICw();
+			} else
+				tmodel.setInAICinterval(false);
+
+			/*
+			 * System.out.print("name=" + tmodel.name + " w=" + tmodel.AICw +
+			 * " cumw=" + tmodel.cumAICw); System.out.print(" in=" + probIn +
+			 * " out=" + probOut); System.out.print(" r=" + randomNumber +
+			 * " isIn=" + tmodel.isInAICinterval);
+			 */
+
+		}
+
+		/*
+		 * System.out.print(confidenceInterval + " confidence interval (" +
+		 * numModels + " models) = ["); for (Enumeration
+		 * e=confidenceModels.elements(); e.hasMoreElements();) { Model m =
+		 * (Model)e.nextElement(); System.out.print(m.name + " "); }
+		 * System.out.print("]");
+		 */
+	}
+
+	public double getMinModelValue() {
+		return minModel.getAIC();
+	}
+
+	public double getMinModelWeight() {
+		return minModel.getAICw();
+	}
+
+	@Override
+	public double getValue(Model m) {
+		return m.getAIC();
+	}
+
+	@Override
+	public double getWeight(Model m) {
+		return m.getAICw();
+	}
+
+	@Override
+	public double getCumWeight(Model m) {
+		return m.getCumAICw();
+	}
+	
+	@Override
+	public double getDelta(Model m) {
+		return m.getAICd();
+	}
+
+	@Override
+	public double getUDelta(Model m) {
+		return m.getUAICd();
+	}
+	
+	@Override
+	public double setUDelta(Model m) {
+		m.setUAICd(computeAic(m.getLnLIgnoringGaps(), m.getK(), options)
+				- computeAic(unconstrainedModel.getLnL(), 
+						unconstrainedModel.getK(), options));
+		return m.getUAICd();
+	}
+	
+	@Override
+	public int getType() {
+		return IC_AIC;
+	}
+
+} // class AIC
+
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/selection/AICc.java b/src/main/java/es/uvigo/darwin/jmodeltest/selection/AICc.java
new file mode 100644
index 0000000..4e43dab
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/selection/AICc.java
@@ -0,0 +1,295 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.selection;
+
+import java.util.Random;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+
+public class AICc extends InformationCriterion {
+
+	// constructor
+	public AICc(boolean mwritePAUPblock, boolean mdoImportances,
+			boolean mdoModelAveraging, double minterval) {
+		super(mwritePAUPblock, mdoImportances, mdoModelAveraging, minterval);
+	}
+
+	/****************************
+	 * computeAICc ******************************* * Computes the corrected AIC
+	 * (AICc) for small sample sizes (relative * to the number of parameters)
+	 * and finds out the model with the * minimum AICc * *
+	 ************************************************************************/
+
+	public void compute() {
+
+		boolean sorted;
+		int temp2, pass;
+		double[] tempw = new double[options.getNumModels()];
+		double min, sumExp, cum, temp1;
+
+		// Calculate AICc and minAICc
+		min = computeAicc(models[0], options);
+
+		if (doCheckAgainstULK) {
+			unconstrainedModel.setAICc(computeSingle(unconstrainedModel));
+		}
+		minModel = models[0];
+		for (Model model : models) {
+			model.setAICc(computeAicc(model, options));
+
+			if (model.getAICc() < min) {
+				min = model.getAICc();
+				minModel = model;
+			}
+			
+			if (doCheckAgainstULK) {
+				model.setUAICcd(model.getAICc() - unconstrainedModel.getAICc());
+			}
+		}
+
+		validResults = min > 0;
+		
+		// Calculate Akaike differences
+		sumExp = 0;
+		for (int i = 0; i < numModels; i++) {
+			models[i].setAICcd(models[i].getAICc() - minModel.getAICc());
+			sumExp += Math.exp(-0.5 * models[i].getAICcd());
+		}
+
+		// Calculate Akaike weights
+		for (int i = 0; i < numModels; i++) {
+			if (models[i].getAICcd() > 1000)
+				models[i].setAICcw(0.0);
+			else
+				models[i].setAICcw(Math.exp(-0.5 * models[i].getAICcd()) / sumExp);
+			tempw[i] = models[i].getAICc();
+			order[i] = i;
+		}
+
+		// Get order for Akaike weights and calculate cumWeigths
+		sorted = false;
+		pass = 1;
+		while (!sorted) {
+			sorted = true;
+			for (int i = 0; i < (numModels - pass); i++)
+				if (tempw[i] > tempw[i + 1]) {
+					temp1 = tempw[i + 1];
+					tempw[i + 1] = tempw[i];
+					tempw[i] = temp1;
+
+					temp2 = order[i + 1];
+					order[i + 1] = order[i];
+					order[i] = temp2;
+
+					sorted = false;
+				}
+			pass++;
+		}
+
+		cum = 0;
+		for (int i = 0; i < numModels; i++) {
+			cum += models[order[i]].getAICcw();
+			models[order[i]].setCumAICcw(cum);
+		}
+
+		// confidence interval
+		buildConfidenceInterval();
+
+		// parameter importances
+		if (doImportances || doModelAveraging)
+			parameterImportance();
+
+		// model averaging
+		if (doModelAveraging)
+			averageModels();
+
+	}
+
+	public double computeSingle(Model model) {
+		return computeAicc(model, options);
+	}
+	
+	public static double computeAicc(Model model, ApplicationOptions options) {
+		int K;
+		if (options.countBLasParameters)
+			K = model.getK();
+		else
+			K = model.getK() - options.getNumBranches();
+
+		double aicc;
+		if ((options.getSampleSize() - K - 1) == 0) {
+			aicc = 0;
+		} else {
+			aicc = 2 * (model.getLnL() + K)
+				+ ((double) 2 * K * (K + 1) / (options.getSampleSize() - K - 1));
+		}
+		return aicc;
+	}
+	
+	public static double computeAicc(double lnL, int k, ApplicationOptions options) {
+		int K;
+		if (options.countBLasParameters)
+			K = k;
+		else
+			K = k - options.getNumBranches();
+
+		double aicc;
+		if ((options.getSampleSize() - K - 1) == 0) {
+			aicc = 0;
+		} else {
+			aicc = 2 * (lnL + K)
+				+ ((double) 2 * K * (K + 1) / (options.getSampleSize() - K - 1));
+		}
+		System.out.println("AICC 2 IS " + aicc);
+		return aicc;
+	}
+	
+	protected void printHeader(TextOutputStream stream) {
+		stream.println("\n\n\n---------------------------------------------------------------");
+		stream.println("*                                                             *");
+		stream.println("*        CORRECTED AKAIKE INFORMATION CRITERION (AICc)        *");
+		stream.println("*                                                             *");
+		stream.println("---------------------------------------------------------------");
+		stream.println(" ");
+		stream.println(" Sample size: " + options.getSampleSize());
+	}
+	
+	protected void printFooter(TextOutputStream stream) {
+		stream.println("-lnL:\tnegative log likelihod");
+		stream.println(" K:\tnumber of estimated parameters");
+		stream.println(" AICc:\tCorrected Akaike Information Criterion");
+		stream.println(" delta:\tAICc difference");
+		stream.println(" weight:\tAICc weight");
+		stream.println(" cumWeight:\tcumulative AICc weight");
+	}
+	
+
+	/**************
+	 * buildConfidenceInterval ************************
+	 * 
+	 * Builts the confidence interval of selected models and their cumulative
+	 * weight
+	 * 
+	 * The model that just passed the confidence will be or not in the interval
+	 * by chance (see below)
+	 ****************************************************************/
+
+	public void buildConfidenceInterval() {
+		int i;
+		Model tmodel = models[0];
+		cumWeight = 0;
+
+		// first construct the confidence interval for models
+		if (confidenceInterval >= 1.0d) {
+			for (i = 0; i < numModels; i++) {
+				tmodel = models[order[i]];
+				tmodel.setInAICcinterval(true);
+				confidenceModels.add(tmodel);
+			}
+			cumWeight = 1.0;
+		} else {
+			for (i = 0; i < numModels; i++) {
+				tmodel = models[order[i]];
+				if (tmodel.getCumAICcw() <= confidenceInterval) {
+					tmodel.setInAICcinterval(true);
+					confidenceModels.add(tmodel);
+					cumWeight += tmodel.getAICcw();
+				} else
+					break;
+			}
+
+			// lets decide whether the model that just passed the confidence
+			// interval should be included (suggested by John Huelsenbeck)
+			double probOut = (tmodel.getCumAICcw() - confidenceInterval)
+					/ tmodel.getAICcw();
+			double probIn = 1.0 - probOut;
+			Random generator = new Random();
+			double randomNumber = generator.nextDouble();
+			if (randomNumber <= probIn) {
+				tmodel.setInAICcinterval(true);
+				if (!confidenceModels.contains(tmodel)) confidenceModels.add(tmodel);
+				cumWeight += tmodel.getAICcw();
+			} else
+				tmodel.setInAICcinterval(false);
+
+			/*
+			 * System.out.print("name=" + tmodel.name + " w=" + tmodel.AICcw +
+			 * " cumw=" + tmodel.cumAICw); System.out.print(" in=" + probIn +
+			 * " out=" + probOut); System.out.print(" r=" + randomNumber +
+			 * " isIn=" + tmodel.isInAICcinterval + " ");
+			 */
+		}
+
+		/*
+		 * System.out.print(confidenceInterval + " confidence interval (" +
+		 * numModels + " models) = ["); for (Enumeration
+		 * e=confidenceModels.elements(); e.hasMoreElements();) { Model m =
+		 * (Model)e.nextElement(); System.out.print(m.name + " "); }
+		 * System.out.print("]");
+		 */
+	}
+
+	public double getMinModelValue() {
+		return minModel.getAICc();
+	}
+
+	public double getMinModelWeight() {
+		return minModel.getAICcw();
+	}
+	
+	@Override
+	public double getValue(Model m) {
+		return m.getAICc();
+	}
+	
+	@Override
+	public double getWeight(Model m) {
+		return m.getAICcw();
+	}
+	
+	@Override
+	public double getDelta(Model m) {
+		return m.getAICcd();
+	}
+	
+	@Override
+	public double getUDelta(Model m) {
+		return m.getUAICcd();
+	}
+	
+	@Override
+	public double setUDelta(Model m) {
+		m.setUAICcd(computeAicc(m.getLnLIgnoringGaps(), m.getK(), options)
+				- computeAicc(unconstrainedModel.getLnL(), 
+						unconstrainedModel.getK(), options));
+		return m.getUAICcd();
+	}
+	
+	@Override
+	public double getCumWeight(Model m) {
+		return m.getCumAICcw();
+	}
+	
+	@Override
+	public int getType() {
+		return IC_AICc;
+	}
+
+} // class AICc
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/selection/BIC.java b/src/main/java/es/uvigo/darwin/jmodeltest/selection/BIC.java
new file mode 100644
index 0000000..d33dbbe
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/selection/BIC.java
@@ -0,0 +1,277 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.selection;
+
+import java.util.Random;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+
+public class BIC extends InformationCriterion {
+
+	// constructor
+	public BIC(boolean mwritePAUPblock, boolean mdoImportances,
+			boolean mdoModelAveraging, double minterval) {
+		super(mwritePAUPblock, mdoImportances, mdoModelAveraging, minterval);
+	}
+
+	/****************************
+	 * compute ******************************* * Computes the Bayesian
+	 * Information Criterion (BIC) for every model * and finds out the model
+	 * with the minimum BIC * *
+	 ************************************************************************/
+
+	public void compute() {
+
+		boolean sorted;
+		int i, temp2, pass;
+		double[] tempw = new double[numModels];
+		double min, sumExp, cum, temp1;
+
+		// Calculate BIC and minBIC
+		min = computeBic(models[0], options);
+		minModel = models[0];
+		
+		if (doCheckAgainstULK) {
+			unconstrainedModel.setBIC(computeSingle(unconstrainedModel));
+		}
+		for (Model model : models) {
+			model.setBIC(computeBic(model, options));
+
+			if (model.getBIC() < min) {
+				min = model.getBIC();
+				minModel = model;
+			}
+			
+			if (doCheckAgainstULK) {
+				model.setUBICd(model.getBIC() - unconstrainedModel.getBIC());
+			}
+		}
+
+		// Calculate BIC differences
+		sumExp = 0;
+		for (i = 0; i < numModels; i++) {
+			models[i].setBICd(models[i].getBIC() - minModel.getBIC());
+			sumExp += Math.exp(-0.5 * models[i].getBICd());
+		}
+
+		// Calculate BIC weights
+		for (i = 0; i < numModels; i++) {
+			if (models[i].getBICd() > 1000)
+				models[i].setBICw(0.0);
+			else
+				models[i].setBICw(Math.exp(-0.5 * models[i].getBICd()) / sumExp);
+			tempw[i] = models[i].getBIC();
+			order[i] = i;
+		}
+
+		// Get order for BIC weights and calculate cumWeigths
+		sorted = false;
+		pass = 1;
+		while (!sorted) {
+			sorted = true;
+			for (i = 0; i < (numModels - pass); i++)
+				if (tempw[i] > tempw[i + 1]) {
+					temp1 = tempw[i + 1];
+					tempw[i + 1] = tempw[i];
+					tempw[i] = temp1;
+
+					temp2 = order[i + 1];
+					order[i + 1] = order[i];
+					order[i] = temp2;
+
+					sorted = false;
+				}
+			pass++;
+		}
+
+		cum = 0;
+		for (i = 0; i < numModels; i++) {
+			cum += models[order[i]].getBICw();
+			models[order[i]].setCumBICw(cum);
+		}
+
+		// confidence interval
+		buildConfidenceInterval();
+
+		// parameter importances
+		if (doImportances || doModelAveraging)
+			parameterImportance();
+
+		// model averaging
+		if (doModelAveraging)
+			averageModels();
+
+	}
+
+	public double computeSingle(Model model) {
+		return computeBic(model, options);
+	}
+	
+	public static double computeBic(Model model, ApplicationOptions options) {
+		if (options.countBLasParameters)
+			return 2 * model.getLnL()
+					+ model.getK()
+					* Math.log(options.getSampleSize());
+		else
+			return 2 * model.getLnL()
+					+ (model.getK() - options.getNumBranches())
+					* Math.log(options.getSampleSize());
+	}
+	
+	public static double computeBic(double lnL, int k, ApplicationOptions options) {
+		if (options.countBLasParameters)
+			return 2 * lnL + k * Math.log(options.getSampleSize());
+		else
+			return 2 * lnL + (k - options.getNumBranches())
+					* Math.log(options.getSampleSize());
+	}
+	
+	protected void printHeader(TextOutputStream stream) {
+		stream.println("\n\n\n---------------------------------------------------------------");
+		stream.println("*                                                             *");
+		stream.println("*             BAYESIAN INFORMATION CRITERION (BIC)            *");
+		stream.println("*                                                             *");
+		stream.println("---------------------------------------------------------------");
+		stream.println(" ");
+		stream.println(" Sample size: " + options.getSampleSize());
+	}
+	
+	protected void printFooter(TextOutputStream stream) {
+		stream.println("-lnL:\tnegative log likelihod");
+		stream.println("K:\tnumber of estimated parameters");
+		stream.println("BIC:\tBayesian Information Criterion");
+		stream.println("delta:\tBIC difference");
+		stream.println("weight:\tBIC weight");
+		stream.println("cumWeight:\tcumulative BIC weight");
+	}
+	
+	/**************
+	 * buildConfidenceInterval ************************
+	 * 
+	 * Builts the confidence interval of selected models and their cumulative
+	 * weight
+	 * 
+	 * The model that just passed the confidence will be or not in the interval
+	 * by chance (see below)
+	 ****************************************************************/
+
+	public void buildConfidenceInterval() {
+		int i;
+		Model tmodel = models[0];
+		cumWeight = 0;
+
+		// first construct the confidence interval for models
+		if (confidenceInterval >= 1.0d) {
+			for (i = 0; i < numModels; i++) {
+				tmodel = models[order[i]];
+				tmodel.setInBICinterval(true);
+				confidenceModels.add(tmodel);
+			}
+			cumWeight = 1.0;
+		} else {
+			for (i = 0; i < numModels; i++) {
+				tmodel = models[order[i]];
+				if (tmodel.getCumBICw() <= confidenceInterval) {
+					tmodel.setInBICinterval(true);
+					confidenceModels.add(tmodel);
+					cumWeight += tmodel.getBICw();
+				} else
+					break;
+			}
+
+			// lets decide whether the model that just passed the confidence
+			// interval should be included (suggested by John Huelsenbeck)
+			double probOut = (tmodel.getCumBICw() - confidenceInterval)
+					/ tmodel.getBICw();
+			double probIn = 1.0 - probOut;
+			Random generator = new Random();
+			double randomNumber = generator.nextDouble();
+			if (randomNumber <= probIn) {
+				tmodel.setInBICinterval(true);
+				confidenceModels.add(tmodel);
+				cumWeight += tmodel.getBICw();
+			} else
+				tmodel.setInBICinterval(false);
+
+			/*
+			 * System.out.print("name=" + tmodel.name + " w=" + tmodel.BICw +
+			 * " cumw=" + tmodel.cumBICw); System.out.print(" in=" + probIn +
+			 * " out=" + probOut); System.out.print(" r=" + randomNumber +
+			 * " isIn=" + tmodel.isInBICinterval);
+			 */
+
+		}
+
+		/*
+		 * System.out.print(confidenceInterval + " confidence interval (" +
+		 * numModels + " models) = ["); for (Enumeration
+		 * e=confidenceModels.elements(); e.hasMoreElements();) { Model m =
+		 * (Model)e.nextElement(); System.out.print(m.name + " "); }
+		 * System.out.print("]");
+		 */
+	}
+
+	public double getMinModelValue() {
+		return minModel.getBIC();
+	}
+
+	public double getMinModelWeight() {
+		return minModel.getBICw();
+	}
+	
+	@Override
+	public double getValue(Model m) {
+		return m.getBIC();
+	}
+	
+	@Override
+	public double getWeight(Model m) {
+		return m.getBICw();
+	}
+	
+	@Override
+	public double getDelta(Model m) {
+		return m.getBICd();
+	}
+	
+	@Override
+	public double getUDelta(Model m) {
+		return m.getUBICd();
+	}
+	
+	@Override
+	public double setUDelta(Model m) {
+		m.setUBICd(computeBic(m.getLnLIgnoringGaps(), m.getK(), options)
+				- computeBic(unconstrainedModel.getLnL(), 
+						unconstrainedModel.getK(), options));
+		return m.getUBICd();
+	}
+	
+	@Override
+	public double getCumWeight(Model m) {
+		return m.getCumBICw();
+	}
+
+	@Override
+	public int getType() {
+		return IC_BIC;
+	}
+} // class BIC
+
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/selection/DT.java b/src/main/java/es/uvigo/darwin/jmodeltest/selection/DT.java
new file mode 100644
index 0000000..04a7ccc
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/selection/DT.java
@@ -0,0 +1,272 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.selection;
+
+import java.util.Random;
+
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.tree.TreeDistancesCache;
+import es.uvigo.darwin.jmodeltest.tree.TreeEuclideanDistancesCache;
+
+//DP check: DT might keep running even with bad likelihoods ?
+public class DT extends InformationCriterion {
+
+	private TreeDistancesCache distances = TreeEuclideanDistancesCache.getInstance();
+	
+	// constructor
+	public DT(boolean mwritePAUPblock, boolean mdoImportances,
+			boolean mdoModelAveraging, double minterval) {
+		super(mwritePAUPblock, mdoImportances, mdoModelAveraging, minterval);
+	}
+
+	/****************************
+	 * compute ******************************* * Computes the Decision theory
+	 * Criterion (DT) for every model * and finds out the model with the minimum
+	 * DT * *
+	 ************************************************************************/
+
+	public void compute() {
+
+		boolean sorted;
+		int i, j, temp2, pass;
+		double min, sum, sumReciprocal, cum, temp1;
+		double[] tempw = new double[numModels];
+		double[] bicValues = new double[numModels];
+		double[] bicLike = new double[numModels];
+
+		/* exactly as in DT-ModSel.pl */
+		// get BICs and min BIC
+		double minBIC = min = Double.MAX_VALUE;
+		for (i = 0; i < numModels; i++) {
+			bicValues[i] = BIC.computeBic(models[i], options);
+			if (bicValues[i] < minBIC)
+				minBIC = bicValues[i];
+		}
+		
+		double denom = 0.0;
+		for (i = 0; i < numModels; i++) {
+			bicLike[i] = Math.exp(-0.5*(bicValues[i] - minBIC));
+			denom += bicLike[i];
+		}
+
+		for (Model model1 : models) {
+			sum = 0.0;
+			j = 0;
+			for (Model model2 : models) {
+				double distance = distances.getDistance(model1.getTree(), model2.getTree());
+				if (distance > 0) {
+					sum += distance * bicLike[j];
+				}
+				j++;
+			}
+			model1.setDT(sum / denom);
+			if (model1.getDT() < min) {
+				min = model1.getDT();
+				minModel = model1;
+			}
+		}
+
+		// Calculate DT differences
+		sumReciprocal = sum = 0;
+		for (i = 0; i < numModels; i++) {
+			models[i].setDTd(models[i].getDT() - minModel.getDT());
+			sumReciprocal += 1.0 / models[i].getDT();
+		}
+
+		// DP we need to do it in a different way?: i think so...
+		for (i = 0; i < numModels; i++) {
+			if (models[i].getDTd() > 1000)
+				models[i].setDTw(0.0);
+			else
+				models[i].setDTw((1.0 / models[i].getDT()) / sumReciprocal);
+			tempw[i] = models[i].getDT();
+			order[i] = i;
+		}
+
+		// Get order for DT weights and calculate cumWeigths
+		sorted = false;
+		pass = 1;
+		while (!sorted) {
+			sorted = true;
+			for (i = 0; i < (numModels - pass); i++)
+				if (tempw[i] > tempw[i + 1]) {
+					temp1 = tempw[i + 1];
+					tempw[i + 1] = tempw[i];
+					tempw[i] = temp1;
+
+					temp2 = order[i + 1];
+					order[i + 1] = order[i];
+					order[i] = temp2;
+
+					sorted = false;
+				}
+			pass++;
+		}
+
+		cum = 0;
+		for (i = 0; i < numModels; i++) {
+			cum += models[order[i]].getDTw();
+			models[order[i]].setCumDTw(cum);
+		}
+
+		// confidence interval
+		buildConfidenceInterval();
+
+		// parameter importances
+		if (doImportances || doModelAveraging)
+			parameterImportance();
+
+		// model averaging
+		if (doModelAveraging)
+			averageModels();
+
+	}
+	
+	public double computeSingle(Model model) {
+		throw new RuntimeException("Cannot compute a single criterion value for DT");
+	}
+	
+	protected void printHeader(TextOutputStream stream) {
+		stream.println("\n\n\n---------------------------------------------------------------");
+		stream.println("*                                                             *");
+		stream.println("*      DECISION THEORY PERFORMANCE-BASED SELECTION (DT)       *");
+		stream.println("*                                                             *");
+		stream.println("---------------------------------------------------------------");
+		stream.println(" ");
+		stream.println(" Sample size: " + options.getSampleSize());
+	}
+	
+	protected void printFooter(TextOutputStream stream) {
+		stream.println("-lnL:t\tnegative log likelihod");
+		stream.println("K:\tnumber of estimated parameters");
+		stream.println("DT:\tdecision theory performance-based score");
+		stream.println("delta:\tDT difference");
+		stream.println("weight:\tDT weight* (calculated using 1/DT)");
+		stream.println("cumWeight:\tcumulative DT weight");
+	}
+	
+	/**************
+	 * buildConfidenceInterval ************************
+	 * 
+	 * Builts the confidence interval of selected models and their cumulative
+	 * weight
+	 * 
+	 * The model that just passed the confidence will be or not in the interval
+	 * by chance (see below)
+	 ****************************************************************/
+
+	public void buildConfidenceInterval() {
+		int i;
+		Model tmodel = models[0];
+		cumWeight = 0;
+
+		// first construct the confidence interval for models
+		if (confidenceInterval >= 1.0d) {
+			for (i = 0; i < numModels; i++) {
+				tmodel = models[order[i]];
+				tmodel.setInDTinterval(true);
+				confidenceModels.add(tmodel);
+			}
+			cumWeight = 1.0;
+		} else {
+			for (i = 0; i < numModels; i++) {
+				tmodel = models[order[i]];
+				if (tmodel.getCumDTw() <= confidenceInterval) {
+					tmodel.setInDTinterval(true);
+					confidenceModels.add(tmodel);
+					cumWeight += tmodel.getDTw();
+				} else
+					break;
+			}
+
+			// lets decide whether the model that just passed the confidence
+			// interval should be included (suggested by John Huelsenbeck)
+			double probOut = (tmodel.getCumDTw() - confidenceInterval)
+					/ tmodel.getDTw();
+			double probIn = 1.0 - probOut;
+			Random generator = new Random();
+			double randomNumber = generator.nextDouble();
+			if (randomNumber <= probIn) {
+				tmodel.setInDTinterval(true);
+				confidenceModels.add(tmodel);
+				cumWeight += tmodel.getDTw();
+			} else
+				tmodel.setInDTinterval(false);
+
+			/*
+			 * System.out.print("name=" + tmodel.name + " w=" + tmodel.DTw +
+			 * " cumw=" + tmodel.cumDTw); System.out.print(" in=" + probIn +
+			 * " out=" + probOut); System.out.print(" r=" + randomNumber +
+			 * " isIn=" + tmodel.isInDTinterval);
+			 */
+
+		}
+
+		/*
+		 * System.out.print(confidenceInterval + " confidence interval (" +
+		 * numModels + " models) = ["); for (Enumeration
+		 * e=confidenceModels.elements(); e.hasMoreElements();) { Model m =
+		 * (Model)e.nextElement(); System.out.print(m.name + " "); }
+		 * System.out.print("]");
+		 */
+	}
+
+	public double getMinModelValue() {
+		return minModel.getDT();
+	}
+
+	public double getMinModelWeight() {
+		return minModel.getDTw();
+	}
+	
+	@Override
+	public double getValue(Model m) {
+		return m.getDT();
+	}
+	
+	@Override
+	public double getWeight(Model m) {
+		return m.getDTw();
+	}
+	
+	@Override
+	public double getDelta(Model m) {
+		return m.getDTd();
+	}
+	
+	@Override
+	public double getUDelta(Model m) {
+		return Double.NaN;
+	}
+	
+	@Override
+	public double setUDelta(Model m) {
+		return Double.NaN;
+	}
+	
+	@Override
+	public double getCumWeight(Model m) {
+		return m.getCumDTw();
+	}
+	
+	@Override
+	public int getType() {
+		return IC_DT;
+	}
+} // class DT
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/selection/HLRT.java b/src/main/java/es/uvigo/darwin/jmodeltest/selection/HLRT.java
new file mode 100644
index 0000000..904d166
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/selection/HLRT.java
@@ -0,0 +1,643 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.selection;
+
+import java.util.Enumeration;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.statistics.Statistics;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class HLRT {
+	private ApplicationOptions options;
+	public final double MAX_PROB = 0.999999;
+	public final double MIN_PROB = 0.000001;
+	public double alphaLRT;
+	public TextOutputStream stream = ModelTest.getMainConsole();
+
+	public int TPMnumber;
+	public int TIMnumber;
+
+	// constructor
+	public HLRT(ApplicationOptions options) {
+		this.options = options;
+		TPMnumber = 0;
+		TIMnumber = 0;
+	}
+
+	/****************************
+	 * compute ********************************* * Builds and tests the
+	 * hierarchy of LRTs accordingly to the starting * model and adding or
+	 * removing parameters in a particular order * *
+	 ***********************************************************************/
+
+	public void compute(boolean forward, double alpha, boolean writePAUPblock) {
+
+		int i;
+		double P;
+		Model currentModel, nullModel, altModel, competingModel;
+		String[] hypotheses;
+
+		alphaLRT = alpha;
+		hypotheses = new String[ModelTest.testingOrder.size()];
+		i = 0;
+
+		for (Enumeration<String> e = ModelTest.testingOrder.elements(); e
+				.hasMoreElements();)
+			hypotheses[i++] = e.nextElement();
+
+		if (ModelTest.buildGUI)
+			System.out.print("computing hLRT ... ");
+
+		if (forward)
+			currentModel = ModelTest.getCandidateModels()[0];
+		else
+			currentModel = ModelTest.getCandidateModels()[options
+					.getNumModels() - 1];
+
+		stream.println("\n\n\n---------------------------------------------------------------");
+		stream.println("*                                                             *");
+		stream.println("*          HIERARCHICAL LIKELIHOO RATIO TESTS (hLRT)          *");
+		stream.println("*                                                             *");
+		stream.println("---------------------------------------------------------------");
+
+		if (options.getSubstTypeCode() >= 4) {
+			stream.println("\nhLRT is not available for the 203 substitution scheme.");
+			stream.println("Please use one of the other available selection criteria (AIC, BIC, AICc or DT).");
+			return;
+		}
+
+		if (options.fixedTopology | options.userTopologyExists) {
+			stream.println("\nSettings: ");
+			if (forward)
+				stream.println("  Forward selection (adding parameters)");
+			else
+				stream.println("  Backward selection (removing parameters)");
+
+			stream.println("    starting model = " + currentModel.getName());
+			stream.print("    hypotheses order = ");
+			for (i = 0; i < hypotheses.length; i++) {
+				stream.print(hypotheses[i]);
+				if (i < hypotheses.length - 1)
+					stream.print("-");
+			}
+			stream.print("\n  Confidence alpha level = ");
+			stream.printf("%6.4f\n", alphaLRT);
+
+			nullModel = null;
+			altModel = null;
+
+			for (i = 0; i < hypotheses.length; i++) {
+				if (forward)
+					nullModel = currentModel;
+				else
+					altModel = currentModel;
+
+				stream.println("\n* Tested hypothesis = " + hypotheses[i]);
+				competingModel = findCompetingModel(currentModel,
+						hypotheses[i], forward);
+				if (competingModel == null) {
+					stream.println("Cannot be tested. No competing model differs just by "
+							+ hypotheses[i]
+							+ " from "
+							+ currentModel.getName()
+							+ ".\nRevise the order of hypotheses selected for the LRTs."
+							+ "\n...Skipping to the next hypothesis");
+					// System.err.println("hypothesis = " + hypotheses[i] +
+					// " -- not found best competing model");
+					continue;
+				}
+
+				// System.err.println("hypothesis = " + hypotheses[i] +
+				// " -- found best competing model = " + competingModel.name);
+
+				if (ApplicationOptions.getInstance().getSubstTypeCode() == 3)
+					if (competingModel.getName().startsWith("TIM")
+							|| competingModel.getName().startsWith("TPM"))
+						competingModel = BestTIMTPM(competingModel);
+
+				if (forward)
+					altModel = competingModel;
+				else
+					nullModel = competingModel;
+
+				stream.printf("Null model        = %-8s", nullModel.getName());
+				stream.printf("\t-lnL = %6.4f", nullModel.getLnL());
+				stream.printf("\nAlternative model = %-8s", altModel.getName());
+				stream.printf("\t-lnL = %6.4f", altModel.getLnL());
+				stream.println();
+
+				if (hypotheses[i].equals("gamma")
+						|| hypotheses[i].equals("pinv"))
+					P = LRTboundary(nullModel, altModel);
+				else
+					P = LRT(nullModel, altModel);
+
+				if (forward) {
+					if (P < alphaLRT)
+						currentModel = altModel;
+					else {
+						stream.println("\nThe current model could not be rejected");
+						if (ModelTest.buildGUI)
+							Utilities.toConsoleEnd();
+						break;
+					}
+				} else {
+					if (P > alphaLRT)
+						currentModel = nullModel;
+					else {
+						stream.println("\nThe current model rejected the null model");
+						if (ModelTest.buildGUI)
+							Utilities.toConsoleEnd();
+						break;
+					}
+				}
+
+				if (ModelTest.buildGUI)
+					Utilities.toConsoleEnd();
+			}
+
+			ModelTest.setMinHLRT(currentModel);
+
+			stream.println("\n Model selected: ");
+			ModelTest.getMinHLRT().print(stream);
+
+			// print ML tree for best-fit model
+			if (ApplicationOptions.getInstance().optimizeMLTopology)
+				stream.println("\nML tree (NNI) for the best hLRT model = "
+						+ ModelTest.getMinHLRT().getTreeString());
+
+			// print PAUP* block
+			if (writePAUPblock)
+				ModelTest
+						.WritePaupBlock(stream, "hLRT", ModelTest.getMinHLRT());
+
+		} else {
+			stream.println("\nhLRT is only available when likelihoods are calculated on the same tree (i.e., models are nested)");
+			stream.println("Execute jModelTest using a fixed BIONJ-JC tree or a user-defined topology");
+		}
+
+		if (ModelTest.buildGUI) {
+			Utilities.toConsoleEnd();
+			System.out.println("OK");
+		}
+	}
+
+	/****************************
+	 * computeDynamical ************************ * Builds and tests the
+	 * hierarchy of LRTs in a dynamic fashion -- finding the best step to take
+	 * (biggest increase in lnL) -- * and adding or removing parameters in a
+	 * particular order * *
+	 ***********************************************************************/
+
+	public void computeDynamical(boolean forward, double alpha,
+			boolean writePAUPblock) {
+
+		int i, j, bestHypothesisIndex;
+		double P;
+		Model currentModel, nullModel, altModel, competingModel, bestCompetingModel;
+		String[] hypotheses, trimmedHypotheses;
+		boolean thereAreValidHypotheses;
+		double lnDifference, bestLnDifference;
+
+		alphaLRT = alpha;
+		hypotheses = new String[ModelTest.testingOrder.size()];
+		i = 0;
+		for (String s : ModelTest.testingOrder)
+			hypotheses[i++] = s;
+
+		if (ModelTest.buildGUI)
+			System.out.print("computing dynamical LRTs ... ");
+
+		if (forward)
+			currentModel = ModelTest.getCandidateModels()[0];
+		else
+			currentModel = ModelTest.getCandidateModels()[options
+					.getNumModels() - 1];
+
+		stream.println("\n\n\n---------------------------------------------------------------");
+		stream.println("*                                                             *");
+		stream.println("*          DYNAMICAL LIKELIHOO RATIO TESTS (dLRT)             *");
+		stream.println("*                                                             *");
+		stream.println("---------------------------------------------------------------");
+
+		stream.println("\nSettings: ");
+		if (forward)
+			stream.println("  Forward selection (adding parameters)");
+		else
+			stream.println("  Backward selection (removing parameters)");
+
+		stream.println("    starting model = " + currentModel.getName());
+		stream.print("    hypotheses = ");
+		for (i = 0; i < hypotheses.length; i++) {
+			stream.print(hypotheses[i]);
+			if (i < hypotheses.length - 1)
+				stream.print(", ");
+		}
+		stream.print("\n  Confidence alpha level = ");
+		stream.printf("%6.4f\n", alphaLRT);
+
+		nullModel = null;
+		altModel = null;
+
+		thereAreValidHypotheses = true;
+		while (thereAreValidHypotheses) {
+			bestCompetingModel = null;
+			bestHypothesisIndex = 0;
+
+			if (forward) {
+				nullModel = currentModel;
+				bestLnDifference = 0;
+			} else {
+				altModel = currentModel;
+				bestLnDifference = 1000000;
+			}
+
+			// chose best competing model across hypotheses
+			for (i = 0; i < hypotheses.length; i++) {
+				lnDifference = 0;
+				competingModel = findCompetingModel(currentModel,
+						hypotheses[i], forward);
+				if (competingModel != null) {
+					if (ApplicationOptions.getInstance().getSubstTypeCode() == 3)
+						if (competingModel.getName().startsWith("TIM")
+								|| competingModel.getName().startsWith("TPM"))
+							competingModel = BestTIMTPM(competingModel);
+					lnDifference = Math.abs(currentModel.getLnL()
+							- competingModel.getLnL());
+					if ((forward && lnDifference > bestLnDifference)
+							|| (!forward && lnDifference < bestLnDifference)) {
+						bestCompetingModel = competingModel;
+						bestLnDifference = lnDifference;
+						bestHypothesisIndex = i;
+					}
+				}
+			}
+
+			// we should not be here
+			if (bestCompetingModel == null) {
+				stream.print("\nNo best competing model for any of the "
+						+ hypotheses.length + " remaining hypotheses: ");
+				for (i = 0; i < hypotheses.length; i++) {
+					stream.print(hypotheses[i]);
+					if (i < hypotheses.length - 1)
+						stream.print(" + ");
+				}
+				stream.println(", given the current model = "
+						+ currentModel.getName());
+				// System.err.println("hypothesis = " +
+				// hypotheses[bestHypothesisIndex] +
+				// " -- not found best competing model");
+				thereAreValidHypotheses = false;
+				continue;
+			}
+
+			/*
+			 * stream.println("\nBest hypothesis = " +
+			 * hypotheses[bestHypothesisIndex] + "\n current model = " +
+			 * currentModel.name + "\n competing model = " +
+			 * bestCompetingModel.name + "\n best lnL increase = " +
+			 * bestLnDifference);
+			 */
+
+			// System.err.println("hypothesis = " +
+			// hypotheses[bestHypothesisIndex] +
+			// " -- found best competing model = " + bestCompetingModel.name);
+
+			if (forward)
+				altModel = bestCompetingModel;
+			else
+				nullModel = bestCompetingModel;
+
+			stream.println("\nTesting " + hypotheses[bestHypothesisIndex]
+					+ " hypothesis");
+			stream.printf("Null model        = %-8s", nullModel.getName());
+			stream.printf("\t-lnL = %6.4f", nullModel.getLnL());
+			stream.printf("\nAlternative model = %-8s", altModel.getName());
+			stream.printf("\t-lnL = %6.4f", altModel.getLnL());
+			stream.println();
+
+			// test this best hypothesis
+			if (hypotheses[bestHypothesisIndex].equals("gamma")
+					|| hypotheses[bestHypothesisIndex].equals("pinv"))
+				P = LRTboundary(nullModel, altModel);
+			else
+				P = LRT(nullModel, altModel);
+
+			if (forward) {
+				if (P < alphaLRT)
+					currentModel = altModel;
+				else {
+					stream.println("\nThe current model could not be rejected");
+					if (ModelTest.buildGUI)
+						Utilities.toConsoleEnd();
+					break;
+				}
+			} else {
+				if (P > alphaLRT)
+					currentModel = nullModel;
+				else {
+					stream.println("\nThe current model rejected the null model");
+					if (ModelTest.buildGUI)
+						Utilities.toConsoleEnd();
+					break;
+				}
+			}
+
+			// remove the hypothesis tested
+			trimmedHypotheses = new String[hypotheses.length - 1];
+			for (i = j = 0; i < hypotheses.length; i++) {
+				if (i < bestHypothesisIndex)
+					trimmedHypotheses[j++] = hypotheses[i].toString();
+				else if (i > bestHypothesisIndex)
+					trimmedHypotheses[j++] = hypotheses[i].toString();
+			}
+			hypotheses = trimmedHypotheses;
+
+			if (hypotheses.length <= 0)
+				thereAreValidHypotheses = false;
+
+			if (ModelTest.buildGUI)
+				Utilities.toConsoleEnd();
+		}
+
+		ModelTest.setMinDLRT(currentModel);
+
+		stream.println("\n Model selected: ");
+		ModelTest.getMinDLRT().print(stream);
+
+		// print PAUP* block
+		if (writePAUPblock)
+			ModelTest.WritePaupBlock(stream, "dLRT", ModelTest.getMinDLRT());
+
+		if (ModelTest.buildGUI) {
+			Utilities.toConsoleEnd();
+			System.out.println("OK");
+		}
+	}
+
+	/****************************
+	 * findCompetingModel*********************** * Finds the corresponding
+	 * competing model given the current * model and hypothesis that is being
+	 * tested. The null model * has to be nested within the alternative, and
+	 * they can only differ * by one set of parameters * *
+	 ***********************************************************************/
+
+	public Model findCompetingModel(Model current, String test, boolean adding) {
+		int distance;
+		boolean isTest;
+		Model competing, found;
+
+		found = null;
+		for (Model model : ModelTest.getCandidateModels()) {
+			competing = model;
+			isTest = false;
+			distance = 0;
+
+			// if step forward compare only with more complex models
+			if (adding && current.getK() - competing.getK() >= 0)
+				continue;
+			// if step down compare only with simpler models
+			else if (!adding && current.getK() - competing.getK() <= 0)
+				continue;
+
+			if (current.ispF() != competing.ispF()) {
+				if (test.equals("freq"))
+					isTest = true;
+				distance++;
+			}
+			if ((!current.ispT() && competing.ispT())
+					|| (!competing.ispT() && current.ispT())) {
+				if (test.equals("titv"))
+					isTest = true;
+				if (!current.ispR() && !competing.ispR()) // because we will
+															// increase this
+															// distance later
+															// for models with
+															// pR
+					distance++;
+			}
+			if (current.ispG() != competing.ispG()) {
+				if (test.equals("gamma"))
+					isTest = true;
+				distance++;
+			}
+			if (current.ispI() != competing.ispI()) {
+				if (test.equals("pinv"))
+					isTest = true;
+				distance++;
+			}
+
+			// because JC and GTR have the same pT ...
+			if (current.ispT() == competing.ispT()
+					&& current.ispR() != competing.ispR())
+				isTest = false;
+
+			if (ApplicationOptions.getInstance().getSubstTypeCode() == 0) {
+				if ((Math.abs(competing.getNumTi() - current.getNumTi()) == 1)
+						&& (Math.abs(competing.getNumTv() - current.getNumTv()) == 3)) {
+					if (test.equals("2ti4tv"))
+						isTest = true;
+					distance++;
+				}
+			} else if (((adding) && (current.ispT() || current.ispR()))
+					|| ((!adding) && (competing.ispT() || competing.ispR()))) {
+				if (Math.abs(competing.getNumTi() - current.getNumTi()) == 1) {
+					if (test.equals("2ti"))
+						isTest = true;
+					distance++;
+				}
+				if (Math.abs(competing.getNumTv() - current.getNumTv()) == 1) {
+					if (test.equals("2tv"))
+						isTest = true;
+					distance++;
+				} else if (Math.abs(competing.getNumTv() - current.getNumTv()) == 2) {
+					if (test.equals("4tv"))
+						isTest = true;
+					distance++;
+				} else if (Math.abs(competing.getNumTv() - current.getNumTv()) == 3)
+					isTest = false;
+			}
+
+			if (isTest && distance == 1) {
+				found = model;
+				break;
+			}
+
+			// System.err.println("test = " + test + "   current = " +
+			// current.name + "  competing = " + competing.name +
+			// "  isTest = " + isTest + "  distance = " + distance);
+
+		}
+
+		return found;
+	}
+
+	/****************************
+	 * BestTIMTPM ******************************* * Returns the corresponding
+	 * individual model within the families * TPM, TPMuf, TIM and TIMef * *
+	 *************************************************************************/
+
+	public Model BestTIMTPM(Model whichModel) {
+		Model foundModel = null;
+		String name, model1, model2, model3;
+
+		name = whichModel.getName();
+		model1 = name.replaceFirst("[0-9]", "1");
+		model2 = name.replaceFirst("[0-9]", "2");
+		model3 = name.replaceFirst("[0-9]", "3");
+
+		// System.err.println ("Find best among " + model1 + " and " + model2 +
+		// " and " + model3);
+		foundModel = findBest(model1, model2, model3);
+		// System.err.println ("Found :" + foundModel.name);
+
+		return foundModel;
+	}
+
+	/****************************
+	 * findBest ******************************* * Finds the model with the
+	 * highest likelihood out of three * TIM or TPM given models * *
+	 ************************************************************************/
+
+	public Model findBest(String modelName1, String modelName2,
+			String modelName3) {
+		Model m1, m2, m3;
+
+		m1 = m2 = m3 = null;
+
+		for (Model model : ModelTest.getCandidateModels()) {
+			if (modelName1.equals(model.getName()))
+				m1 = model;
+			else if (modelName2.equals(model.getName()))
+				m2 = model;
+			else if (modelName3.equals(model.getName()))
+				m3 = model;
+		}
+
+		// check if we already know the familiy number
+		if (m1.getName().startsWith("TIM") && TIMnumber > 0) {
+			if (TIMnumber == 1)
+				return m1;
+			else if (TIMnumber == 2)
+				return m2;
+			else
+				return m3;
+		} else if (m1.getName().startsWith("TPM") && TPMnumber > 0) {
+			if (TPMnumber == 1)
+				return m1;
+			else if (TPMnumber == 2)
+				return m2;
+			else
+				return m3;
+		}
+
+		// otherwise we will select it now
+		stream.println("Selecting first best representative model among:");
+		stream.println("  " + m1.getName() + " (-lnL = " + m1.getLnL() + ")");
+		stream.println("  " + m2.getName() + " (-lnL = " + m2.getLnL() + ")");
+		stream.println("  " + m3.getName() + " (-lnL = " + m3.getLnL() + ")");
+
+		if (m1.getLnL() <= m2.getLnL() && m1.getLnL() <= m3.getLnL()) {
+			if (m1.getName().startsWith("TIM"))
+				TIMnumber = 1;
+			else
+				TPMnumber = 1;
+			return m1;
+		} else if (m2.getLnL() <= m1.getLnL() && m2.getLnL() <= m3.getLnL()) {
+			if (m2.getName().startsWith("TIM"))
+				TIMnumber = 2;
+			else
+				TPMnumber = 2;
+			return m2;
+		} else {
+			if (m3.getName().startsWith("TIM"))
+				TIMnumber = 3;
+			else
+				TPMnumber = 3;
+			return m3;
+		}
+	}
+
+	/****************************
+	 * LRT ************************************* * Computes a likelihood ratio
+	 * test between two model and returns * a P-value according to a standard
+	 * chi2 distribution * *
+	 ***********************************************************************/
+
+	private double LRT(Model model0, Model model1) {
+		double delta, prob;
+		int df;
+
+		delta = 2 * (model0.getLnL() - model1.getLnL());
+		df = model1.getK() - model0.getK();
+
+		if (delta == 0)
+			prob = 1.0;
+		else
+			prob = Statistics.chiSquareProbability(delta, df);
+
+		stream.printf("2(lnL1-lnL0)      = %6.4f", delta);
+		if (prob == 1.0)
+			stream.println("\tP-value > " + MAX_PROB);
+		else if (prob < 0.000001)
+			stream.println("\tP-value < " + MIN_PROB);
+		else
+			stream.printf("\tP-value = %6.4f\n", prob);
+
+		return prob;
+	}
+
+	/***************************
+	 * LRTboundary******************************* * Computes a likelihood ratio
+	 * test between two model and returns * a P-value according to a mixed chi2
+	 * distribution * *
+	 ***********************************************************************/
+
+	private double LRTboundary(Model model0, Model model1) {
+		double delta, prob;
+		int df;
+
+		delta = 2 * (model0.getLnL() - model1.getLnL());
+		df = model1.getK() - model0.getK();
+
+		if (delta == 0)
+			prob = 1.0;
+		else {
+			if (df == 1)
+				prob = Statistics.chiSquareProbability(delta, df) / 2;
+			else
+				prob = (Statistics.chiSquareProbability(delta, df - 1) + Statistics
+						.chiSquareProbability(delta, df)) / 2;
+		}
+
+		stream.printf("2(lnL1-lnL0)      = %6.4f", delta);
+		if (prob == 1.0)
+			stream.println("\tP-value > " + MAX_PROB);
+		else if (prob < 0.000001)
+			stream.println("\tP-value < " + MIN_PROB);
+		else
+			stream.printf("\tP-value = %6.4f\n", prob);
+
+		return prob;
+	}
+
+} // class hLRT
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/selection/InformationCriterion.java b/src/main/java/es/uvigo/darwin/jmodeltest/selection/InformationCriterion.java
new file mode 100644
index 0000000..a4c40fe
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/selection/InformationCriterion.java
@@ -0,0 +1,660 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.selection;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.exe.PhymlSingleModel;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public abstract class InformationCriterion {
+
+	protected ApplicationOptions options = ApplicationOptions.getInstance();
+
+	public static final int IC_AIC = 1;
+	public static final int IC_AICc = 2;
+	public static final int IC_BIC = 3;
+	public static final int IC_DT = 4;
+
+	private static final String[] names = { "", "AIC", "AICc", "BIC", "DT" };
+
+	public int[] order;
+	protected int numModels;
+	protected Model[] models;
+	protected boolean writePAUPblock;
+	protected boolean doImportances;
+	protected boolean doModelAveraging;
+	protected double confidenceInterval;
+	protected List<Model> confidenceModels;
+	protected double cumWeight;
+	protected Model minModel;
+
+	protected boolean doCheckAgainstULK;
+	protected Model unconstrainedModel;
+
+	// importances
+	protected double ifA, ifG, ifC, ifT;
+	protected double ititv, ikappa, ipinvI, ishapeG, ipinvIG, ishapeIG;
+	protected double iRa, iRb, iRc, iRd, iRe, iRf;
+	// averaged estimates
+	protected double afA, afG, afC, afT;
+	protected double atitv, akappa, apinvI, ashapeG, apinvIG, ashapeIG;
+	protected double aRa, aRb, aRc, aRd, aRe, aRf;
+
+	protected boolean validResults;
+	
+	public List<Model> getConfidenceModels() {
+		return confidenceModels;
+	}
+
+	public InformationCriterion(boolean mwritePAUPblock,
+			boolean mdoImportances, boolean mdoModelAveraging, double minterval) {
+		List<Model> modelList = new ArrayList<Model>();
+		for (Model model : ModelTest.getCandidateModels()) {
+			if (model.getLnL() > 0) {
+				modelList.add(model);
+			}
+		}
+		models = modelList.toArray(new Model[0]);
+		numModels = models.length;
+		order = new int[numModels];
+		writePAUPblock = mwritePAUPblock;
+		doImportances = mdoImportances;
+		doModelAveraging = mdoModelAveraging;
+		confidenceInterval = minterval;
+		confidenceModels = new ArrayList<Model>();
+		validResults = true;
+		
+		doCheckAgainstULK = (getType() != IC_DT
+				&& (options.getNumPatterns() > 0) && (options
+				.getUnconstrainedLnL() > 1e-10));
+
+		if (doCheckAgainstULK) {
+			unconstrainedModel = new Model(numModels, "UModel", "-",
+					options.getNumPatterns() - 1);
+			unconstrainedModel.setLnL(options.getUnconstrainedLnL());
+		}
+	}
+
+	/**************************************************************
+	 * parameterImportance
+	 * 
+	 * Calculates the importance for each parameter
+	 * 
+	 * Assumes model estimates rate parametes Ra-Re when they are different to
+	 * Rf
+	 * 
+	 * Note: Modeltest assumed TrN y TIM estimate only Rb, Re K81 estimates no R
+	 * parameter TVM estimates only Ra, Rc, Rd GTR y SIM estimate Ra, Rb, Rc,
+	 * Rd, Re
+	 * 
+	 * Importance is rescaled by the total weight of the models included in the
+	 * confidence interval
+	 **************************************************************/
+	public void parameterImportance() {
+		double weight;
+		String partition;
+		ifA = ifG = ifC = ifT = 0;
+		ititv = iRa = iRb = iRc = iRd = iRe = iRf = 0;
+		ipinvI = ishapeG = ipinvIG = ishapeIG = 0;
+
+		for (Model tmodel : confidenceModels) {
+
+			weight = getWeight(tmodel) / cumWeight;
+			partition = tmodel.getPartition();
+
+			/* base frequencies */
+			if (tmodel.ispF()) {
+				ifA += weight;
+				ifC += weight;
+				ifG += weight;
+				ifT += weight;
+			}
+
+			/* substitution rates */
+			if (tmodel.ispT()) {
+				ikappa += weight;
+				ititv += weight;
+			} else if (tmodel.ispR()) {
+				if (partition.charAt(0) != partition.charAt(5))
+					iRa += weight;
+				if (partition.charAt(1) != partition.charAt(5))
+					iRb += weight;
+				if (partition.charAt(2) != partition.charAt(5))
+					iRc += weight;
+				if (partition.charAt(3) != partition.charAt(5))
+					iRd += weight;
+				if (partition.charAt(4) != partition.charAt(5))
+					iRe += weight;
+				iRf += weight;
+			}
+
+			/* rate variation */
+			if (tmodel.ispI() && !tmodel.ispG()) {
+				ipinvI += weight;
+			} else if (!tmodel.ispI() && tmodel.ispG()) {
+				ishapeG += weight;
+			} else if (tmodel.ispI() && tmodel.ispG()) {
+				ipinvIG += weight;
+				ishapeIG += weight;
+			}
+		}
+	}
+
+	/************************************************************
+	 * averageModels
+	 * 
+	 * Calculates the model averaged estimates
+	 * 
+	 * Assumes K81,TrN,TIM,TVMSIM, GRT estimate all rate parametes Ra-Rf
+	 * 
+	 * for a given parameter, weight is rescaled by parameter importance
+	 ***********************************************************/
+
+	public void averageModels() {
+
+		double weight, minWeight, NA;
+		String partition;
+
+		afA = afG = afC = afT = 0;
+		atitv = akappa = aRa = aRb = aRc = aRd = aRe = aRf = 0;
+		apinvI = ashapeG = apinvIG = ashapeIG = 0;
+
+		NA = Utilities.NA;
+		minWeight = getWeight(models[order[numModels - 1]]);
+
+		for (Model tmodel : confidenceModels) {
+
+			weight = getWeight(tmodel) / cumWeight; // because importance is
+													// already reescaled by
+													// cumWeight
+			partition = tmodel.getPartition();
+
+			/* base frequencies */
+			if (tmodel.ispF()) {
+				if (ifA >= minWeight)
+					afA += tmodel.getfA() * weight / ifA;
+				if (ifC >= minWeight)
+					afC += tmodel.getfC() * weight / ifC;
+				if (ifG >= minWeight)
+					afG += tmodel.getfG() * weight / ifG;
+				if (ifT >= minWeight)
+					afT += tmodel.getfT() * weight / ifT;
+			}
+
+			/* substitution rates */
+			if (tmodel.ispT()) {
+				if (ikappa >= minWeight)
+					akappa += tmodel.getKappa() * weight / ikappa;
+				if (ititv >= minWeight)
+					atitv += tmodel.getTitv() * weight / ititv;
+			} else if (tmodel.ispR()) {
+				if (partition.charAt(0) != partition.charAt(5)
+						&& iRa >= minWeight)
+					aRa += tmodel.getRa() * weight / iRa;
+				if (partition.charAt(1) != partition.charAt(5)
+						&& iRb >= minWeight)
+					aRb += tmodel.getRb() * weight / iRb;
+				if (partition.charAt(2) != partition.charAt(5)
+						&& iRc >= minWeight)
+					aRc += tmodel.getRc() * weight / iRc;
+				if (partition.charAt(3) != partition.charAt(5)
+						&& iRd >= minWeight)
+					aRd += tmodel.getRd() * weight / iRd;
+				if (partition.charAt(4) != partition.charAt(5)
+						&& iRe >= minWeight)
+					aRe += tmodel.getRe() * weight / iRe;
+				if (iRf >= minWeight)
+					aRf += tmodel.getRf() * weight / iRf;
+
+			}
+
+			/* rate variation */
+			if (!tmodel.ispI() && tmodel.ispG()) {
+				if (ishapeG > minWeight)
+					ashapeG += tmodel.getShape() * weight / ishapeG;
+			} else if (tmodel.ispI() && !tmodel.ispG()) {
+				if (ipinvI > minWeight)
+					apinvI += tmodel.getPinv() * weight / ipinvI;
+			} else if (tmodel.ispI() && tmodel.ispG()) {
+				if (ishapeIG > minWeight)
+					ashapeIG += tmodel.getShape() * weight / ishapeIG;
+				if (ipinvIG > minWeight)
+					apinvIG += tmodel.getPinv() * weight / ipinvIG;
+			}
+		}
+
+		// make NA estimates when importance is zero (almost)
+		if (ifA < minWeight)
+			afA = NA;
+		if (ifC < minWeight)
+			afC = NA;
+		if (ifG < minWeight)
+			afG = NA;
+		if (ifT < minWeight)
+			afT = NA;
+		if (ikappa < minWeight)
+			akappa = NA;
+		if (ititv < minWeight)
+			atitv = NA;
+		if (iRa < minWeight)
+			aRa = NA;
+		if (iRb < minWeight)
+			aRb = NA;
+		if (iRc < minWeight)
+			aRc = NA;
+		if (iRd < minWeight)
+			aRd = NA;
+		if (iRe < minWeight)
+			aRe = NA;
+		if (iRf < minWeight)
+			aRf = NA;
+		if (ishapeG < minWeight)
+			ashapeG = NA;
+		if (ipinvI < minWeight)
+			apinvI = NA;
+		if (ishapeIG < minWeight)
+			ashapeIG = NA;
+		if (ipinvIG < minWeight)
+			apinvIG = NA;
+	}
+
+	public double getAfA() {
+		return afA;
+	}
+
+	public double getIfA() {
+		return ifA;
+	}
+
+	public double getIfG() {
+		return ifG;
+	}
+
+	public double getIshapeIG() {
+		return ishapeIG;
+	}
+
+	public double getIpinvIG() {
+		return ipinvIG;
+	}
+
+	public double getIshapeG() {
+		return ishapeG;
+	}
+
+	public double getIpinvI() {
+		return ipinvI;
+	}
+
+	public double getiRf() {
+		return iRf;
+	}
+
+	public double getiRe() {
+		return iRe;
+	}
+
+	public double getiRd() {
+		return iRd;
+	}
+
+	public double getiRc() {
+		return iRc;
+	}
+
+	public double getiRb() {
+		return iRb;
+	}
+
+	public double getiRa() {
+		return iRa;
+	}
+
+	public double getIkappa() {
+		return ikappa;
+	}
+
+	public double getItitv() {
+		return ititv;
+	}
+
+	public double getIfT() {
+		return ifT;
+	}
+
+	public double getIfC() {
+		return ifC;
+	}
+
+	public double getAfG() {
+		return afG;
+	}
+
+	public double getAshapeIG() {
+		return ashapeIG;
+	}
+
+	public double getApinvIG() {
+		return apinvIG;
+	}
+
+	public double getAshapeG() {
+		return ashapeG;
+	}
+
+	public double getApinvI() {
+		return apinvI;
+	}
+
+	public double getaRf() {
+		return aRf;
+	}
+
+	public double getaRe() {
+		return aRe;
+	}
+
+	public double getaRd() {
+		return aRd;
+	}
+
+	public double getaRc() {
+		return aRc;
+	}
+
+	public double getaRb() {
+		return aRb;
+	}
+
+	public double getaRa() {
+		return aRa;
+	}
+
+	public double getAkappa() {
+		return akappa;
+	}
+
+	public double getAtitv() {
+		return atitv;
+	}
+
+	public double getAfT() {
+		return afT;
+	}
+
+	public double getAfC() {
+		return afC;
+	}
+
+	public Model getMinModel() {
+		return minModel;
+	}
+
+	@Override
+	public String toString() {
+		switch (getType()) {
+		case IC_AIC:
+			return "AIC";
+		case IC_BIC:
+			return "BIC";
+		case IC_AICc:
+			return "AICc";
+		case IC_DT:
+			return "DT";
+		}
+		return null;
+	}
+
+	public Model getModel(int i) {
+		return models[order[i]];
+	}
+
+	public void print(TextOutputStream stream) {
+		int i, j;
+		String criterion = names[getType()];
+
+		printHeader(stream);
+
+		stream.println(" ");
+		stream.println(" Model selected: ");
+		getMinModel().print(stream);
+
+		// print PAUP* block
+		if (writePAUPblock)
+			ModelTest.WritePaupBlock(stream, criterion, minModel);
+
+		// print ML tree for best-fit model
+		stream.println(" ");
+		stream.println("Tree for the best " + criterion + " model = "
+				+ minModel.getTreeString());
+
+		// update unconstrained model
+		if (unconstrainedModel != null) {
+			unconstrainedModel.setLnL(minModel.getUnconstrainedLnL());
+		}
+
+		// print weights
+		stream.println(" ");
+		stream.println(" ");
+		stream.println("* " + criterion
+				+ " MODEL SELECTION : Selection uncertainty");
+		stream.println(" ");
+		stream.printf(
+				"Model             -lnL    K     %4s       delta       weight   cumWeight",
+				criterion);
+		if (doCheckAgainstULK && minModel.getUnconstrainedLnL() > 1e-10) {
+			stream.println("       uDelta");
+		} else {
+			stream.println("");
+		}
+		stream.print("-------------------------------------------------------------------------");
+		if (doCheckAgainstULK && minModel.getUnconstrainedLnL() > 1e-10) {
+			stream.print("-------------");
+		}
+		for (i = 0; i < numModels; i++) {
+			j = order[i];
+			// j = i;
+			stream.println(" ");
+			stream.printf("%-10s", models[j].getName());
+			stream.printf("  %10.5f", models[j].getLnL());
+			if (options.countBLasParameters)
+				stream.printf("   %2d", models[j].getK());
+			else
+				stream.printf("  %2d",
+						models[j].getK() - options.getNumBranches());
+			stream.printf("  %10.6f", getValue(models[j]));
+			stream.printf("  %9.6f", getDelta(models[j]));
+			if (getWeight(models[j]) > 0.0001)
+				stream.printf("   %9.6f", getWeight(models[j]));
+			else
+				stream.printf("   %4.2e", getWeight(models[j]));
+			stream.printf("   %7.6f", getCumWeight(models[j]));
+			if (doCheckAgainstULK && minModel.getUnconstrainedLnL() > 1e-10) {
+				if (!options.isAmbiguous()) {
+					stream.printf("   %10.4f", getUDelta(models[j]));
+				} else if (i == 0) {
+					stream.printf("   %10.4f", setUDelta(models[j]));
+				} else {
+					stream.print("            -");
+				}
+			}
+		}
+		stream.print("\n-------------------------------------------------------------------------");
+		if (doCheckAgainstULK && minModel.getUnconstrainedLnL() > 1e-10) {
+			stream.print("-------------");
+		}
+		stream.println("");
+		printFooter(stream);
+
+		Utilities.toConsoleEnd();
+
+		// indicate table availability
+		if (ModelTest.buildGUI) {
+			stream.println("\nModel selection results also available at the \"Model > Show model table\" menu");
+			Utilities.toConsoleEnd();
+		}
+
+		// print confidence set
+		stream.println(" ");
+		stream.println(" ");
+		stream.println("* " + criterion
+				+ " MODEL SELECTION : Confidence interval");
+		stream.println(" ");
+		stream.print("There are " + confidenceModels.size() + " models in the ");
+		stream.printf("%.0f% ", confidenceInterval * 100);
+		stream.print("confidence interval: [ ");
+		for (Model m : confidenceModels) {
+			stream.print(m.getName() + " ");
+		}
+		stream.println("] ");
+
+		// print parameter importances
+		if (doImportances) {
+			stream.println(" ");
+			stream.println(" ");
+			stream.println("* " + criterion
+					+ " MODEL SELECTION : Parameter importance");
+			stream.println(" ");
+			stream.println("Parameter   Importance");
+			stream.print("----------------------");
+			if (options.doF) {
+				stream.printf("\nfA\t%10.4f", ifA);
+				stream.printf("\nfC\t%10.4f", ifC);
+				stream.printf("\nfG\t%10.4f", ifG);
+				stream.printf("\nfT\t%10.4f", ifT);
+			}
+			stream.printf("\nkappa\t%10.4f", ikappa);
+			stream.printf("\ntitv\t%10.4f", ititv);
+			stream.printf("\nrAC\t%10.4f", iRa);
+			stream.printf("\nrAG\t%10.4f", iRb);
+			stream.printf("\nrAT\t%10.4f", iRc);
+			stream.printf("\nrCG\t%10.4f", iRd);
+			stream.printf("\nrCT\t%10.4f", iRe);
+			stream.printf("\nrGT\t%10.4f", iRf);
+			if (options.doI)
+				stream.printf("\npinv(I)\t%10.4f", ipinvI);
+			if (options.doG)
+				stream.printf("\nalpha(G)\t%10.4f", ishapeG);
+			if (options.doI && options.doG) {
+				stream.printf("\npinv(IG)\t%10.4f", ipinvIG);
+				stream.printf("\nalpha(IG)\t%10.4f", ishapeIG);
+			}
+			stream.println("\n----------------------");
+			stream.println("Values have been rounded.");
+			stream.println(" (I):  considers only +I models.");
+			stream.println(" (G):  considers only +G models.");
+			stream.println(" (IG): considers only +I+G models.");
+		}
+
+		// print model averaging
+		if (doModelAveraging) {
+			stream.println(" ");
+			stream.println(" ");
+			stream.println("* " + criterion
+					+ " MODEL SELECTION : Model averaged estimates");
+			stream.println(" ");
+			stream.println("           Model-averaged");
+			stream.println("Parameter       estimates");
+			stream.print("-------------------------");
+			if (options.doF) {
+				stream.printf("\nfA\t%13s", Utilities.checkNA(afA));
+				stream.printf("\nfC\t%13s", Utilities.checkNA(afC));
+				stream.printf("\nfG\t%13s", Utilities.checkNA(afG));
+				stream.printf("\nfT\t%13s", Utilities.checkNA(afT));
+			}
+			stream.printf("\nkappa\t%13s", Utilities.checkNA(akappa));
+			stream.printf("\ntitv\t%13s", Utilities.checkNA(atitv));
+			stream.printf("\nrAC\t%13s", Utilities.checkNA(aRa));
+			stream.printf("\nrAG\t%13s", Utilities.checkNA(aRb));
+			stream.printf("\nrAT\t%13s", Utilities.checkNA(aRc));
+			stream.printf("\nrCG\t%13s", Utilities.checkNA(aRd));
+			stream.printf("\nrCT\t%13s", Utilities.checkNA(aRe));
+			stream.printf("\nrGT\t%13s", Utilities.checkNA(aRf));
+			if (options.doI)
+				stream.printf("\npinv(I)\t%13s", Utilities.checkNA(apinvI));
+			if (options.doG)
+				stream.printf("\nalpha(G)\t%13s", Utilities.checkNA(ashapeG));
+			if (options.doI && options.doG) {
+				stream.printf("\npinv(IG)\t%13s", Utilities.checkNA(apinvIG));
+				stream.printf("\nalpha(IG)\t%13s", Utilities.checkNA(ashapeIG));
+			}
+			stream.println("\n-------------------------");
+			stream.println("Numbers have been rounded.");
+			stream.println(" (I):  considers only +I models.");
+			stream.println(" (G):  considers only +G models.");
+			stream.println(" (IG): considers only +I+G models.");
+		}
+
+		stream.println(" ");
+		stream.println(" ");
+		stream.println("* " + criterion
+				+ " MODEL SELECTION : Best Model's command line");
+		stream.println(" ");
+		stream.println("phyml "
+				+ PhymlSingleModel.writePhyml3CommandLine(getMinModel(), false,
+						options, false, -1));
+		if (getValue(minModel) < 0.0) {
+			stream.println(" ");
+			stream.println("WARNING! Criterion has zero or negative values. Please check whether your sample size is big enough compared to the number of parameters (K)");
+		}
+	}
+
+	public int getNumModels() {
+		return numModels;
+	}
+
+	public boolean isValid() {
+		return validResults;
+	}
+	
+	public abstract void compute();
+
+	public abstract double computeSingle(Model model);
+
+	// public abstract void print (TextOutputStream stream);
+	public abstract void buildConfidenceInterval();
+
+	public abstract double getMinModelValue();
+
+	public abstract double getMinModelWeight();
+
+	public abstract double getValue(Model m);
+
+	public abstract double getDelta(Model m);
+
+	public abstract double getUDelta(Model m);
+
+	public abstract double setUDelta(Model m);
+
+	public abstract double getWeight(Model m);
+
+	public abstract double getCumWeight(Model m);
+
+	protected abstract void printHeader(TextOutputStream stream);
+
+	protected abstract void printFooter(TextOutputStream stream);
+
+	public abstract int getType();
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/statistics/Statistics.java b/src/main/java/es/uvigo/darwin/jmodeltest/statistics/Statistics.java
new file mode 100644
index 0000000..6184452
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/statistics/Statistics.java
@@ -0,0 +1 @@
+/*
Copyright (C) 2011  Diego Darriba, David Posada

This program 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.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package es.uvigo.darwin.jmodeltest.statistics;


public class Statistics 
	{

	public Statistics() 
		{
		}

 /*************************** chiSquareProbability *************************
 *																		 	*
 *	Returns the pvalue corresponding to a given chi square value.		 	*
 * 																		 	*
 *	Adapted from: 	Hill, I. D. and Pike, M. C.  Algorithm 299 Collected 	*
 *	Algorithms 	for the CACM 1967 p. 243. Updated for rounding errors 	 	*
 *	based on remark inACM TOMS 											 	*
 *	June 1985, page 185. Found in Perlman.lib								*
 *																		 	*
 *	x: obtained chi-square value, df: degrees of freedom					*																			*
 *																		 	*
 ***************************************************************************/

	static private final double	BIGX =			20.0;							/* max value to represent exp (x) */
	static private final double	LOG_SQRT_PI =	0.5723649429247000870717135;	/* log (sqrt (pi)) */
	static private final double	I_SQRT_PI =		0.5641895835477562869480795;	/* 1 / sqrt (pi) */
	static private final double	Z_MAX =			6.0;							/* maximum meaningful z value */ 
		
	static public double chiSquareProbability (double x, int df)  
		{
		double	a, y, s;
		double	e, c, z;
		boolean	even;         /* true if df is an even number */
		
		if (x <= 0.0 || df < 1)
			return (1.0);
		
		y= 1;
		
		a = 0.5 * x;
		even = (2*(df/2)) == df;
		if (df > 1)
			y = ex (-a);
		s = (even ? y : (2.0 * normalProbability (-Math.sqrt(x))));
		if (df > 2)
			{
			x = 0.5 * (df - 1.0);
			z = (even ? 1.0 : 0.5);
			if (a > BIGX)
				{
	   		e = (even ? 0.0 : LOG_SQRT_PI);
				c = Math.log (a);
				while (z <= x)
					{
					e = Math.log (z) + e;
					s += ex (c*z-a-e);
					z += 1.0;
					}
				return (s);
				}
			else
				{
				e = (even ? 1.0 : (I_SQRT_PI / Math.sqrt (a)));
				c = 0.0;
				while (z <= x)
					{
					e = e * (a / z);
					c = c + e;
					z += 1.0;
					}
				return (c * y + s);
				}
			}
		else
			return (s);
		}

		


 /*************************** normalProbability *************************
 *																		 	*
 *	Returns the probability that a standard normal is less thana given	 	*
 * 		z standard normal value											 	*
 *	
 *   Cumulative distribution function										*
 *																		 	*
 *	Adapted from a polynomial approximation in: Ibbetson D, Algorithm 209	*	
 *	Collected Algorithms of the CACM 1963 p. 616							*
 *	This routine has six digit accuracy, so it is only useful for absolute	*
 *	z values < 6.  For z values >= to 6.0, normalProbability() returns 1.0.	*
 *																		 	*
 *																		 	*
 ***************************************************************************/
		
	static private double normalProbability (double z)        /* VAR returns cumulative probability from -oo to z VAR normal z value */
		{	
		double 	y, x, w;
		
		if (z == 0.0)
			x = 0.0;
		else
			{
			y = 0.5 * Math.abs(z);
			if (y >= (Z_MAX * 0.5))
				x = 1.0;
			else if (y < 1.0)
				{
				w = y*y;
				x = ((((((((0.000124818987 * w
					-0.001075204047) * w +0.005198775019) * w
					-0.019198292004) * w +0.059054035642) * w
					-0.151968751364) * w +0.319152932694) * w
					-0.531923007300) * w +0.797884560593) * y * 2.0;
				}
			else
				{
				y -= 2.0;
				x = (((((((((((((-0.000045255659 * y
					+0.000152529290) * y -0.000019538132) * y
					-0.000676904986) * y +0.001390604284) * y
					-0.000794620820) * y -0.002034254874) * y
					+0.006549791214) * y -0.010557625006) * y
					+0.011630447319) * y -0.009279453341) * y
					+0.005353579108) * y -0.002141268741) * y
						+0.000535310849) * y +0.999936657524;
					}
				}
		return (z > 0.0 ? ((x + 1.0) * 0.5) : ((1.0 - x) * 0.5));	
		}




/**************************** ex ***************************************
 *																		*
 *	Resturns exp(X) or 0 if x is too small								*					
 *																		*
 ************************************************************************/

	static private final double	ex (double x)
		{
		return (((x) < -BIGX) ? 0.0 : Math.exp (x));   
		}


} // class Statistics
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/threads/SwingWorker.java b/src/main/java/es/uvigo/darwin/jmodeltest/threads/SwingWorker.java
new file mode 100755
index 0000000..62937f4
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/threads/SwingWorker.java
@@ -0,0 +1 @@
+/*
Copyright (C) 2011  Diego Darriba, David Posada

This program 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.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package es.uvigo.darwin.jmodeltest.threads;

import javax.swing.SwingUtilities;

public abstract class SwingWorker {
    private Object value;  // see getValue(), setValue()

    /** 
     * Class to maintain reference to current worker thread
     * under separate synchronization control.
     */
    private static class ThreadVar {
        private Thread thread;
        ThreadVar(Thread t) { thread = t; }
        synchronized Thread get() { return thread; }
        synchronized void clear() { thread = null; }
    }

    private ThreadVar threadVar;

    /** 
     * Get the value produced by the worker thread, or null if it 
     * hasn't been constructed yet.
     */
    protected synchronized Object getValue() { 
        return value; 
    }

    /** 
     * Set the value produced by worker thread 
     */
    private synchronized void setValue(Object x) { 
        value = x; 
    }

    /** 
     * Compute the value to be returned by the <code>get</code> method. 
     */
    public abstract Object construct();

    /**
     * Called on the event dispatching thread (not on the worker thread)
     * after the <code>construct</code> method has returned.
     */
    public void finished() {
    }

    /**
     * A new method that interrupts the worker thread.  Call this method
     * to force the worker to stop what it's doing.
     */
    public void interrupt() {
        Thread t = threadVar.get();
        if (t != null) {
            t.interrupt();
        }
        threadVar.clear();
    }

    /**
     * Return the value created by the <code>construct</code> method.  
     * Returns null if either the constructing thread or the current
     * thread was interrupted before a value was produced.
     * 
     * @return the value created by the <code>construct</code> method
     */
    public Object get() {
        while (true) {  
            Thread t = threadVar.get();
            if (t == null) {
                return getValue();
            }
            try {
                t.join();
            }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // propagate
                return null;
            }
        }
    }


    /**
     * Start a thread that will call the <code>construct</code> method
     * and then exit.
     */
    public SwingWorker() {
        final Runnable doFinished = new Runnable() {
           public void run() { finished(); }
        };

        Runnable doConstruct = new Runnable() { 
            public void run() {
                try {
                    setValue(construct());
                }
                finally {
                    threadVar.clear();
                }

                SwingUtilities.invokeLater(doFinished);
            }
        };

        Thread t = new Thread(doConstruct);
        threadVar = new ThreadVar(t);
    }

    /**
     * Start the worker thread.
     */
    public void start() {
        Thread t = threadVar.get();
        if (t != null) {
            t.start();
        }
    }
}
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeDistancesCache.java b/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeDistancesCache.java
new file mode 100755
index 0000000..a4b3a9b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeDistancesCache.java
@@ -0,0 +1,146 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.tree;
+
+import java.util.Hashtable;
+
+import pal.tree.Tree;
+
+/**
+ * Caches the distances between every couple of trees in a set. This is
+ * useful for instance when a tree-distance-based algorithm is computed
+ * many times, like the Decision Theory Information Criterion.
+ * 
+ * This cache support both euclidean and RF distances.
+ * 
+ * @author Diego Darriba López
+ * 
+ * @since 3.0
+ */
+public class TreeDistancesCache {
+
+    /** Constant of the euclidean distances */
+    public static final int EUCLIDEAN = 1;
+    /** Constant of the RF distances */
+    public static final int ROBINSON_FOULDS = 2;
+    /** Cache hash table coupling each pair of trees with its distance */
+    private Hashtable<TreePair, Double> distances;
+    /** Sort of computed distance */
+    private int distanceType;
+
+    /**
+     * Gets the distance type.
+     * 
+     * @return the sort of distance, according to the defined constants
+     */
+    public int getDistanceType() {
+        return distanceType;
+    }
+
+    /**
+     * Instantiates a new tree distances cache.
+     * 
+     * @param distanceType sort of distance to compute
+     */
+    public TreeDistancesCache(int distanceType) {
+
+        if (distanceType != EUCLIDEAN && distanceType != ROBINSON_FOULDS) {
+            //TODO: EXCEPTION!!!
+        }
+        this.distanceType = distanceType;
+        distances = new Hashtable<TreePair, Double>();
+
+    }
+
+    /**
+     * Gets the distance between two trees
+     * 
+     * @param t1 the first tree
+     * @param t2 the second tree
+     * 
+     * @return the distance
+     */
+    public double getDistance(Tree t1, Tree t2) {
+        double distance = 0.0;
+        TreePair tp = new TreePair(t1, t2);
+        if (distances.containsKey(tp)) {
+            distance = distances.get(tp);
+        } else {
+            switch (distanceType) {
+                case EUCLIDEAN:
+                	distance = TreeUtilities.getEuclideanTreeDistance(t1, t2);
+                    break;
+                case ROBINSON_FOULDS:
+                    distance = TreeUtilities.getRobinsonFouldsTreeDistance(t1, t2); 
+                    break;
+            }
+            distances.put(tp, distance);
+        }
+        return distance;
+    }
+
+    /**
+     * This class represents a pair of trees
+     */
+    private class TreePair {
+
+        private Tree t1,  t2;
+
+        public TreePair(Tree t1, Tree t2) {
+            this.t1 = t1;
+            this.t2 = t2;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + getOuterType().hashCode();
+            result = prime * result + ((t1 == null) ? 0 : t1.hashCode());
+            result = prime * result + ((t2 == null) ? 0 : t2.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            TreePair other = (TreePair) obj;
+            if (!getOuterType().equals(other.getOuterType())) {
+                return false;
+            }
+            // assume not null members
+            boolean checkB, checkA;
+            checkA = (t1.equals(other.t1) && t2.equals(other.t2));
+            checkB = (t1.equals(other.t2) && t2.equals(other.t1));
+
+            return checkA || checkB;
+        }
+
+        private TreeDistancesCache getOuterType() {
+            return TreeDistancesCache.this;
+        }
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeEuclideanDistancesCache.java b/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeEuclideanDistancesCache.java
new file mode 100755
index 0000000..650132f
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeEuclideanDistancesCache.java
@@ -0,0 +1,44 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.tree;
+
+/**
+ * This class is a distances cache implementing the euclidean distance
+ * 
+ * @author Diego Darriba
+ * 
+ * @since 3.0
+ */
+public class TreeEuclideanDistancesCache extends TreeDistancesCache {
+
+	private static TreeEuclideanDistancesCache instance;
+	
+	private TreeEuclideanDistancesCache() {
+		super(EUCLIDEAN);
+	}
+	
+	public static TreeEuclideanDistancesCache getInstance() {
+		
+		if (instance == null)
+			instance = new TreeEuclideanDistancesCache();
+		return instance;
+		
+	}
+
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeRFDistancesCache.java b/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeRFDistancesCache.java
new file mode 100644
index 0000000..931ecf7
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeRFDistancesCache.java
@@ -0,0 +1,44 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.tree;
+
+/**
+ * This class is a distances cache implementing the euclidean distance
+ * 
+ * @author Diego Darriba
+ * 
+ * @since 3.0
+ */
+public class TreeRFDistancesCache extends TreeDistancesCache {
+
+	private static TreeRFDistancesCache instance;
+	
+	private TreeRFDistancesCache() {
+		super(ROBINSON_FOULDS);
+	}
+	
+	public static TreeRFDistancesCache getInstance() {
+		
+		if (instance == null)
+			instance = new TreeRFDistancesCache();
+		return instance;
+		
+	}
+
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeSummary.java b/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeSummary.java
new file mode 100644
index 0000000..67a74b0
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeSummary.java
@@ -0,0 +1,405 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.tree;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Hashtable;
+import java.util.List;
+
+import pal.tree.Tree;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.utilities.Utilities;
+
+public class TreeSummary {
+
+	private int AIC_INDEX = 0;
+	private int AICC_INDEX = 1;
+	private int BIC_INDEX = 2;
+	private int DT_INDEX = 3;
+	// number of Information Criteria
+	private int IC_COUNT = 4;
+
+	private Tree bestTree[] = new Tree[IC_COUNT];
+	private TreeDistancesCache rfDistances = TreeRFDistancesCache.getInstance();
+	private TreeDistancesCache euclideanDistances = TreeEuclideanDistancesCache
+			.getInstance();
+	private Hashtable<Tree, SummaryRow> summary;
+	// sorted topologies by criterion
+	private List<Tree> topologiesAIC = null, topologiesAICc = null,
+			topologiesBIC = null, topologiesDT = null, sortedTopologies = null;
+
+	public TreeSummary(Tree bestAIC, Tree bestAICc, Tree bestBIC, Tree bestDT,
+			Model[] models) {
+		if (bestAIC != null) {
+			this.bestTree[AIC_INDEX] = bestAIC;
+			this.topologiesAIC = new ArrayList<Tree>();
+		}
+		if (bestAICc != null) {
+			this.bestTree[AICC_INDEX] = bestAICc;
+			this.topologiesAICc = new ArrayList<Tree>();
+		}
+		if (bestBIC != null) {
+			this.bestTree[BIC_INDEX] = bestBIC;
+			this.topologiesBIC = new ArrayList<Tree>();
+		}
+		if (bestDT != null) {
+			this.bestTree[DT_INDEX] = bestDT;
+			this.topologiesDT = new ArrayList<Tree>();
+		}
+		this.summary = new Hashtable<Tree, SummaryRow>();
+
+		for (Model model : models) {
+			boolean done = false;
+			for (Tree tree : summary.keySet()) {
+				if (sameTopology(tree, model.getTree())) {
+					summary.get(tree).addModel(model);
+					done = true;
+					break;
+				}
+			}
+			if (!done) {
+				// new topology
+				SummaryRow newRow = new SummaryRow(model.getTree());
+				newRow.addModel(model);
+				summary.put(model.getTree(), newRow);
+				if (topologiesAIC != null)
+					topologiesAIC.add(model.getTree());
+				if (topologiesAICc != null)
+					topologiesAICc.add(model.getTree());
+				if (topologiesBIC != null)
+					topologiesBIC.add(model.getTree());
+				if (topologiesDT != null)
+					topologiesDT.add(model.getTree());
+			}
+		}
+
+		for (Tree tree : summary.keySet()) {
+			summary.get(tree).computeEuclideanDistances();
+		}
+		// sort by criteria
+		if (topologiesAIC != null)
+			Collections.sort(topologiesAIC, new AicComparator());
+		if (topologiesAICc != null)
+			Collections.sort(topologiesAICc, new AiccComparator());
+		if (topologiesBIC != null)
+			Collections.sort(topologiesBIC, new BicComparator());
+		if (topologiesDT != null)
+			Collections.sort(topologiesDT, new DtComparator());
+		
+		sortedTopologies = topologiesAIC != null ? topologiesAIC
+				: topologiesBIC != null ? topologiesBIC
+						: topologiesAICc != null ? topologiesAICc
+								: topologiesDT != null ? topologiesDT
+									: new ArrayList<Tree>(summary.keySet());
+	}
+
+	public int getNumberOfTopologies() {
+		return summary.size();
+	}
+
+	public Tree getTopology (int index) {
+		return sortedTopologies.get(index);
+	}
+	
+	public List<Model> getModelsByTopology (int index) {
+		return summary.get(getTopology(index)).models;
+	}
+	
+	public List<Model> getAICModels(int index) {
+		Tree key = topologiesAIC.get(index);
+		return summary.get(key).models;
+	}
+
+	public List<Model> getBICModels(int index) {
+		Tree key = topologiesBIC.get(index);
+		return summary.get(key).models;
+	}
+
+	public List<Model> getAICcModels(int index) {
+		Tree key = topologiesAICc.get(index);
+		return summary.get(key).models;
+	}
+
+	public List<Model> getDTModels(int index) {
+		Tree key = topologiesDT.get(index);
+		return summary.get(key).models;
+	}
+
+	public int aicIndexOf(Tree tree) {
+		return topologiesAIC.indexOf(tree);
+	}
+
+	public long aicRfOf(Tree tree) {
+		return summary.get(tree).rfDistance[AIC_INDEX];
+	}
+	
+	public double aicAvgDistance(Tree tree) {
+		return summary.get(tree).avgEuclideanDistance[AIC_INDEX];
+	}
+	
+	public double aicVarDistance(Tree tree) {
+		return summary.get(tree).varEuclideanDistance[AIC_INDEX];
+	}
+	
+	public double aiccWeight(Tree tree) {
+		return summary.get(tree).support[AICC_INDEX];
+	}
+	
+	public int aiccIndexOf(Tree tree) {
+		return topologiesAICc.indexOf(tree);
+	}
+
+	public long aiccRfOf(Tree tree) {
+		return summary.get(tree).rfDistance[AICC_INDEX];
+	}
+	
+	public double aiccAvgDistance(Tree tree) {
+		return summary.get(tree).avgEuclideanDistance[AICC_INDEX];
+	}
+	
+	public double aiccVarDistance(Tree tree) {
+		return summary.get(tree).varEuclideanDistance[AICC_INDEX];
+	}
+	
+	public double aicWeight(Tree tree) {
+		return summary.get(tree).support[AIC_INDEX];
+	}
+	
+	public int bicIndexOf(Tree tree) {
+		return topologiesBIC.indexOf(tree);
+	}
+
+	public long bicRfOf(Tree tree) {
+		return summary.get(tree).rfDistance[BIC_INDEX];
+	}
+	
+	public double bicAvgDistance(Tree tree) {
+		return summary.get(tree).avgEuclideanDistance[BIC_INDEX];
+	}
+	
+	public double bicVarDistance(Tree tree) {
+		return summary.get(tree).varEuclideanDistance[BIC_INDEX];
+	}
+	
+	public double bicWeight(Tree tree) {
+		return summary.get(tree).support[BIC_INDEX];
+	}
+	
+	public int dtIndexOf(Tree tree) {
+		return topologiesDT.indexOf(tree);
+	}
+
+	public long dtRfOf(Tree tree) {
+		return summary.get(tree).rfDistance[DT_INDEX];
+	}
+	
+	public double dtAvgDistance(Tree tree) {
+		return summary.get(tree).avgEuclideanDistance[DT_INDEX];
+	}
+	
+	public double dtVarDistance(Tree tree) {
+		return summary.get(tree).varEuclideanDistance[DT_INDEX];
+	}
+	
+	public double dtWeight(Tree tree) {
+		return summary.get(tree).support[DT_INDEX];
+	}
+	
+	private boolean sameTopology(Tree t1, Tree t2) {
+		return (rfDistances.getDistance(t1, t2) == 0);
+	}
+
+	private long rfDistance(Tree t1, Tree t2) {
+		if (t1 == null || t2 == null) {
+			return -1;
+		} else {
+			return Math.round(rfDistances.getDistance(t1, t2));
+		}
+	}
+
+	class SummaryRow {
+		List<Model> models;
+		Tree commonTopology;
+		long rfDistance[] = new long[] { 0l, 0l, 0l, 0l };
+		double avgEuclideanDistance[] = new double[] { 0.0d, 0.0d, 0.0d, 0.0d };
+		double varEuclideanDistance[] = new double[] { 0.0d, 0.0d, 0.0d, 0.0d };
+		double support[] = new double[] { 0.0d, 0.0d, 0.0d, 0.0d };
+
+		SummaryRow(Tree commonTopology) {
+			this.commonTopology = commonTopology;
+			for (int i = 0; i < IC_COUNT; i++) {
+				this.rfDistance[i] = rfDistance(commonTopology, bestTree[i]);
+			}
+			this.models = new ArrayList<Model>();
+		}
+
+		void addModel(Model model) {
+			// check same topology
+			if (checkTopology(model)) {
+				models.add(model);
+				support[AIC_INDEX] += model.getAICw();
+				support[AICC_INDEX] += model.getAICcw();
+				support[BIC_INDEX] += model.getBICw();
+				support[DT_INDEX] += model.getDTw();
+			}
+		}
+
+		void computeEuclideanDistances() {
+			// set variables to zero
+			for (int i = 0; i < IC_COUNT; i++) {
+				if (bestTree[i] != null) {
+					avgEuclideanDistance[i] = 0.0d;
+					varEuclideanDistance[i] = 0.0d;
+					for (Model model : models) {
+						double distance = euclideanDistances.getDistance(
+								model.getTree(), bestTree[i]);
+						avgEuclideanDistance[i] += distance;
+						varEuclideanDistance[i] += distance * distance;
+					}
+					avgEuclideanDistance[i] /= models.size();
+					varEuclideanDistance[i] /= models.size();
+					varEuclideanDistance[i] -= avgEuclideanDistance[i]
+							* avgEuclideanDistance[i];
+				}
+			}
+		}
+
+		boolean checkTopology(Model model) {
+			return (rfDistances.getDistance(commonTopology, model.getTree()) == 0);
+		}
+	}
+
+	class AicComparator implements Comparator<Tree> {
+
+		@Override
+		public int compare(Tree o1, Tree o2) {
+			long d1 = rfDistance(o1, bestTree[AIC_INDEX]);
+			long d2 = rfDistance(o2, bestTree[AIC_INDEX]);
+			return (int) (d1 - d2);
+		}
+
+	}
+
+	class AiccComparator implements Comparator<Tree> {
+
+		@Override
+		public int compare(Tree o1, Tree o2) {
+			long d1 = rfDistance(o1, bestTree[AICC_INDEX]);
+			long d2 = rfDistance(o2, bestTree[AICC_INDEX]);
+			return (int) (d1 - d2);
+		}
+
+	}
+
+	class BicComparator implements Comparator<Tree> {
+
+		@Override
+		public int compare(Tree o1, Tree o2) {
+			long d1 = rfDistance(o1, bestTree[BIC_INDEX]);
+			long d2 = rfDistance(o2, bestTree[BIC_INDEX]);
+			return (int) (d1 - d2);
+		}
+
+	}
+
+	class DtComparator implements Comparator<Tree> {
+
+		@Override
+		public int compare(Tree o1, Tree o2) {
+			long d1 = rfDistance(o1, bestTree[DT_INDEX]);
+			long d2 = rfDistance(o2, bestTree[DT_INDEX]);
+			return (int) (d1 - d2);
+		}
+
+	}
+
+	public void print(TextOutputStream stream) {
+		int MAX_LEN = 80;
+		if (topologiesAIC != null || topologiesBIC != null
+				|| topologiesAICc != null || topologiesDT != null) {
+			List<Tree> sortedTopologies = topologiesAIC != null ? topologiesAIC
+					: topologiesBIC != null ? topologiesBIC
+							: topologiesAICc != null ? topologiesAICc
+									: topologiesDT;
+			stream.println("::Optimized Topologies Summary::");
+			stream.println("");
+			stream.println("There are " + getNumberOfTopologies()
+					+ " different topologies.");
+			stream.println("");
+			for (int i = 0; i < getNumberOfTopologies(); i++) {
+				int index = i + 1;
+				Tree currentTree = sortedTopologies.get(i);
+
+				SummaryRow summaryRow = summary.get(currentTree);
+
+				int aicIndex = topologiesAIC != null ? aicIndexOf(currentTree) + 1
+						: -1;
+				int aiccIndex = topologiesAICc != null ? aiccIndexOf(currentTree) + 1
+						: -1;
+				int bicIndex = topologiesBIC != null ? bicIndexOf(currentTree) + 1
+						: -1;
+				int dtIndex = topologiesDT != null ? dtIndexOf(currentTree) + 1
+						: -1;
+				stream.println("Topology Id: " + index);
+				stream.println("\tRank\tWeight\t\t RF\tAvgEucl\t\tVarEucl");
+				if (topologiesAIC != null) {
+						stream.println(getIcRow("AIC", aicIndex, summaryRow, AIC_INDEX));
+				}
+				if (topologiesBIC != null) {
+					stream.println(getIcRow("BIC", bicIndex, summaryRow, BIC_INDEX));
+				}
+				if (topologiesAICc != null) {
+					stream.println(getIcRow("AICc", aiccIndex, summaryRow, AICC_INDEX));
+				}
+				if (topologiesDT != null) {
+					stream.println(getIcRow("DT", dtIndex, summaryRow, DT_INDEX));
+				}
+				stream.println("Models supporting:   "
+						+ summaryRow.models.size());
+
+				stream.print("                     ");
+				int chars = 0;
+				for (Model model : summaryRow.models) {
+					if (chars >= MAX_LEN) {
+						stream.println("");
+						stream.print("                     ");
+						chars = 0;
+					}
+					stream.print(model.getName() + " ");
+					chars += model.getName().length() + 1;
+				}
+				stream.println("");
+				stream.println("");
+			}
+		}
+	}
+	
+	private String getIcRow(String name, int rankIndex, SummaryRow summaryRow, int criterionIndex) {
+		return name + "\t"
+				+ Utilities.format(rankIndex,3,0,false)
+				+ "\t"
+				+ Utilities
+						.asPercent(summaryRow.support[criterionIndex] * 100)
+				+ "\t\t" + Utilities.format(summaryRow.rfDistance[criterionIndex],3,0,false)
+				+ "\t" + Utilities.format(summaryRow.avgEuclideanDistance[criterionIndex],8,2,true)
+				+ "\t" + Utilities.format(summaryRow.varEuclideanDistance[criterionIndex],8,2,true);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeUtilities.java b/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeUtilities.java
new file mode 100644
index 0000000..7b54e98
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/tree/TreeUtilities.java
@@ -0,0 +1,170 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.tree;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import pal.io.FormattedOutput;
+import pal.misc.IdGroup;
+import pal.tree.Node;
+import pal.tree.ReadTree;
+import pal.tree.SplitSystem;
+import pal.tree.SplitUtils;
+import pal.tree.Tree;
+import pal.tree.TreeParseException;
+
+public class TreeUtilities {
+
+	public static final String TREE_CLADE_SUPPORT_ATTRIBUTE = "support";
+
+	public TreeUtilities() {
+	}
+
+	/****************************
+	 * readTree ********************************** * Reads a tree in Newick
+	 * format, rooted or unroored, binary or with * polytomies, and with or
+	 * without branch lengths. Returns the root * node *
+	 * 
+	 * @throws IOException
+	 * @throws TreeParseException
+	 *             *
+	 ************************************************************************/
+
+	public static Tree readTree(String treefilename) throws IOException,
+			TreeParseException {
+		Tree tree;
+		try {
+			tree = new ReadTree(treefilename);
+		} catch (TreeParseException e) {
+			throw e;
+		} catch (IOException e) {
+			throw e;
+		}
+		return tree;
+	}
+
+	public static void printNH(PrintWriter out, Tree tree, Node node,
+			boolean printLengths, boolean printInternalLabels,
+			boolean printCladeSupport) {
+
+		if (!node.isLeaf()) {
+			out.print("(");
+
+			for (int i = 0; i < node.getChildCount(); i++) {
+				if (i != 0) {
+					out.print(",");
+				}
+
+				printNH(out, tree, node.getChild(i), printLengths,
+						printInternalLabels, printCladeSupport);
+			}
+
+			out.print(")");
+		}
+
+		if (!node.isRoot()) {
+			if (node.isLeaf() || printInternalLabels) {
+
+				String id = node.getIdentifier().toString();
+				out.print(id);
+			}
+
+			if (printCladeSupport) {
+				if (tree.getAttribute(node, TREE_CLADE_SUPPORT_ATTRIBUTE) != null) {
+					double support = (Double) tree.getAttribute(node,
+							TREE_CLADE_SUPPORT_ATTRIBUTE);
+					out.printf(":" + FormattedOutput.getInstance().getDecimalString(support, 4));
+				}
+			}
+
+			if (printLengths) {
+				out.printf(":" + FormattedOutput.getInstance().getDecimalString(node.getBranchLength(), 10));
+			}
+		}
+
+	}
+
+	public static String toNewick(Tree tree, boolean printLengths,
+			boolean printInternalLabels, boolean printCladeSupport) {
+
+		StringWriter sw = new StringWriter();
+		PrintWriter mp = new PrintWriter(sw);
+
+		printNH(mp, tree, tree.getRoot(), printLengths, printInternalLabels,
+				printCladeSupport);
+
+		sw.append(';');
+		return sw.toString();
+	}
+
+	public static double getEuclideanTreeDistance(Tree t1, Tree t2) {
+		double sum = 0.0;
+        int numberOfInternalNodes = t1.getInternalNodeCount();
+        if (numberOfInternalNodes != t2.getInternalNodeCount()) {
+            throw new RuntimeException("Different number of internal nodes: " +
+                    t1.getInternalNodeCount() + " vs " + t2.getInternalNodeCount());
+        }
+        int numberOfExternalNodes = t1.getExternalNodeCount();
+        if (numberOfExternalNodes != t2.getExternalNodeCount()) {
+            throw new RuntimeException("Different number of external nodes: " +
+                    t1.getInternalNodeCount() + " vs " + t2.getInternalNodeCount());
+        }
+        for (int i = 0; i < numberOfInternalNodes; i++) {
+            double bl1 = t1.getInternalNode(i).getBranchLength();
+            double bl2 = t2.getInternalNode(i).getBranchLength();
+            sum += (bl1 - bl2) * (bl1 - bl2);
+        }
+        for (int i = 0; i < numberOfExternalNodes; i++) {
+            double bl1 = t1.getExternalNode(i).getBranchLength();
+            double bl2 = t2.getExternalNode(i).getBranchLength();
+            sum += (bl1 - bl2) * (bl1 - bl2);
+        }
+        return Math.sqrt(sum);
+	}
+	
+	public static double getRobinsonFouldsTreeDistance(Tree t1, Tree t2) {
+		SplitSystem s1 = SplitUtils.getSplits(t1);
+		IdGroup idGroup = s1.getIdGroup();
+		SplitSystem s2 = SplitUtils.getSplits(idGroup, t2);
+
+		if (s1.getLabelCount() != s2.getLabelCount())
+			throw new IllegalArgumentException("Number of labels must be the same!");
+
+		int ns1 = s1.getSplitCount();
+		int ns2 = s2.getSplitCount();
+
+		// number of splits in t1 missing in t2
+		int fn = 0;
+		for (int i = 0; i < ns1; i++)
+		{
+			if (!s2.hasSplit(s1.getSplit(i))) fn++;
+		}
+
+		// number of splits in t2 missing in t1
+		int fp = 0;
+		for (int i = 0; i < ns2; i++)
+		{
+			if (!s1.hasSplit(s2.getSplit(i))) fp++;
+		}
+
+
+		return ((double) fp + (double) fn);
+	}
+} // end of class
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/utilities/InitialFocusSetter.java b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/InitialFocusSetter.java
new file mode 100644
index 0000000..999dd63
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/InitialFocusSetter.java
@@ -0,0 +1,42 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.utilities;
+
+import java.awt.Component;
+import java.awt.Window;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+ public class InitialFocusSetter {
+        public static void setInitialFocus(Window w, Component c) {
+            w.addWindowListener(new FocusSetter(c));
+        }
+    
+        public static class FocusSetter extends WindowAdapter {
+            Component initComp;
+            FocusSetter(Component c) {
+                initComp = c;
+            }
+            public void windowOpened(WindowEvent e) {
+                initComp.requestFocus();
+    
+                // Since this listener is no longer needed, remove it
+                e.getWindow().removeWindowListener(this);
+            }
+        }
+    }
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/utilities/ModelDef.java b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/ModelDef.java
new file mode 100644
index 0000000..2ba3e25
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/ModelDef.java
@@ -0,0 +1,60 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.utilities;
+
+import es.uvigo.darwin.jmodeltest.model.Model;
+
+public class ModelDef {
+
+	final String name;
+	final String partition;
+	final boolean equalFreqs;
+	final boolean equalRates[];
+	
+	ModelDef(Model model) {
+		this.name = model.getName();
+		this.equalFreqs = !model.ispF();
+		this.partition = model.getPartition();
+		this.equalRates = new boolean[] { 
+				checkRates(0,1), checkRates(0,2), checkRates(0,3),
+				checkRates(0,4), checkRates(0,5), checkRates(1,2),
+				checkRates(1,3), checkRates(1,4), checkRates(1,5),
+				checkRates(2,3), checkRates(2,4), checkRates(2,5),
+				checkRates(3,4), checkRates(3,5), checkRates(4,5)};
+	}
+
+	private boolean checkRates(int p0, int p1) {
+		return partition.charAt(p0) == partition.charAt(p1);
+	}
+	public String getName() {
+		return name;
+	}
+
+	public boolean isEqualFreqs() {
+		return equalFreqs;
+	}
+
+	public boolean isEqualRate(int aaPair) {
+		return equalRates[aaPair];
+	}
+
+	public boolean isName(String name) {
+		//!name.contains("\\+") || 
+		return name.split("\\+")[0].equals(this.name);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/utilities/MyTableCellRenderer.java b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/MyTableCellRenderer.java
new file mode 100644
index 0000000..2484bcd
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/MyTableCellRenderer.java
@@ -0,0 +1,87 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.utilities;
+
+import java.awt.Color;
+import java.awt.Component;
+
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableCellRenderer;
+
+import es.uvigo.darwin.jmodeltest.ModelTest;
+
+/************************* MyTableCellRenderer  ********************************/
+/* This class formats the cells in the table
+I use this class to highlight the selected model by every criteria */
+
+public class MyTableCellRenderer extends DefaultTableCellRenderer { 
+
+	private static final long serialVersionUID = 8637781802600263981L;
+
+	private JTable whichTable;
+	private Object whichValue, val;
+	private String whichTableName;
+	
+	public MyTableCellRenderer (JTable mTable, String mTableName)
+		{
+		whichTable = mTable;
+		whichTableName = mTableName;
+		}
+	
+	public Component getTableCellRendererComponent (JTable table, Object value,
+		boolean isSelected, boolean hasFocus, int row, int column)
+		{
+		setOpaque(true);
+		setText(value.toString());
+		// set cell's foreground to default cell foreground color
+		setForeground(table.getForeground()); 
+
+		if (whichTableName.equals("AIC"))
+			whichValue = new Integer(ModelTest.getMinAIC().getId());
+		else if (whichTableName.equals("AICc"))
+			whichValue = new Integer(ModelTest.getMinAICc().getId());
+		else if (whichTableName.equals("BIC"))
+			whichValue = new Integer(ModelTest.getMinBIC().getId());
+		else if (whichTableName.equals("DT"))
+			whichValue = new Integer(ModelTest.getMinDT().getId());
+		else
+			whichValue = new Integer(0);	
+						
+		val = whichTable.getValueAt(row, 0);
+		// if cell is selected, set background color to default cell selection background color
+		if (isSelected) 
+			{
+			setBackground(table.getSelectionBackground());
+			}
+		// otherwise, set cell background color to some custom color
+		else
+			{
+			// set rows background to some color
+			if (val.equals(whichValue))
+				{
+				setForeground(Color.red);
+				}
+			// set even rows background to white
+			else
+				{ 
+				setForeground(Color.black);
+				}
+			}
+		return this;
+		}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/utilities/MyTableModel.java b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/MyTableModel.java
new file mode 100644
index 0000000..c60b829
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/MyTableModel.java
@@ -0,0 +1,292 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.utilities;
+
+import java.math.BigDecimal;
+
+import javax.swing.table.AbstractTableModel;
+
+import es.uvigo.darwin.jmodeltest.ModelTest;
+
+/************************* MyTableModel ********************************/
+/* This class fills in the data in the table */
+
+public class MyTableModel extends AbstractTableModel {
+
+	private static final long serialVersionUID = -8310097889316872278L;
+
+	int i;
+
+	final String[] columnNamesModel = { "ID", "Name", "Partition", "-lnL", "p",
+			"fA", "fC", "fG", "fT", "ti/tv", "R(a)", "R(b)", "R(c)", "R(d)",
+			"R(e)", "R(f)", "p-inv", "shape"};
+	final String[] columnNamesAIC = { "ID", "Name", "Partition", "-lnL", "p",
+			"AIC", "deltaAIC", "weight", "cumWeight", "uDelta" };
+
+	final String[] columnNamesAICc = { "ID", "Name", "Partition", "-lnL", "p",
+			"AICc", "deltaAICc", "weight", "cumWeight", "uDelta" };
+
+	final String[] columnNamesBIC = { "ID", "Name", "Partition", "-lnL", "p",
+			"BIC", "deltaBIC", "weight", "cumWeight", "uDelta" };
+
+	final String[] columnNamesDT = { "ID", "Name", "Partition", "-lnL", "p",
+			"DT", "deltaDT", "weight", "cumWeight", "-" };
+
+	private String[] columnNames;
+	private Object[][] data;
+	private int size;
+
+	public MyTableModel(String whichTable, int size) {
+		this.size = size;
+		int precision = ModelTest.PRECISION;
+
+		if (whichTable.equals("Model")) {
+			columnNames = columnNamesModel;
+			data = new Object[size][18];
+			for (i = 0; i < size; i++) {
+				data[i][0] = new Integer(
+						ModelTest.getCandidateModels()[i].getId());
+				data[i][1] = ModelTest.getCandidateModels()[i].getName();
+				data[i][2] = ModelTest.getCandidateModels()[i].getPartition();
+				data[i][3] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getLnL(), precision));
+				data[i][4] = new Integer(
+						ModelTest.getCandidateModels()[i].getK());
+
+				if (ModelTest.getCandidateModels()[i].ispF()) {
+					data[i][5] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getfA(),
+							precision));
+					data[i][6] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getfC(),
+							precision));
+					data[i][7] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getfG(),
+							precision));
+					data[i][8] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getfT(),
+							precision));
+				} else {
+					data[i][5] = "-";
+					data[i][6] = "-";
+					data[i][7] = "-";
+					data[i][8] = "-";
+				}
+
+				if (ModelTest.getCandidateModels()[i].ispT())
+					data[i][9] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getTitv(),
+							precision));
+				else
+					data[i][9] = "-";
+
+				if (ModelTest.getCandidateModels()[i].ispR()) {
+					data[i][10] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getRa(), 6));
+					data[i][11] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getRb(), 6));
+					data[i][12] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getRc(), 6));
+					data[i][13] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getRd(), 6));
+					data[i][14] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getRe(), 6));
+					data[i][15] = new Double(1);
+				} else {
+					data[i][10] = "-";
+					data[i][11] = "-";
+					data[i][12] = "-";
+					data[i][13] = "-";
+					data[i][14] = "-";
+					data[i][15] = "-";
+				}
+
+				if (ModelTest.getCandidateModels()[i].ispI()) {
+						data[i][16] = Utilities.format(ModelTest.getCandidateModels()[i].getPinv(), precision+2, precision, false);
+				} else {
+					data[i][16] = "-";
+				}
+
+				if (ModelTest.getCandidateModels()[i].ispG()) {
+					if (ModelTest.getCandidateModels()[i].getShape() != ModelTest.INFINITY) {
+						data[i][17] = Utilities.format(ModelTest.getCandidateModels()[i].getShape(), precision+2, precision, false);
+					} else {
+						data[i][17] = "inf";
+					}
+				} else {
+					data[i][17] = "-";
+				}
+				
+			}
+		} else if (whichTable.equals("AIC")) {
+			columnNames = columnNamesAIC;
+			data = new Object[size][10];
+		} else if (whichTable.equals("AICc")) {
+			columnNames = columnNamesAICc;
+			data = new Object[size][10];
+		} else if (whichTable.equals("BIC")) {
+			columnNames = columnNamesBIC;
+			data = new Object[size][10];
+		} else if (whichTable.equals("DT")) {
+			columnNames = columnNamesDT;
+			data = new Object[size][10];
+		}
+	}
+
+	public int getColumnCount() {
+		return columnNames.length;
+	}
+
+	public int getRowCount() {
+		return data.length;
+	}
+
+	public String getColumnName(int col) {
+		return columnNames[col];
+	}
+
+	public Object getValueAt(int row, int col) {
+		return data[row][col];
+	}
+
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public Class getColumnClass(int c) {
+		return getValueAt(0, c).getClass();
+	}
+
+	public double Round(double number, int decimalPlace) {
+		double returnValue = number;
+		if (!(Double.isNaN(number) || Double.isInfinite(number))) {
+			BigDecimal bd = new BigDecimal(number);
+			bd = bd.setScale(decimalPlace, BigDecimal.ROUND_HALF_UP);
+			returnValue = bd.doubleValue();
+		}
+		return (returnValue);
+	}
+
+	public void populate(String whichTable) {
+		int precision = ModelTest.PRECISION;
+
+		if (whichTable.equals("AIC")) {
+			for (i = 0; i < size; i++) {
+				data[i][0] = new Integer(
+						ModelTest.getCandidateModels()[i].getId());
+				data[i][1] = ModelTest.getCandidateModels()[i].getName();
+				data[i][2] = ModelTest.getCandidateModels()[i].getPartition();
+				data[i][3] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getLnL(), precision));
+				data[i][4] = new Integer(
+						ModelTest.getCandidateModels()[i].getK());
+				data[i][5] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getAIC(), precision));
+				data[i][6] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getAICd(), precision));
+				data[i][7] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getAICw(), precision));
+				data[i][8] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getCumAICw(),
+						precision));
+				if (ModelTest.getCandidateModels()[i].getUnconstrainedLnL() > 0.0d) {
+					data[i][9] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getUAICd(),
+							precision));
+				} else {
+					data[i][9] = "-";
+				}
+			}
+		} else if (whichTable.equals("AICc")) {
+			for (i = 0; i < size; i++) {
+				data[i][0] = new Integer(
+						ModelTest.getCandidateModels()[i].getId());
+				data[i][1] = ModelTest.getCandidateModels()[i].getName();
+				data[i][2] = ModelTest.getCandidateModels()[i].getPartition();
+				data[i][3] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getLnL(), precision));
+				data[i][4] = new Integer(
+						ModelTest.getCandidateModels()[i].getK());
+				data[i][5] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getAICc(), precision));
+				data[i][6] = new Double(
+						Round(ModelTest.getCandidateModels()[i].getAICcd(),
+								precision));
+				data[i][7] = new Double(
+						Round(ModelTest.getCandidateModels()[i].getAICcw(),
+								precision));
+				data[i][8] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getCumAICcw(),
+						precision));
+				if (ModelTest.getCandidateModels()[i].getUnconstrainedLnL() > 0.0d) {
+					data[i][9] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getUAICcd(),
+							precision));
+				} else {
+					data[i][9] = "-";
+				}
+			}
+		} else if (whichTable.equals("BIC")) {
+			for (i = 0; i < size; i++) {
+				data[i][0] = new Integer(
+						ModelTest.getCandidateModels()[i].getId());
+				data[i][1] = ModelTest.getCandidateModels()[i].getName();
+				data[i][2] = ModelTest.getCandidateModels()[i].getPartition();
+				data[i][3] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getLnL(), precision));
+				data[i][4] = new Integer(
+						ModelTest.getCandidateModels()[i].getK());
+				data[i][5] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getBIC(), precision));
+				data[i][6] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getBICd(), precision));
+				data[i][7] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getBICw(), 4));
+				data[i][8] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getCumBICw(),
+						precision));
+				if (ModelTest.getCandidateModels()[i].getUnconstrainedLnL() > 0.0d) {
+					data[i][9] = new Double(Round(
+							ModelTest.getCandidateModels()[i].getUBICd(),
+							precision));
+				} else {
+					data[i][9] = "-";
+				}
+			}
+		} else if (whichTable.equals("DT")) {
+			for (i = 0; i < size; i++) {
+				data[i][0] = new Integer(
+						ModelTest.getCandidateModels()[i].getId());
+				data[i][1] = ModelTest.getCandidateModels()[i].getName();
+				data[i][2] = ModelTest.getCandidateModels()[i].getPartition();
+				data[i][3] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getLnL(), precision));
+				data[i][4] = new Integer(
+						ModelTest.getCandidateModels()[i].getK());
+				data[i][5] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getDT(), precision));
+				data[i][6] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getDTd(), precision));
+				data[i][7] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getDTw(), 4));
+				data[i][8] = new Double(Round(
+						ModelTest.getCandidateModels()[i].getCumDTw(),
+						precision));
+				data[i][9] = "";
+			}
+		}
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/utilities/PrintUtilities.java b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/PrintUtilities.java
new file mode 100644
index 0000000..4877d67
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/PrintUtilities.java
@@ -0,0 +1,101 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.utilities;
+
+/*
+ * http://www.developerdotstar.com/community/node/124/print
+ * http://www.apl.jhu.edu/~hall/java/Swing-Tutorial/Swing-Tutorial-Printing.html
+ *
+ * And also from a post on the forums at java.swing.com. My apologies that do not have
+ * a link to that post, by my hat goes off to the poster because he/she figured out the
+ * sticky problem of paging properly when printing a Swing component.
+ */
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+
+import javax.swing.RepaintManager;
+
+public class PrintUtilities implements Printable {
+  private Component componentToBePrinted;
+  
+  public static void printComponent(Component c) {
+    new PrintUtilities(c).print();
+  }
+  
+  public PrintUtilities(Component componentToBePrinted) {
+    this.componentToBePrinted = componentToBePrinted;
+  }
+  
+  public void print() {
+    PrinterJob printJob = PrinterJob.getPrinterJob();
+    printJob.setPrintable(this);
+    if (printJob.printDialog())
+      try {
+        printJob.print();
+      }
+      catch (PrinterException pe) {
+        System.err.println("Error printing: " + pe);
+      }
+  }
+
+  public int print(Graphics g, PageFormat pf, int pageIndex) {
+    int response = NO_SUCH_PAGE;
+    Graphics2D g2 = (Graphics2D) g;
+    // for faster printing, turn off double buffering
+    disableDoubleBuffering(componentToBePrinted);
+    Dimension d = componentToBePrinted.getSize(); //get size of document
+    double panelWidth = d.width; //width in pixels
+    double panelHeight = d.height; //height in pixels
+    double pageHeight = pf.getImageableHeight(); //height of printer page
+    double pageWidth = pf.getImageableWidth(); //width of printer page
+    double scale = pageWidth / panelWidth;
+    int totalNumPages = (int) Math.ceil(scale * panelHeight / pageHeight);
+    // make sure not print empty pages
+    if (pageIndex >= totalNumPages) {
+      response = NO_SUCH_PAGE;
+    }
+    else {
+      // shift Graphic to line up with beginning of print-imageable region
+      g2.translate(pf.getImageableX(), pf.getImageableY());
+      // shift Graphic to line up with beginning of next page to print
+      g2.translate(0f, -pageIndex * pageHeight);
+      // scale the page so the width fits...
+      g2.scale(scale, scale);
+      componentToBePrinted.paint(g2); //repaint the page for printing
+      enableDoubleBuffering(componentToBePrinted);
+      response = Printable.PAGE_EXISTS;
+    }
+    return response;
+  }
+
+  public static void disableDoubleBuffering(Component c) {
+    RepaintManager currentManager = RepaintManager.currentManager(c);
+    currentManager.setDoubleBufferingEnabled(false);
+  }
+
+  public static void enableDoubleBuffering(Component c) {
+    RepaintManager currentManager = RepaintManager.currentManager(c);
+    currentManager.setDoubleBufferingEnabled(true);
+  }
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/utilities/Simulation.java b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/Simulation.java
new file mode 100644
index 0000000..6901d8d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/Simulation.java
@@ -0,0 +1,491 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+package es.uvigo.darwin.jmodeltest.utilities;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.PushbackReader;
+import java.io.StringReader;
+import java.util.Arrays;
+import java.util.Locale;
+
+import pal.tree.Tree;
+import pal.tree.TreeParseException;
+import es.uvigo.darwin.jmodeltest.ApplicationOptions;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.ModelTestService;
+import es.uvigo.darwin.jmodeltest.exe.RunConsense;
+import es.uvigo.darwin.jmodeltest.exe.RunPhyml;
+import es.uvigo.darwin.jmodeltest.exe.RunPhymlThread;
+import es.uvigo.darwin.jmodeltest.io.AlignmentReader;
+import es.uvigo.darwin.jmodeltest.io.TextOutputStream;
+import es.uvigo.darwin.jmodeltest.model.Model;
+import es.uvigo.darwin.jmodeltest.observer.ConsoleProgressObserver;
+import es.uvigo.darwin.jmodeltest.selection.AIC;
+import es.uvigo.darwin.jmodeltest.selection.AICc;
+import es.uvigo.darwin.jmodeltest.selection.BIC;
+import es.uvigo.darwin.jmodeltest.selection.DT;
+import es.uvigo.darwin.jmodeltest.selection.HLRT;
+import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
+import es.uvigo.darwin.jmodeltest.tree.TreeUtilities;
+
+public class Simulation {
+	private ApplicationOptions options;
+	
+	private static final double nil = -99999;
+
+	private static final String AIC = "AIC";
+	private static final String AICc = "AICc";
+	private static final String BIC = "BIC";
+	private static final String DT = "DT";
+	private static final String[] IC_TYPES = { AIC, AICc, BIC, DT };
+
+	public Simulation(ApplicationOptions options) {
+		this.options = options;
+	}
+
+	/*************************
+	 * runSimulations ****************************** * Organizes all the tasks
+	 * that the program needs to carry out * * *
+	 ***********************************************************************/
+	public void run() {
+		int i;
+		boolean append;
+		/*
+		 * .trees: base trees for every model in standard orden
+		 * 
+		 * .AIC_tre: best tree for the AIC model .AIC_mmi_mtre: model averaged
+		 * AIC tree (50% majority rule) .AIC_mmi_atre: model averaged AIC tree
+		 * (strict) ... same for AICc, BIC and DT
+		 * 
+		 * .parms: parameter estimates for every model in standard orden
+		 * .AIC_parms: parameter estimates for the AIC model .AIC_imp_parms:
+		 * parameter importances obtained with the AIC .AIC_mmi_parms: parameter
+		 * importances obtained with the AIC ... same for AICc, BIC and DT
+		 */
+
+		// make simulation directories
+		String simdir = "sims/";
+		new File(simdir).mkdir();
+
+		String outdir = simdir + "out/";
+		new File(outdir).mkdir();
+
+		String treedir = simdir + "trees/";
+		new File(treedir).mkdir();
+
+		String parmdir = simdir + "parameters/";
+		new File(parmdir).mkdir();
+
+		String simsName = options.simulationsName;
+
+		if (options.getInputFile().getName().endsWith("001")
+				|| options.getInputFile().getName().endsWith("001.phy")
+				|| options.getInputFile().getName().endsWith("001.dat"))
+			append = false;
+		else
+			append = true;
+
+		// outfiles
+		TextOutputStream outConsole = ModelTest.setMainConsole(new TextOutputStream(
+				outdir + simsName + ".out", append));
+		TextOutputStream treeConsole = new TextOutputStream(treedir + simsName
+				+ ".trees", append);
+		TextOutputStream parameterConsole = new TextOutputStream(parmdir
+				+ simsName + ".parms", append);
+
+		// print header information
+		ModelTest.printHeader(outConsole);
+
+		// print notice information
+		// printNotice(outConsole);
+
+		// check expiration date
+		// CheckExpiration (outConsole);
+
+		// print the command line
+		outConsole.print("\nArguments =");
+		for (i = 0; i < ModelTest.arguments.length; i++)
+			outConsole.print(" " + ModelTest.arguments[i]);
+
+		// open data file
+		File file = options.getInputFile();
+		outConsole.print("\n\nReading data file \"" + file.getName()
+				+ "\"...");
+
+		if (file.exists()) {
+			try {
+
+//				File outputFile = File
+//						.createTempFile("jmodeltest", "input.aln");
+				String alnStr = ModelTestService.readAlignment(file, options.getAlignmentFile());
+
+				PushbackReader pr = new PushbackReader(
+						new StringReader(alnStr));
+				options.setAlignment(AlignmentReader.createAlignment(
+						new PrintWriter(System.err),
+						pr, 
+						true)); // file
+
+				outConsole.println(" OK.");
+				outConsole.println("  number of sequences: "
+						+ options.getNumTaxa());
+				outConsole.println("  number of sites: " + options.getNumSites());
+			} catch (Exception e)// file cannot be read correctly
+			{
+				System.err.println("\nThe specified file \""
+						+ file.getName()
+						+ "\" cannot be read as an alignment");
+				outConsole.println(" failed.\n");
+				System.exit(0);
+			}
+		} else // file does not exist
+		{
+			System.err.println("\nThe specified file \""
+					+ file.getName() + "\" cannot be found");
+			outConsole.println(" failed.\n");
+			System.exit(0);
+		}
+
+		// open tree file if necessary
+		if (options.userTopologyExists) {
+			File treefile = options.getTreeFile();
+			options.setInputTreeFile(file);
+			outConsole.print("Reading tree file \"" + treefile.getName()
+					+ "\"...");
+
+			// read the tree in
+			Tree tree = null;
+			try {
+				tree = TreeUtilities.readTree(treefile.getAbsolutePath());
+			} catch (IOException e) {
+				System.err.println("\nThe specified tree file \""
+						+ treefile.getName() + "\" cannot be found");
+				outConsole.println(" failed.\n");
+				System.exit(0);
+			} catch (TreeParseException e) {
+				System.err.println("\nThe specified file \""
+						+ treefile.getName()
+						+ "\" cannot be read as valid Newick tree");
+				outConsole.println(" failed.\n");
+				System.exit(0);
+			}
+			if (tree != null) {
+				options.setUserTree(TreeUtilities.toNewick(tree, true,
+						false, false));
+				TextOutputStream out = new TextOutputStream(
+						options.getTreeFile().getAbsolutePath());
+				out.print(TreeUtilities.toNewick(tree, true, false, false));
+				out.close();
+				outConsole.println(" OK.");
+			}
+
+		}
+
+		// print some progress
+		System.err.print("Doing \"" + file.getName() + "\" ... ");
+
+		// calculate number of models
+		if (options.getSubstTypeCode() == 0)
+			options.setNumModels(3);
+		else if (options.getSubstTypeCode() == 1)
+			options.setNumModels(5);
+		else if (options.getSubstTypeCode() == 2)
+			options.setNumModels(7);
+		else
+			options.setNumModels(11);
+
+		if (options.doF)
+			options.setNumModels(options.getNumModels() * 2);
+
+		if (options.doI && options.doG)
+			options.setNumModels(options.getNumModels() * 4);
+		else if (options.doI || options.doG)
+			options.setNumModels(options.getNumModels() * 2);
+
+		// build set of models
+		options.setCandidateModels();
+
+		// calculate likelihoods with phyml in the command line
+		RunPhyml phymlrun = new RunPhymlThread(new ConsoleProgressObserver(options), options, ModelTest.getCandidateModels());
+		phymlrun.execute();
+
+		// print all model trees to tree file and parameters to parms file
+		if (!append)
+			parameterConsole
+					.println("data\tname\tln\tK\tfA\tfC\tfG\tfT\tkappa\ttitv\trAC\tAG\trAT\trCG\trCT\trGT\tpinvI\tshapeG\tpinvIG\tshapeIG");
+		for (i = 0; i < options.getNumModels(); i++) {
+			treeConsole.println(options.getInputFile().getName() + "\t"
+					+ ModelTest.getCandidateModels()[i].getName() + "\t"
+					+ ModelTest.getCandidateModels()[i].getTreeString());
+			printModelLine(
+					ModelTest.getCandidateModels()[i],
+					parameterConsole,
+					options.getInputFile().getName() + "\t"
+							+ ModelTest.getCandidateModels()[i].getName(), nil, nil);
+		}
+
+		// do AIC if selected
+		if (options.doAIC) {
+			// TODO: oquhuh
+			printSelection("AIC", treedir, simsName, parmdir, outConsole,
+					append);
+		}
+
+		// do AICc if selected
+		if (options.doAICc) {
+			printSelection("AICc", treedir, simsName, parmdir, outConsole,
+					append);
+		}
+
+		// do BIC if selected
+		if (options.doBIC) {
+			printSelection("BIC", treedir, simsName, parmdir, outConsole,
+					append);
+		}
+
+		// do DT if selected
+		if (options.doDT) {
+			printSelection("DT", treedir, simsName, parmdir, outConsole, append);
+		}
+
+		// do hLRT if selected
+		if (options.doHLRT) {
+			HLRT myHLRT = new HLRT(options);
+			myHLRT.compute(!options.backwardHLRTSelection,
+					options.confidenceLevelHLRT, options.writePAUPblock);
+			treeConsole.println(ModelTest.averagedTreeString);
+		}
+
+		// do dLRT if selected
+		if (options.doDLRT) {
+			HLRT myHLRT = new HLRT(options);
+			myHLRT.computeDynamical(!options.backwardHLRTSelection,
+					options.confidenceLevelHLRT, options.writePAUPblock);
+		}
+
+		outConsole.println("\n=> This run has finished.\n");
+		
+		treeConsole.close();
+		
+		System.err.println("OK.");
+	}
+
+	/****************************
+	 * printModelLine *************************** * Print model components in a
+	 * tabulated format * *
+	 ************************************************************************/
+
+	public void printModelLine(Model model, TextOutputStream stream,
+			String whichName, double score, double weight) {
+
+		if (whichName == null)
+			stream.printf("%-10s", model.getName());
+		else
+			stream.printf("%-10s", whichName);
+
+		if (model.getLnL() == 0) {
+			stream.println("\tOPTIMIZATION FAILED!");
+			System.exit(0);
+		} else {
+			stream.printf("\t%.4f", model.getLnL());
+			stream.printf("\t%d", model.getK());
+
+			if (score != nil)
+				stream.printf("\t%.4f ", score);
+
+			if (weight != nil)
+				stream.printf("\t%.4f ", weight);
+
+			if (model.ispF()) {
+				stream.printf("\t%.4f ", model.getfA());
+				stream.printf("\t%.4f ", model.getfC());
+				stream.printf("\t%.4f ", model.getfG());
+				stream.printf("\t%.4f ", model.getfT());
+			} else
+				stream.print("\t-\t-\t-\t-");
+
+			if (model.ispT()) {
+				stream.printf("\t%.4f", model.getKappa());
+				stream.printf("\t%.4f", model.getTitv());
+			} else
+				stream.print("\t-\t-");
+
+			if (model.ispR()) {
+				stream.printf("\t%.4f", model.getRa());
+				stream.printf("\t%.4f", model.getRb());
+				stream.printf("\t%.4f", model.getRc());
+				stream.printf("\t%.4f", model.getRd());
+				stream.printf("\t%.4f", model.getRe());
+				stream.printf("\t%.4f", 1.0);
+			} else
+				stream.print("\t-\t-\t-\t-\t-\t-");
+
+			if (model.ispI() && model.ispG()) {
+				stream.printf("\t-\t-\t%.4f", model.getPinv());
+				stream.printf("\t%.4f", model.getShape());
+			} else if (model.ispI())
+				stream.printf("\t%.4f\t-\t-\t-", model.getPinv());
+			else if (model.ispG())
+				stream.printf("\t-\t%.4f\t-\t-", model.getShape());
+			else
+				stream.print("\t-\t-\t-\t-");
+
+			stream.println(" ");
+		}
+	}
+
+	/*************************
+	 * CheckNAsim ********************************* * Returns formatted value or
+	 * NA symbol depending on variable status * * *
+	 ***********************************************************************/
+
+	public static String CheckNAsim(double value) {
+		if (value == Utilities.NA)
+			return "-";
+		else {
+			String s = String.format(Locale.ENGLISH, "%.4f", value);
+			return s;
+		}
+	}
+
+	public void printSelection(String icType, String treedir, String simsName,
+			String parmdir, TextOutputStream outConsole, boolean append) {
+
+		// Validate
+		if (!Arrays.asList(IC_TYPES).contains(icType)) {
+			// TODO: EXCEPTION!
+		}
+
+		TextOutputStream ICtre = new TextOutputStream(treedir + simsName + "."
+				+ icType + "_tre", append);
+		TextOutputStream IC_mmi_mtre = new TextOutputStream(treedir + simsName
+				+ "." + icType + "_mmi_mtre", append);
+		TextOutputStream IC_mmi_atre = new TextOutputStream(treedir + simsName
+				+ "." + icType + "_mmi_atre", append);
+
+		TextOutputStream IC_parms = new TextOutputStream(parmdir + simsName
+				+ "." + icType + "_parms", append);
+		TextOutputStream IC_imp_parms = new TextOutputStream(parmdir + simsName
+				+ "." + icType + "_imp_parms", append);
+		TextOutputStream IC_mmi_parms = new TextOutputStream(parmdir + simsName
+				+ "." + icType + "_mmi_parms", append);
+
+		InformationCriterion ic;
+		if (icType.equals(AIC)) {
+			ic = new AIC(options.writePAUPblock, options.doImportances,
+					options.doModelAveraging, options.confidenceInterval);
+		} else if (icType.equals("AICc")) {
+			ic = new AICc(options.writePAUPblock, options.doImportances,
+					options.doModelAveraging, options.confidenceInterval);
+		} else if (icType.equals("BIC")) {
+			ic = new BIC(options.writePAUPblock, options.doImportances,
+					options.doModelAveraging, options.confidenceInterval);
+		} else if (icType.equals("DT")) {
+			ic = new DT(options.writePAUPblock, options.doImportances,
+					options.doModelAveraging, options.confidenceInterval);
+		} else {
+			ic = null;
+			// TODO: EXCEPTION!!!
+		}
+
+		ic.compute();
+		ic.print(outConsole);
+		if (icType.equals(AIC)) {
+			ModelTest.setMyAIC((AIC) ic);
+		} else if (icType.equals("AICc")) {
+			ModelTest.setMyAICc((AICc) ic);
+		} else if (icType.equals("BIC")) {
+			ModelTest.setMyBIC((BIC) ic);
+		} else if (icType.equals("DT")) {
+			ModelTest.setMyDT((DT) ic);
+		}
+
+		ICtre.println(ic.getMinModel().getTreeString());
+		if (!append)
+			IC_parms.print("data\tname\tln\tK\tscore\tweigth\tfA\tfC\tfG\tfT\tkappa\ttitv\trAC\tAG\trAT\trCG\trCT\trGT\tpinvI\tshapeG\tpinvIG\tshapeIG\n");
+		printModelLine(ic.getMinModel(), IC_parms, options.getInputFile().getName()
+				+ "\t" + ic.getMinModel().getName(), ic.getMinModelValue(),
+				ic.getMinModelWeight());
+
+		if (options.doAveragedPhylogeny) {
+			new RunConsense(ic,	"50% majority rule", 
+					options.confidenceInterval);
+			IC_mmi_mtre.println(ModelTest.averagedTreeString);
+			new RunConsense(ic, "strict",
+					options.confidenceInterval);
+			IC_mmi_atre.println(ModelTest.averagedTreeString);
+		}
+		if (options.doImportances) {
+			if (!append) {
+				IC_imp_parms
+						.print("data\tfA\tfC\tfG\tfT\tkappa\ttitv\trAC\tAG\trAT\trCG\trCT\trGT\tpinvI\tshapeG\tpinvIG\tshapeIG\n");
+			}
+			IC_imp_parms.print(options.getInputFile().getName());
+			IC_imp_parms.printf("\t%.4f", ic.getIfA());
+			IC_imp_parms.printf("\t%.4f", ic.getIfC());
+			IC_imp_parms.printf("\t%.4f", ic.getIfG());
+			IC_imp_parms.printf("\t%.4f", ic.getIfT());
+			IC_imp_parms.printf("\t%.4f", ic.getIkappa());
+			IC_imp_parms.printf("\t%.4f", ic.getItitv());
+			IC_imp_parms.printf("\t%.4f", ic.getiRa());
+			IC_imp_parms.printf("\t%.4f", ic.getiRb());
+			IC_imp_parms.printf("\t%.4f", ic.getiRc());
+			IC_imp_parms.printf("\t%.4f", ic.getiRd());
+			IC_imp_parms.printf("\t%.4f", ic.getiRe());
+			IC_imp_parms.printf("\t%.4f", ic.getiRf());
+			IC_imp_parms.printf("\t%.4f", ic.getIpinvI());
+			IC_imp_parms.printf("\t%.4f", ic.getIshapeG());
+			IC_imp_parms.printf("\t%.4f", ic.getIpinvIG());
+			IC_imp_parms.printf("\t%.4f", ic.getIshapeIG());
+			IC_imp_parms.println(" ");
+		}
+		if (options.doModelAveraging) {
+			if (!append) {
+				IC_mmi_parms
+						.print("data\tfA\tfC\tfG\tfT\tkappa\ttitv\trAC\tAG\trAT\trCG\trCT\trGT\tpinvI\tshapeG\tpinvIG\tshapeIG\n");
+			}
+			IC_mmi_parms.print(options.getInputFile().getName());
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getAfA()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getAfC()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getAfG()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getAfT()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getAkappa()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getAtitv()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getaRa()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getaRb()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getaRc()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getaRd()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getaRe()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getaRf()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getApinvI()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getAshapeG()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getApinvIG()));
+			IC_mmi_parms.printf("\t%s", CheckNAsim(ic.getAshapeIG()));
+			IC_mmi_parms.println(" ");
+		}
+		
+		ICtre.close();
+		IC_mmi_mtre.close();
+		IC_mmi_atre.close();
+		IC_parms.close();
+		IC_imp_parms.close();
+		IC_mmi_parms.close();
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/utilities/TableMap.java b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/TableMap.java
new file mode 100644
index 0000000..94cee1b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/TableMap.java
@@ -0,0 +1,91 @@
+/*
+Copyright (C) 1997 Philip Milne
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/** 
+ * In a chain of data manipulators some behaviour is common. TableMap
+ * provides most of this behavour and can be subclassed by filters
+ * that only need to override a handful of specific methods. TableMap 
+ * implements TableModel by routing all requests to its model, and
+ * TableModelListener by routing all events to its listeners. Inserting 
+ * a TableMap which has not been subclassed into a chain of table filters 
+ * should have no effect.
+ *
+ * @version 1.4 12/17/97
+ * @author Philip Milne */
+
+package es.uvigo.darwin.jmodeltest.utilities;
+
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+
+public class TableMap extends AbstractTableModel 
+                      implements TableModelListener {
+
+	private static final long serialVersionUID = 6058255125683787605L;
+	
+	protected TableModel model; 
+
+    public TableModel getModel() {
+        return model;
+    }
+
+    public void setModel(TableModel model) {
+        this.model = model; 
+        model.addTableModelListener(this); 
+    }
+
+    // By default, implement TableModel by forwarding all messages 
+    // to the model. 
+
+    public Object getValueAt(int aRow, int aColumn) {
+        return model.getValueAt(aRow, aColumn); 
+    }
+        
+    public void setValueAt(Object aValue, int aRow, int aColumn) {
+        model.setValueAt(aValue, aRow, aColumn); 
+    }
+
+    public int getRowCount() {
+        return (model == null) ? 0 : model.getRowCount(); 
+    }
+
+    public int getColumnCount() {
+        return (model == null) ? 0 : model.getColumnCount(); 
+    }
+        
+    public String getColumnName(int aColumn) {
+        return model.getColumnName(aColumn); 
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+	public Class getColumnClass(int aColumn) {
+        return model.getColumnClass(aColumn); 
+    }
+        
+    public boolean isCellEditable(int row, int column) { 
+         return model.isCellEditable(row, column); 
+    }
+//
+// Implementation of the TableModelListener interface, 
+//
+    // By default forward all events to all the listeners. 
+    public void tableChanged(TableModelEvent e) {
+        fireTableChanged(e);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/utilities/TableSorter.java b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/TableSorter.java
new file mode 100644
index 0000000..a2ec418
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/TableSorter.java
@@ -0,0 +1,326 @@
+/*
+Copyright (C) 1997 Philip Milne
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/**
+ * A sorter for TableModels. The sorter has a model (conforming to TableModel) 
+ * and itself implements TableModel. TableSorter does not store or copy 
+ * the data in the TableModel, instead it maintains an array of 
+ * integers which it keeps the same size as the number of rows in its 
+ * model. When the model changes it notifies the sorter that something 
+ * has changed eg. "rowsAdded" so that its internal array of integers 
+ * can be reallocated. As requests are made of the sorter (like 
+ * getValueAt(row, col) it redirects them to its model via the mapping 
+ * array. That way the TableSorter appears to hold another copy of the table 
+ * with the rows in a different order. The sorting algorthm used is stable 
+ * which means that it does not move around rows when its comparison 
+ * function returns 0 to denote that they are equivalent. 
+ *
+ * @version 1.5 12/17/97
+ * @author Philip Milne
+ */
+package es.uvigo.darwin.jmodeltest.utilities;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.swing.JTable;
+import javax.swing.event.TableModelEvent;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableModel;
+
+public class TableSorter extends TableMap {
+
+	private static final long serialVersionUID = -650033900610744016L;
+	
+	private int indexes[];
+	private List<Integer> sortingColumns = new ArrayList<Integer>();
+	private boolean ascending = true;
+    int compares;
+
+    public TableSorter() {
+        indexes = new int[0]; // for consistency
+    }
+
+    public TableSorter(TableModel model) {
+        setModel(model);
+    }
+
+    public void setModel(TableModel model) {
+        super.setModel(model); 
+        reallocateIndexes(); 
+    }
+
+    public int compareRowsByColumn(int row1, int row2, int column) {
+        @SuppressWarnings("rawtypes")
+		Class type = model.getColumnClass(column);
+        TableModel data = model;
+
+        /* Check for nulls. */
+        Object o1 = data.getValueAt(row1, column);
+        Object o2 = data.getValueAt(row2, column); 
+
+        /* If both values are null, return 0. */
+        if (o1 == null && o2 == null) {
+            return 0; 
+        } else if (o1 == null) { 
+        	/* Define null less than everything. */ 
+            return -1; 
+        } else if (o2 == null) { 
+            return 1; 
+        }
+
+        /*
+         * We copy all returned values from the getValue call in case
+         * an optimised model is reusing one object to return many
+         * values.  The Number subclasses in the JDK are immutable and
+         * so will not be used in this way but other subclasses of
+         * Number might want to do this to save space and avoid
+         * unnecessary heap allocation.
+         */
+
+        if (type.getSuperclass() == java.lang.Number.class) {
+            Number n1 = (Number)data.getValueAt(row1, column);
+            double d1 = n1.doubleValue();
+            Number n2 = (Number)data.getValueAt(row2, column);
+            double d2 = n2.doubleValue();
+
+            if (d1 < d2) {
+                return -1;
+            } else if (d1 > d2) {
+                return 1;
+            } else {
+                return 0;
+            }
+        } else if (type == java.util.Date.class) {
+            Date d1 = (Date)data.getValueAt(row1, column);
+            long n1 = d1.getTime();
+            Date d2 = (Date)data.getValueAt(row2, column);
+            long n2 = d2.getTime();
+
+            if (n1 < n2) {
+                return -1;
+            } else if (n1 > n2) {
+                return 1;
+            } else {
+                return 0;
+            }
+        } else if (type == String.class) {
+            String s1 = data.getValueAt(row1, column).toString();
+            String s2 = data.getValueAt(row2, column).toString();
+            int result = s1.compareTo(s2);
+
+            if (result < 0) {
+                return -1;
+            } else if (result > 0) {
+                return 1;
+            } else {
+                return 0;
+            }
+        } else if (type == Boolean.class) {
+            Boolean bool1 = (Boolean)data.getValueAt(row1, column);
+            boolean b1 = bool1.booleanValue();
+            Boolean bool2 = (Boolean)data.getValueAt(row2, column);
+            boolean b2 = bool2.booleanValue();
+
+            if (b1 == b2) {
+                return 0;
+            } else if (b1) { // Define false < true
+                return 1;
+            } else {
+                return -1;
+            }
+        } else {
+            Object v1 = data.getValueAt(row1, column);
+            String s1 = v1.toString();
+            Object v2 = data.getValueAt(row2, column);
+            String s2 = v2.toString();
+            int result = s1.compareTo(s2);
+
+            if (result < 0) {
+                return -1;
+            } else if (result > 0) {
+                return 1;
+            } else {
+        	return 0;
+            }
+        }
+    }
+
+    public int compare(int row1, int row2) {
+        compares++;
+        for (int column : sortingColumns) {
+            int result = compareRowsByColumn(row1, row2, column);
+            if (result != 0) {
+                return ascending ? result : -result;
+            }
+        }
+        return 0;
+    }
+
+    public void reallocateIndexes() {
+        int rowCount = model.getRowCount();
+
+        /* Set up a new array of indexes with the right number of elements
+         * for the new data model. */
+        indexes = new int[rowCount];
+
+        /* Initialise with the identity mapping. */
+        for (int row = 0; row < rowCount; row++) {
+            indexes[row] = row;
+        }
+    }
+
+    public void tableChanged(TableModelEvent e) {
+        reallocateIndexes();
+
+        super.tableChanged(e);
+    }
+
+    public void checkModel() {
+        if (indexes.length != model.getRowCount()) {
+            System.err.println("Sorter not informed of a change in model.");
+        }
+    }
+
+    public void sort(Object sender) {
+        checkModel();
+
+        compares = 0;
+        shuttlesort(indexes.clone(), indexes, 0, indexes.length);
+    }
+
+    public void n2sort() {
+        for (int i = 0; i < getRowCount(); i++) {
+            for (int j = i+1; j < getRowCount(); j++) {
+                if (compare(indexes[i], indexes[j]) == -1) {
+                    swap(i, j);
+                }
+            }
+        }
+    }
+
+     /*
+      * This is a home-grown implementation which we have not had time
+      * to research - it may perform poorly in some circumstances. It
+      * requires twice the space of an in-place algorithm and makes
+      * NlogN assigments shuttling the values between the two
+      * arrays. The number of compares appears to vary between N-1 and
+      * NlogN depending on the initial order but the main reason for
+      * using it here is that, unlike qsort, it is stable.
+      */
+    public void shuttlesort(int from[], int to[], int low, int high) {
+        if (high - low < 2) {
+            return;
+        }
+        int middle = (low + high)/2;
+        shuttlesort(to, from, low, middle);
+        shuttlesort(to, from, middle, high);
+
+        int p = low;
+        int q = middle;
+
+        /* 
+         * This is an optional short-cut; at each recursive call,
+         * check to see if the elements in this subset are already
+         * ordered.  If so, no further comparisons are needed; the
+         * sub-array can just be copied.  The array must be copied rather
+         * than assigned otherwise sister calls in the recursion might
+         * get out of sinc.  When the number of elements is three they
+         * are partitioned so that the first set, [low, mid), has one
+         * element and and the second, [mid, high), has two. We skip the
+         * optimisation when the number of elements is three or less as
+         * the first compare in the normal merge will produce the same
+         * sequence of steps. This optimisation seems to be worthwhile
+         * for partially ordered lists but some analysis is needed to
+         * find out how the performance drops to Nlog(N) as the initial
+         * order diminishes - it may drop very quickly.  
+         */
+        if (high - low >= 4 && compare(from[middle-1], from[middle]) <= 0) {
+            for (int i = low; i < high; i++) {
+                to[i] = from[i];
+            }
+            return;
+        }
+
+        // A normal merge. 
+
+        for (int i = low; i < high; i++) {
+            if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
+                to[i] = from[p++];
+            }
+            else {
+                to[i] = from[q++];
+            }
+        }
+    }
+
+    public void swap(int i, int j) {
+        int tmp = indexes[i];
+        indexes[i] = indexes[j];
+        indexes[j] = tmp;
+    }
+
+    /*The mapping only affects the contents of the data rows.
+     * Pass all requests to these rows through the mapping array: "indexes". */
+    public Object getValueAt(int aRow, int aColumn) {
+        checkModel();
+        return model.getValueAt(indexes[aRow], aColumn);
+    }
+
+    public void setValueAt(Object aValue, int aRow, int aColumn) {
+        checkModel();
+        model.setValueAt(aValue, indexes[aRow], aColumn);
+    }
+
+    public void sortByColumn(int column) {
+        sortByColumn(column, true);
+    }
+
+    public void sortByColumn(int column, boolean ascending) {
+        this.ascending = ascending;
+        sortingColumns.clear();
+        sortingColumns.add(column);
+        sort(this);
+        super.tableChanged(new TableModelEvent(this)); 
+    }
+
+    /* Add a mouse listener to the Table to trigger a table sort 
+     * when a column heading is clicked in the JTable.*/ 
+    public void addMouseListenerToHeaderInTable(JTable table) { 
+        final TableSorter sorter = this; 
+        final JTable tableView = table; 
+        tableView.setColumnSelectionAllowed(false); 
+        MouseAdapter listMouseListener = new MouseAdapter() {
+            public void mouseClicked(MouseEvent e) {
+                TableColumnModel columnModel = tableView.getColumnModel();
+                int viewColumn = columnModel.getColumnIndexAtX(e.getX()); 
+                int column = tableView.convertColumnIndexToModel(viewColumn); 
+                if (e.getClickCount() == 1 && column != -1) {
+                    int shiftPressed = e.getModifiers()&InputEvent.SHIFT_MASK; 
+                    boolean ascending = (shiftPressed == 0); 
+                    sorter.sortByColumn(column, ascending); 
+                }
+            }
+        };
+        JTableHeader th = tableView.getTableHeader(); 
+		th.addMouseListener(listMouseListener);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/jmodeltest/utilities/Utilities.java b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/Utilities.java
new file mode 100644
index 0000000..5e510e4
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/jmodeltest/utilities/Utilities.java
@@ -0,0 +1,489 @@
+/*
+Copyright (C) 2011  Diego Darriba, David Posada
+
+This program 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+package es.uvigo.darwin.jmodeltest.utilities;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
+import javax.swing.text.Document;
+
+import pal.alignment.Alignment;
+import es.uvigo.darwin.jmodeltest.ModelTest;
+import es.uvigo.darwin.jmodeltest.gui.XManager;
+
+public final class Utilities {
+
+	public static final int NA = Integer.MIN_VALUE;
+	public static final int OS_LINUX = 1;
+	public static final int OS_OSX = 2;
+	public static final int OS_WINDOWS = 3;
+
+	public Utilities() {
+	}
+
+	public static String firstNumericToken(String str) {
+		StringTokenizer st = new StringTokenizer(str);
+		String token = "";
+		boolean found = false;
+		while (st.hasMoreTokens() && !found) {
+			token = st.nextToken();
+			found |= isNumber(token);
+		}
+		if (found)
+			return token;
+		else
+			return null;
+	}
+	
+	public static String lastToken(String str) {
+		StringTokenizer st = new StringTokenizer(str);
+		String token = "";
+		while (st.hasMoreTokens()) {
+			token = st.nextToken();
+		}
+		return token;
+	}
+
+	public static boolean isWindows() {
+		if (System.getProperty("os.name").startsWith("Window"))
+			return true;
+		return false;
+	}
+
+	public static int findCurrentOS() {
+		String os = System.getProperty("os.name");
+		if (os.startsWith("Mac"))
+			return OS_OSX;
+		else if (os.startsWith("Windows"))
+			return OS_WINDOWS;
+		else
+			return OS_LINUX;
+	}
+
+	public static String getBinaryVersion() {
+		String arch = System.getProperty("os.arch");
+		String bit = System.getProperty("sun.arch.data.model");
+
+		String binaryName = null;
+		switch (findCurrentOS()) {
+
+		case OS_OSX:
+			if (arch.startsWith("ppc")) {
+				System.err
+						.println("Sorry, PowerPC architecture is no longer supported");
+				System.exit(0);
+			} else {
+				binaryName = "PhyML_3.0_macOS_i386";
+			}
+			break;
+		case OS_LINUX:
+			if (bit.startsWith("64"))
+				binaryName = "PhyML_3.0_linux64";
+			else
+				binaryName = "PhyML_3.0_linux32";
+			break;
+		case OS_WINDOWS:
+			binaryName = "PhyML_3.0_win32.exe";
+			break;
+		default:
+			binaryName = null;
+		}
+
+		return binaryName;
+	}
+
+	public static String calculateRuntimeMinutes(long startTime, long endTime) {
+		long seconds = Math.round((endTime - startTime) / 1000.0);
+		int hours = (int) (seconds / 3600.0);
+		int rest1 = (int) (seconds % (3600.0));
+		int minutes = (int) (rest1 / 60.0);
+		seconds = (int) (seconds - (hours * 3600 + minutes * 60));
+		String h = "" + hours;
+		String m = "" + minutes;
+		String s = "" + seconds;
+		if (minutes < 10)
+			m = "0" + m;
+		if (seconds < 10)
+			s = "0" + s;
+		return h + "h:" + m + ":" + s + "";
+	}
+
+	public static String getCurrentTime(String format) {
+		Calendar cal = new GregorianCalendar();
+	    SimpleDateFormat date_format = new SimpleDateFormat(format);
+	    return date_format.format(cal.getTime());
+	}
+	
+	public static String displayRuntime(long time) {
+		long decimes = Math.round(time / 100.0);
+		int hours = (int) (decimes / 36000.0);
+		int rest1 = (int) (decimes % 36000.0);
+		int minutes = (int) (rest1 / 600.0);
+		int rest2 = (int) (rest1 % 600.0);
+		int seconds = (int) (rest2 / 10.0);
+		decimes = (int) (decimes - (hours * 36000 + minutes * 600 + seconds * 10));
+		String h = "" + hours;
+		String m = "" + minutes;
+		String s = "" + seconds;
+		String d = "0" + decimes;
+		if (hours < 10)
+			h = "0" + h;
+		if (minutes < 10)
+			m = "0" + m;
+		if (seconds < 10)
+			s = "0" + s;
+		return h + "h:" + m + ":" + s + ":" + d + "";
+	}
+
+	public static String calculateRuntime(long startTime, long endTime) {
+		return displayRuntime(endTime - startTime);
+	}
+
+	public static boolean isNumber(String s) {
+		try {
+			Double.parseDouble(s);
+			return true;
+		} catch (NumberFormatException ex) {
+			return false;
+		}
+	}
+
+	public static void toConsoleEnd() {
+		if (ModelTest.buildGUI)
+			XManager.getInstance()
+					.getPane()
+					.setCaretPosition(
+							XManager.getInstance().getPane().getDocument()
+									.getLength());
+	}
+
+	/**
+	 * copyFile
+	 * 
+	 * Copies src file to dst file. If the dst file does not exist, it is
+	 * created modified from The Java Developers Almanac 1.4:
+	 * http://www.exampledepot.com/egs/java.io/CopyFile.html
+	 */
+
+	public static void copyFile(String source, String destination)
+			throws IOException {
+		File src = new File(source);
+		File dst = new File(destination);
+
+		InputStream in = new FileInputStream(src);
+		OutputStream out = new FileOutputStream(dst);
+
+		// Transfer bytes from in to out
+		byte[] buf = new byte[1024];
+		int len;
+		while ((len = in.read(buf)) > 0) {
+			out.write(buf, 0, len);
+		}
+		in.close();
+		out.close();
+	}
+
+	/**
+	 * CheckNA
+	 * 
+	 * If value is NA it prints "-"
+	 */
+	public static String checkNA(double value) {
+		if (value == NA)
+			return "  -  ";
+		else {
+			String s = String.format(Locale.ENGLISH, "%8.4f", value);
+			return s;
+		}
+	}
+
+	/**
+	 * deleteFile
+	 * 
+	 * Delete a given file
+	 */
+	public static void deleteFile(String fileName) {
+
+		File f;
+
+		try {
+			f = new File(fileName);
+		} catch (Exception e) {
+			throw new IllegalArgumentException("DeleteFiles: deletion of "
+					+ fileName + " failed");
+		}
+
+		// Make sure the file or directory exists and isn't write protected
+		if (f.exists()) {
+			if (!f.canWrite())
+				throw new IllegalArgumentException(
+						"DeleteFiles: write protected: " + fileName);
+
+			// if it is a directory, make sure it is empty
+			if (f.isDirectory()) {
+				String[] files = f.list();
+				if (files.length > 0)
+					throw new IllegalArgumentException(
+							"DeleteFiles: directory not empty: " + fileName);
+			}
+
+			// explicit close associated stream for windows
+			//
+			// attempt to delete it
+			boolean success = f.delete();
+
+			if (!success)
+				throw new IllegalArgumentException("DeleteFiles: deletion of "
+						+ fileName + " failed");
+		}
+	}
+
+	/**
+	 * printRed
+	 * 
+	 * Prints to the main console text in red
+	 */
+
+	public static void printRed(String text) {
+		if (ModelTest.buildGUI) {
+			try {
+				Document doc = XManager.getInstance().getPane().getDocument();
+				doc.insertString(doc.getLength(), text, XManager.redText);
+			} catch (javax.swing.text.BadLocationException e) {
+			}
+		}
+	}
+
+	/******************
+	 * RoundDoubleTo **************************
+	 * 
+	 * Rounds a double to a number of significant digits
+	 *********************************************************/
+
+	public static double roundDoubleTo(double decimal, int dplaces) {
+		BigDecimal bd = new BigDecimal(decimal);
+		bd = bd.setScale(dplaces, BigDecimal.ROUND_UP);
+		return bd.doubleValue();
+	}
+
+	public static String asPercent(double decimal) {
+		if (decimal > 100.0d) {
+			decimal = 100.0d;
+		}
+		return format(decimal, 6, 2, false) + "%";
+	}
+
+	public static String format(double number, int totalLength, int decimalPlaces, boolean exp) {
+		StringBuffer sb;
+		String format;
+		if (exp) {
+			format = "%"+totalLength+"."+decimalPlaces+"e";
+		} else {
+			format = "%"+totalLength+"."+decimalPlaces+"f";
+		}
+		sb = new StringBuffer(String.format(Locale.ENGLISH, format, number));
+		// normalize string to size 6
+		for (int i = sb.length(); i < totalLength; i++) {
+			sb.insert(0, " ");
+		}
+
+		return sb.toString();
+	}
+	
+	/******************
+	 * putSlashBeforeSpaces **************************
+	 * 
+	 * Inserts slash before paces in a path (MacOS X)
+	 *********************************************************/
+
+	public static String putSlashBeforeSpaces(String originalPath) {
+		if (originalPath == null)
+			return "";
+
+		StringBuffer s = new StringBuffer(originalPath);
+
+		for (int i = 0; i < s.length(); i++) {
+			if (s.charAt(i) == ' ')
+				s.insert(i++, '\\');
+		}
+		return s.toString();
+	}
+
+	/******************
+	 * substituteSpaces **************************
+	 * 
+	 * substitutes %20 in spaces in a path (MacOS X)
+	 *********************************************************/
+
+	public static String substituteSpaces(String originalPath) {
+		if (originalPath == null)
+			return "";
+
+		StringBuffer s = new StringBuffer(originalPath);
+
+		for (int i = 0; i < s.length(); i++) {
+			if (s.charAt(i) == ' ') {
+				s.setCharAt(i, '0');
+				s.insert(i++, '%');
+				s.insert(i++, '2');
+			}
+		}
+		return s.toString();
+	}
+
+	/******************
+	 * putQuotesAroundSpaces **************************
+	 * 
+	 * Inserts quotes at correct locations in nominated path string. (Windows)
+	 *********************************************************/
+
+	public static String putQuotesAroundSpaces(String originalPath) {
+		StringTokenizer st = new StringTokenizer(originalPath, File.separator);
+		String newPath = "\"";
+		while (st.hasMoreTokens()) {
+			String token = st.nextToken();
+			if (token.contains(" ")) {
+				newPath += File.separator + "\"" + token + "\"";
+			} else {
+				newPath += File.separator + token;
+			}
+		}
+		return newPath.substring(1, newPath.length());
+	}
+
+	/******************
+	 * specialConcatStringArrays **************************
+	 * 
+	 * concatenates two string arrays but removinf the first string from the
+	 * second
+	 *********************************************************/
+
+	public static String[] specialConcatStringArrays(String[] A, String[] B) {
+		String[] C = new String[A.length + B.length - 1];
+		System.arraycopy(A, 0, C, 0, A.length);
+		System.arraycopy(B, 1, C, A.length, B.length - 1);
+		return C;
+	}
+
+	/**
+	 * Calculate invariable sites.
+	 * 
+	 * @param alignment the alignment
+	 * 
+	 * @return the invariable sites in the alignment
+	 */
+	public static int calculateInvariableSites (Alignment alignment) {
+
+		//use this function to estimate a good starting value for the InvariableSites distribution.
+		int numSites    = alignment.getSiteCount();
+		int numSeqs     = alignment.getSequenceCount();
+		int inv         = 0;
+		int tmp;
+		boolean tmpInv = true;
+		for(int i=0; i < numSites; i++) {
+			tmp     = indexOfChar(alignment.getData(0,i));
+			tmpInv  = true;
+			for(int j=0; j < numSeqs; j++) {
+				if(indexOfChar(alignment.getData(j,i)) != tmp) { //if at least one difference in column i:
+					j = numSeqs;    //we exit this for.
+					tmpInv = false; //i is not an invariable site.
+				}
+			}
+			if(tmpInv)
+				inv++;
+		}
+		return inv;
+	}
+	
+	private static int indexOfChar (char c) {
+		char[] charSet = {'A', 'C', 'G', 'T', 'a', 'c', 'g', 't'};
+		for (int charIndex = 0; charIndex < charSet.length; charIndex++)
+			if (charSet[charIndex] == c)
+				return charIndex % 4;
+
+		return -1;
+	}
+	
+	public static double calculateShannonSampleSize (Alignment alignment, boolean doJustShannonEntropy) {
+
+		int numSites = alignment.getSiteCount();
+		int numTaxa = alignment.getSequenceCount();
+		
+		//int    pattern[][]    = new int   [numSites][numSeqs];
+		double freqs  [][]    = new double[numSites][4];
+		byte   state  [][]    = new byte  [numSites][4];
+		double siteS  []      = new double[numSites];
+		int    sequences[]    = new int[numSites];
+		double shannonEntropy = 0.0;
+
+		//We simply count bases at positions and store in state[][]
+		for(int i=0; i < numSites; i++) {
+			for(int j=0; j < numTaxa; j++) {
+				//state[i][indexOfchar(alignment.getData(j,i))]++;
+				int index = indexOfChar(alignment.getData(j,i));
+				if(index >= 0) {
+					state[i][index]++;
+					sequences[i]++;
+				}
+				//state[i][sP.pattern[j][i]]++;
+			}
+		}
+
+		//For each alignment position, we calculate aminoacid frequencies. And also...
+		//For each alignment position, we calculate Shannon Entropy based on previous frequencies.
+		for(int i=0; i < numSites; i++) {
+			for(int j=0; j < 4; j++) {
+				//freqs[i][j] = (double)state[i][j]/(double)numSeqs;
+				freqs[i][j] = (double)state[i][j]/(double)sequences[i];
+				if(freqs[i][j] > 0)
+					siteS[i]   += freqs[i][j]*Math.log(freqs[i][j])/Math.log(2);
+			}
+		}
+
+		//We sum positions entropies over the whole alignment.
+		for(int i=0; i < numSites; i++) {
+			shannonEntropy += siteS[i];
+		}
+
+		if(doJustShannonEntropy) {
+			return -1.0*shannonEntropy; //sum of shannon Entropy positions.
+		} else { //if Options.SHANNON_NxL
+			double meanShannonEntropy;
+			double maxShannonEntropy = 0;
+			double normalizedShannonEntropy = 0;
+			meanShannonEntropy = -1.0*shannonEntropy/(double)numSites; //mean S for sites
+			//let's normalize ShannonEntropy from 0 to 1:
+			for(int i=0; i<4; i++) {
+				maxShannonEntropy += (1.0/(double)4)*Math.log(1.0/(double)4)/Math.log(2);
+			}
+			//by this moment we normalize by a "rule of three"
+			normalizedShannonEntropy = -1.0*meanShannonEntropy/maxShannonEntropy;
+			return (double)numSites*(double)numTaxa*normalizedShannonEntropy; //NxL x averaged Shannon entropy
+		}
+	}
+} // end of class
diff --git a/CHANGELOG b/src/main/resources/CHANGELOG
similarity index 97%
rename from CHANGELOG
rename to src/main/resources/CHANGELOG
index 10f0525..a16c616 100644
--- a/CHANGELOG
+++ b/src/main/resources/CHANGELOG
@@ -1,3 +1,9 @@
+20 Oct 2015 Version 2.1.8 Revision 20151020
+
+  * Removed ReadSeq dependency
+  * Fixed warnings
+  * Updated prottest jarfile to v3.4
+
 20 Feb 2015 Version 2.1.7 Revision 20150220
 
   * Fixed bug in ML tree search operation. Console version
diff --git a/src/main/resources/COPYING b/src/main/resources/COPYING
new file mode 100644
index 0000000..94a0453
--- /dev/null
+++ b/src/main/resources/COPYING
@@ -0,0 +1,621 @@
+                    GNU 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.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU 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
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
diff --git a/INSTALL b/src/main/resources/INSTALL
similarity index 100%
copy from INSTALL
copy to src/main/resources/INSTALL
diff --git a/README b/src/main/resources/README
similarity index 99%
rename from README
rename to src/main/resources/README
index 3963daa..b2c18ff 100644
--- a/README
+++ b/src/main/resources/README
@@ -1,5 +1,5 @@
 -----------------------------------------------------------------------------
-jModelTest 2.1.7 Readme -	Nov/20/2014
+jModelTest 2.1.8 Readme -	Oct/20/2015
 
 Diego Darriba (ddarriba at udc.es)
 Guillermo L. Taboada (taboada at udc.es)
diff --git a/src/main/resources/THIRDPARTYLICENSES b/src/main/resources/THIRDPARTYLICENSES
new file mode 100644
index 0000000..e725d98
--- /dev/null
+++ b/src/main/resources/THIRDPARTYLICENSES
@@ -0,0 +1,576 @@
++++++++++++++++++++++++++++++++++++++++++++
+LICENSE FOR 'MPJ Express'
+http://mpj-express.org
++++++++++++++++++++++++++++++++++++++++++++
+
+1. The license statement
+
+ The MIT License
+
+ Copyright (c) 2005 - 2007
+   1. Distributed Systems Group, University of Portsmouth (2005)
+   2. Aamir Shafi (2005 - 2007)
+   3. Bryan Carpenter (2005 - 2007)
+   4. Mark Baker (2005 - 2007)
+
+ The bulk of code in this distribution was developed by the Distributed Systems
+ Group at the University of Portsmouth. Some sections of the code like
+ the buffering API and derived datatypes include contributions developed at
+ the Community Grids Lab at Indiana University.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+ NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+2. MPJ uses two third party softwares: Jetty and Java Service Wrapper project.
+   The licenses for these two projects can be seen in
+   $MPJ_HOME/THIRDPARTYLICENSES file.
+
+
++++++++++++++++++++++++++++++++++++++++++++
+LICENSE FOR 'PAL' Library
+http://www.cebl.auckland.ac.nz/pal-project/
++++++++++++++++++++++++++++++++++++++++++++
+
+Copyright (c) 1999-2002 by the PAL Development Core Team
+This package may be distributed under the terms of the
+GNU Lesser General Public License (LGPL):
+http://www.cebl.auckland.ac.nz/pal-project/license.html
+
+PAL Development Core Team:
+
+Alexei Drummond, School of Biological Sciences, University of Auckland
+Korbinian Strimmer, Department of Zoology, University of Oxford
+Ed Buckler, Department of Genetics, North Carolina State University
+
++++++++++++++++++++++++++++++++++++++++++++
+LICENSE FOR 'PhyML' Library
+http://code.google.com/p/phyml/
++++++++++++++++++++++++++++++++++++++++++++
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year  name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
++++++++++++++++++++++++++++++++++++++++++++
+LICENSE FOR 'Alter' Library
+http://sing.ei.uvigo.es/ALTER
++++++++++++++++++++++++++++++++++++++++++++
+
+		   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.
\ No newline at end of file
diff --git a/conf/jmodeltest.conf b/src/main/resources/conf/jmodeltest.conf
similarity index 100%
rename from conf/jmodeltest.conf
rename to src/main/resources/conf/jmodeltest.conf
diff --git a/es/uvigo/darwin/jmodeltest/gui/icons/JMT24.gif b/src/main/resources/es/uvigo/darwin/jmodeltest/gui/icons/JMT24.gif
similarity index 100%
rename from es/uvigo/darwin/jmodeltest/gui/icons/JMT24.gif
rename to src/main/resources/es/uvigo/darwin/jmodeltest/gui/icons/JMT24.gif
diff --git a/es/uvigo/darwin/jmodeltest/gui/icons/JMT48.gif b/src/main/resources/es/uvigo/darwin/jmodeltest/gui/icons/JMT48.gif
similarity index 100%
rename from es/uvigo/darwin/jmodeltest/gui/icons/JMT48.gif
rename to src/main/resources/es/uvigo/darwin/jmodeltest/gui/icons/JMT48.gif
diff --git a/es/uvigo/darwin/jmodeltest/gui/icons/JMT96.gif b/src/main/resources/es/uvigo/darwin/jmodeltest/gui/icons/JMT96.gif
similarity index 100%
rename from es/uvigo/darwin/jmodeltest/gui/icons/JMT96.gif
rename to src/main/resources/es/uvigo/darwin/jmodeltest/gui/icons/JMT96.gif
diff --git a/es/uvigo/darwin/jmodeltest/gui/icons/Open16.gif b/src/main/resources/es/uvigo/darwin/jmodeltest/gui/icons/Open16.gif
similarity index 100%
rename from es/uvigo/darwin/jmodeltest/gui/icons/Open16.gif
rename to src/main/resources/es/uvigo/darwin/jmodeltest/gui/icons/Open16.gif
diff --git a/es/uvigo/darwin/jmodeltest/gui/icons/Open24.gif b/src/main/resources/es/uvigo/darwin/jmodeltest/gui/icons/Open24.gif
similarity index 100%
rename from es/uvigo/darwin/jmodeltest/gui/icons/Open24.gif
rename to src/main/resources/es/uvigo/darwin/jmodeltest/gui/icons/Open24.gif
diff --git a/example-data/18S_insects2.nex b/src/main/resources/example-data/18S_insects2.nex
similarity index 100%
rename from example-data/18S_insects2.nex
rename to src/main/resources/example-data/18S_insects2.nex
diff --git a/example-data/Birds.nex b/src/main/resources/example-data/Birds.nex
similarity index 100%
rename from example-data/Birds.nex
rename to src/main/resources/example-data/Birds.nex
diff --git a/example-data/HIV_vpu.ref2.fas b/src/main/resources/example-data/HIV_vpu.ref2.fas
similarity index 100%
rename from example-data/HIV_vpu.ref2.fas
rename to src/main/resources/example-data/HIV_vpu.ref2.fas
diff --git a/example-data/HIVpol.groupM.nex b/src/main/resources/example-data/HIVpol.groupM.nex
old mode 100644
new mode 100755
similarity index 100%
rename from example-data/HIVpol.groupM.nex
rename to src/main/resources/example-data/HIVpol.groupM.nex
diff --git a/example-data/Hex_EF1a.nex b/src/main/resources/example-data/Hex_EF1a.nex
similarity index 100%
rename from example-data/Hex_EF1a.nex
rename to src/main/resources/example-data/Hex_EF1a.nex
diff --git a/example-data/aP6.fas b/src/main/resources/example-data/aP6.fas
similarity index 100%
rename from example-data/aP6.fas
rename to src/main/resources/example-data/aP6.fas
diff --git a/example-data/aP6.phy b/src/main/resources/example-data/aP6.phy
similarity index 100%
rename from example-data/aP6.phy
rename to src/main/resources/example-data/aP6.phy
diff --git a/example-data/channa.nex b/src/main/resources/example-data/channa.nex
similarity index 100%
rename from example-data/channa.nex
rename to src/main/resources/example-data/channa.nex
diff --git a/example-data/data.phy b/src/main/resources/example-data/data.phy
similarity index 100%
rename from example-data/data.phy
rename to src/main/resources/example-data/data.phy
diff --git a/example-data/example.nex b/src/main/resources/example-data/example.nex
similarity index 100%
rename from example-data/example.nex
rename to src/main/resources/example-data/example.nex
diff --git a/example-data/gusanos16S.mafft.fas b/src/main/resources/example-data/gusanos16S.mafft.fas
similarity index 100%
rename from example-data/gusanos16S.mafft.fas
rename to src/main/resources/example-data/gusanos16S.mafft.fas
diff --git a/example-data/gusanosCOI.mafft.fas b/src/main/resources/example-data/gusanosCOI.mafft.fas
similarity index 100%
rename from example-data/gusanosCOI.mafft.fas
rename to src/main/resources/example-data/gusanosCOI.mafft.fas
diff --git a/example-data/primate-mtDNA.nex b/src/main/resources/example-data/primate-mtDNA.nex
similarity index 100%
rename from example-data/primate-mtDNA.nex
rename to src/main/resources/example-data/primate-mtDNA.nex
diff --git a/example-data/rodents.nex b/src/main/resources/example-data/rodents.nex
similarity index 100%
rename from example-data/rodents.nex
rename to src/main/resources/example-data/rodents.nex
diff --git a/src/main/resources/exe/phyml/README b/src/main/resources/exe/phyml/README
new file mode 100644
index 0000000..3b8ba49
--- /dev/null
+++ b/src/main/resources/exe/phyml/README
@@ -0,0 +1,10 @@
+Standard installation:
+
+  Place PhyML binary here, named 'phyml'
+
+  For multi-platform jModelTest distribution use the following names:
+
+    PhyML_3.0_linux32
+    PhyML_3.0_linux64
+    PhyML_3.0_macOS_i386
+    PhyML_3.0_win32.exe
diff --git a/extra/filecluster8.conf.template b/src/main/resources/extra/filecluster8.conf.template
similarity index 100%
rename from extra/filecluster8.conf.template
rename to src/main/resources/extra/filecluster8.conf.template
diff --git a/extra/machines b/src/main/resources/extra/machines
similarity index 100%
rename from extra/machines
rename to src/main/resources/extra/machines
diff --git a/src/main/resources/extra/mpj.tar.gz b/src/main/resources/extra/mpj.tar.gz
new file mode 100644
index 0000000..46151f6
Binary files /dev/null and b/src/main/resources/extra/mpj.tar.gz differ
diff --git a/resources/template/index.html b/src/main/resources/resources/template/index.html
similarity index 100%
rename from resources/template/index.html
rename to src/main/resources/resources/template/index.html
diff --git a/resources/template/resources/homeIcon.gif b/src/main/resources/resources/template/resources/homeIcon.gif
similarity index 100%
rename from resources/template/resources/homeIcon.gif
rename to src/main/resources/resources/template/resources/homeIcon.gif
diff --git a/resources/template/resources/logo0.png b/src/main/resources/resources/template/resources/logo0.png
similarity index 100%
rename from resources/template/resources/logo0.png
rename to src/main/resources/resources/template/resources/logo0.png
diff --git a/resources/template/resources/style.css b/src/main/resources/resources/template/resources/style.css
similarity index 100%
rename from resources/template/resources/style.css
rename to src/main/resources/resources/template/resources/style.css
diff --git a/resources/template/resources/topIcon.gif b/src/main/resources/resources/template/resources/topIcon.gif
similarity index 100%
rename from resources/template/resources/topIcon.gif
rename to src/main/resources/resources/template/resources/topIcon.gif
diff --git a/runjmodeltest-cluster.sh b/src/main/resources/runjmodeltest-cluster.sh
similarity index 100%
rename from runjmodeltest-cluster.sh
rename to src/main/resources/runjmodeltest-cluster.sh
diff --git a/runjmodeltest-gui.bat b/src/main/resources/runjmodeltest-gui.bat
similarity index 100%
rename from runjmodeltest-gui.bat
rename to src/main/resources/runjmodeltest-gui.bat
diff --git a/runjmodeltest-gui.sh b/src/main/resources/runjmodeltest-gui.sh
similarity index 100%
rename from runjmodeltest-gui.sh
rename to src/main/resources/runjmodeltest-gui.sh
diff --git a/trees/aP6.tree b/src/main/resources/trees/aP6.tree
similarity index 100%
rename from trees/aP6.tree
rename to src/main/resources/trees/aP6.tree
diff --git a/trees/aP6b.tree b/src/main/resources/trees/aP6b.tree
similarity index 100%
rename from trees/aP6b.tree
rename to src/main/resources/trees/aP6b.tree

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



More information about the debian-med-commit mailing list