[med-svn] [prottest] 01/02: Imported Upstream version 3.4+dfsg

Andreas Tille tille at debian.org
Sun Sep 6 06:25:19 UTC 2015


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

tille pushed a commit to branch master
in repository prottest.

commit 051a6202331e706d5aa41881810feb8c816b146f
Author: Andreas Tille <tille at debian.org>
Date:   Sun Sep 6 08:11:14 2015 +0200

    Imported Upstream version 3.4+dfsg
---
 COPYING                                            |  340 +++
 INSTALL                                            |   16 +
 THIRDPARTYLICENSES                                 |  576 +++++
 build.xml                                          |   36 +
 buildconf/build-impl.xml                           |  707 ++++++
 buildconf/project.properties                       |   79 +
 lib/AbsoluteLayout.jar                             |  Bin 0 -> 2879 bytes
 lib/copylibs.jar                                   |  Bin 0 -> 17150 bytes
 lib/swing-worker-1.1.jar                           |  Bin 0 -> 11103 bytes
 manifest.mf                                        |    8 +
 .../services/org.jdesktop.application.Application  |    1 +
 .../java/es/uvigo/darwin/prottest/ProtTest.java    |  363 +++
 .../uvigo/darwin/prottest/consensus/Consensus.java |  911 +++++++
 .../uvigo/darwin/prottest/consensus/package.html   |   20 +
 .../darwin/prottest/exe/AminoAcidRunEstimator.java |   66 +
 .../prottest/exe/ExternalExecutionManager.java     |  108 +
 .../darwin/prottest/exe/ExternalExecutor.java      |   97 +
 .../prottest/exe/ParallelModelEstimator.java       |  154 ++
 .../prottest/exe/PhyMLv3AminoAcidRunEstimator.java |  464 ++++
 .../darwin/prottest/exe/PhymlStreamGobbler.java    |   65 +
 .../prottest/exe/RaxMLAminoAcidRunEstimator.java   |  341 +++
 .../darwin/prottest/exe/RaxMLStreamGobbler.java    |   60 +
 .../es/uvigo/darwin/prottest/exe/RunEstimator.java |   60 +
 .../darwin/prottest/exe/RunEstimatorImpl.java      |  212 ++
 .../uvigo/darwin/prottest/exe/StreamGobbler.java   |   53 +
 .../java/es/uvigo/darwin/prottest/exe/package.html |   30 +
 .../prottest/exe/util/TemporaryFileManager.java    |  256 ++
 .../es/uvigo/darwin/prottest/exe/util/package.html |   21 +
 .../darwin/prottest/facade/ProtTestFacade.java     |  144 ++
 .../darwin/prottest/facade/ProtTestFacadeImpl.java |  276 +++
 .../darwin/prottest/facade/ProtTestFacadeMPJ.java  |  210 ++
 .../prottest/facade/ProtTestFacadeSequential.java  |  135 ++
 .../prottest/facade/ProtTestFacadeThread.java      |  231 ++
 .../uvigo/darwin/prottest/facade/TreeFacade.java   |   96 +
 .../darwin/prottest/facade/TreeFacadeImpl.java     |   93 +
 .../es/uvigo/darwin/prottest/facade/package.html   |   27 +
 .../facade/strategy/DistributionStrategy.java      |  147 ++
 .../prottest/facade/strategy/Distributor.java      |  203 ++
 .../strategy/DynamicDistributionStrategy.java      |  162 ++
 .../strategy/HybridDistributionStrategy.java       |  230 ++
 .../ImprovedDynamicDistributionStrategy.java       |  147 ++
 .../facade/strategy/MultipleDistributor.java       |  246 ++
 .../strategy/StaticDistributionStrategy.java       |  145 ++
 .../darwin/prottest/facade/strategy/package.html   |   24 +
 .../facade/thread/ThreadPoolSynchronizer.java      |  104 +
 .../darwin/prottest/facade/thread/package.html     |   21 +
 .../prottest/facade/util/ProtTestParameterVO.java  |  144 ++
 .../prottest/facade/util/SelectionChunk.java       |  210 ++
 .../uvigo/darwin/prottest/facade/util/package.html |   21 +
 .../global/AminoAcidApplicationGlobals.java        |   63 +
 .../darwin/prottest/global/ApplicationGlobals.java |   70 +
 .../prottest/global/ProtTestConsoleParameters.java |   74 +
 .../darwin/prottest/global/ProtTestConstants.java  |  111 +
 .../global/RaxmlAminoAcidApplicationGlobals.java   |   52 +
 .../global/options/ApplicationOptions.java         |  841 +++++++
 .../options/SerializableApplicationOptions.java    |  194 ++
 .../darwin/prottest/global/options/package.html    |   21 +
 .../es/uvigo/darwin/prottest/global/package.html   |   21 +
 .../darwin/prottest/model/AminoAcidModel.java      |   88 +
 .../java/es/uvigo/darwin/prottest/model/Model.java |  479 ++++
 .../es/uvigo/darwin/prottest/model/package.html    |   22 +
 .../prottest/model/state/ModelEmptyLkState.java    |   89 +
 .../prottest/model/state/ModelFilledLkState.java   |  100 +
 .../darwin/prottest/model/state/ModelLkState.java  |   78 +
 .../uvigo/darwin/prottest/model/state/package.html |   21 +
 .../prottest/observer/ModelUpdaterObserver.java    |   40 +
 .../prottest/observer/ObservableModelUpdater.java  |   83 +
 .../es/uvigo/darwin/prottest/observer/package.html |   22 +
 .../java/es/uvigo/darwin/prottest/package.html     |   22 +
 .../es/uvigo/darwin/prottest/selection/AIC.java    |   89 +
 .../es/uvigo/darwin/prottest/selection/AICc.java   |   74 +
 .../es/uvigo/darwin/prottest/selection/BIC.java    |   87 +
 .../es/uvigo/darwin/prottest/selection/DT.java     |   87 +
 .../prottest/selection/InformationCriterion.java   |  423 ++++
 .../es/uvigo/darwin/prottest/selection/LNL.java    |   71 +
 .../selection/model/AICSelectionModel.java         |   37 +
 .../selection/model/AICcSelectionModel.java        |   39 +
 .../selection/model/BICSelectionModel.java         |   37 +
 .../prottest/selection/model/DTSelectionModel.java |   54 +
 .../selection/model/LNLSelectionModel.java         |   37 +
 .../prottest/selection/model/SelectionModel.java   |  165 ++
 .../darwin/prottest/selection/model/package.html   |   21 +
 .../uvigo/darwin/prottest/selection/package.html   |   25 +
 .../selection/printer/AminoAcidPrintFramework.java |   68 +
 .../prottest/selection/printer/PrintFramework.java |  407 ++++
 .../darwin/prottest/selection/printer/package.html |   21 +
 .../java/es/uvigo/darwin/prottest/taxa/Taxon.java  |  164 ++
 .../uvigo/darwin/prottest/taxa/TaxonomicLevel.java |   69 +
 .../es/uvigo/darwin/prottest/taxa/package.html     |   21 +
 .../darwin/prottest/tree/TreeDistancesCache.java   |  157 ++
 .../prottest/tree/TreeEuclideanDistancesCache.java |   44 +
 .../es/uvigo/darwin/prottest/tree/TreeUtils.java   |  516 ++++
 .../uvigo/darwin/prottest/tree/WeightedTree.java   |   60 +
 .../es/uvigo/darwin/prottest/tree/package.html     |   21 +
 .../es/uvigo/darwin/prottest/util/FixedBitSet.java |  268 +++
 .../darwin/prottest/util/ProtTestAlignment.java    |  177 ++
 .../uvigo/darwin/prottest/util/StatFramework.java  |  141 ++
 .../es/uvigo/darwin/prottest/util/Utilities.java   |  299 +++
 .../darwin/prottest/util/WriterOutputStream.java   |   87 +
 .../argumentparser/AminoAcidArgumentParser.java    |   98 +
 .../argumentparser/ProtTestArgumentParser.java     |  293 +++
 .../prottest/util/argumentparser/package.html      |   21 +
 .../prottest/util/attributable/Attributable.java   |   57 +
 .../util/attributable/AttributableHelper.java      |   41 +
 .../darwin/prottest/util/attributable/package.html |   21 +
 .../util/checkpoint/CheckPointManager.java         |  185 ++
 .../darwin/prottest/util/checkpoint/package.html   |   21 +
 .../util/checkpoint/status/ApplicationStatus.java  |   47 +
 .../util/checkpoint/status/ProtTestStatus.java     |   80 +
 .../prottest/util/checkpoint/status/package.html   |   21 +
 .../prottest/util/collection/ModelCollection.java  |  349 +++
 .../util/collection/ParallelModelCollection.java   |  269 +++
 .../util/collection/ParallelModelQueue.java        |   81 +
 .../util/collection/SingleModelCollection.java     |   56 +
 .../darwin/prottest/util/collection/package.html   |   21 +
 .../AminoAcidModelNaturalComparator.java           |   63 +
 .../prottest/util/comparator/LKComparator.java     |   44 +
 .../comparator/ModelDistributionHeuristic.java     |   55 +
 .../util/comparator/ModelWeightComparator.java     |   48 +
 .../darwin/prottest/util/comparator/package.html   |   21 +
 .../util/exception/AlignmentParseException.java    |   46 +
 .../prottest/util/exception/ImportException.java   |   59 +
 .../util/exception/ModelOptimizationException.java |  165 ++
 .../util/exception/ProtTestCheckedException.java   |   42 +
 .../util/exception/ProtTestInternalException.java  |   45 +
 .../util/exception/TreeFormatException.java        |   45 +
 .../prottest/util/factory/ProtTestFactory.java     |  317 +++
 .../darwin/prottest/util/factory/package.html      |   21 +
 .../prottest/util/fileio/AlignmentReader.java      |  285 +++
 .../darwin/prottest/util/fileio/ImportHelper.java  |  573 +++++
 .../darwin/prottest/util/fileio/NexusExporter.java |  248 ++
 .../darwin/prottest/util/fileio/NexusImporter.java |  686 ++++++
 .../prottest/util/fileio/NexusTreeReader.java      |   71 +
 .../util/fileio/SimpleNewickTreeReader.java        |  135 ++
 .../darwin/prottest/util/fileio/TreeReader.java    |   43 +
 .../util/logging/ProtTestLogFormatter.java         |   47 +
 .../prottest/util/logging/ProtTestLogger.java      |  361 +++
 .../es/uvigo/darwin/prottest/util/package.html     |   21 +
 .../util/printer/ProtTestFormattedOutput.java      |  182 ++
 .../prottest/util/printer/ProtTestPrinter.java     |  200 ++
 .../java/es/uvigo/darwin/xprottest/CreditsBox.java |   80 +
 .../es/uvigo/darwin/xprottest/PreferencesView.java |  197 ++
 .../uvigo/darwin/xprottest/XProtTestAboutBox.java  |  229 ++
 .../es/uvigo/darwin/xprottest/XProtTestApp.java    |   97 +
 .../es/uvigo/darwin/xprottest/XProtTestView.java   | 1138 +++++++++
 .../darwin/xprottest/analysis/FrequenciesView.java |  128 +
 .../uvigo/darwin/xprottest/analysis/TreeView.java  |  282 +++
 .../darwin/xprottest/analysis/TreeWrapper.java     |   44 +
 .../xprottest/analysis/consensus/Consensus.java    |  690 ++++++
 .../consensus/resources/Consensus.properties       |   49 +
 .../analysis/resources/FrequenciesView.properties  |    4 +
 .../analysis/resources/TreeView.properties         |   28 +
 .../darwin/xprottest/compute/OptionsView.java      |  748 ++++++
 .../darwin/xprottest/compute/RunningFrame.java     |  261 ++
 .../compute/resources/OptionsView.properties       |   62 +
 .../compute/resources/RunningFrame.properties      |   12 +
 .../xprottest/resources/CreditsBox.properties      |   16 +
 .../xprottest/resources/PreferencesView.properties |   24 +
 .../resources/XProtTestAboutBox.properties         |   19 +
 .../xprottest/resources/XProtTestApp.properties    |   38 +
 .../xprottest/resources/XProtTestView.properties   |   91 +
 .../es/uvigo/darwin/xprottest/resources/about.png  |  Bin 0 -> 8187 bytes
 .../xprottest/resources/busyicons/busy-icon0.png   |  Bin 0 -> 3588 bytes
 .../xprottest/resources/busyicons/busy-icon1.png   |  Bin 0 -> 3585 bytes
 .../xprottest/resources/busyicons/busy-icon10.png  |  Bin 0 -> 3568 bytes
 .../xprottest/resources/busyicons/busy-icon11.png  |  Bin 0 -> 3581 bytes
 .../xprottest/resources/busyicons/busy-icon12.png  |  Bin 0 -> 3589 bytes
 .../xprottest/resources/busyicons/busy-icon13.png  |  Bin 0 -> 3586 bytes
 .../xprottest/resources/busyicons/busy-icon14.png  |  Bin 0 -> 3586 bytes
 .../xprottest/resources/busyicons/busy-icon2.png   |  Bin 0 -> 3585 bytes
 .../xprottest/resources/busyicons/busy-icon3.png   |  Bin 0 -> 3572 bytes
 .../xprottest/resources/busyicons/busy-icon4.png   |  Bin 0 -> 3576 bytes
 .../xprottest/resources/busyicons/busy-icon5.png   |  Bin 0 -> 3580 bytes
 .../xprottest/resources/busyicons/busy-icon6.png   |  Bin 0 -> 3581 bytes
 .../xprottest/resources/busyicons/busy-icon7.png   |  Bin 0 -> 3598 bytes
 .../xprottest/resources/busyicons/busy-icon8.png   |  Bin 0 -> 3594 bytes
 .../xprottest/resources/busyicons/busy-icon9.png   |  Bin 0 -> 3581 bytes
 .../xprottest/resources/busyicons/idle-icon.png    |  Bin 0 -> 3360 bytes
 .../darwin/xprottest/resources/prottestlogo.gif    |  Bin 0 -> 11850 bytes
 .../es/uvigo/darwin/xprottest/resources/splash.png |  Bin 0 -> 21747 bytes
 .../darwin/xprottest/results/Bundle.properties     |   19 +
 .../darwin/xprottest/results/ErrorLogView.java     |  101 +
 .../darwin/xprottest/results/ResultsView.java      | 2483 ++++++++++++++++++++
 .../results/resources/ErrorLogView.properties      |    6 +
 .../results/resources/ResultsView.properties       |   78 +
 .../darwin/xprottest/util/BrowserLauncher.java     |  583 +++++
 .../util/OptimizationStrategyWrapper.java          |   46 +
 .../darwin/xprottest/util/TextAreaAppender.java    |   31 +
 .../darwin/xprottest/util/TextAreaWriter.java      |   31 +
 src/main/resources/CHANGELOG                       |   40 +
 src/main/resources/COPYING                         |  340 +++
 src/main/resources/README                          |  311 +++
 src/main/resources/THIRDPARTYLICENSES              |  576 +++++
 src/main/resources/examples/COX2_PF0016/alignment  |   30 +
 src/main/resources/examples/COX2_PF0016/tree       |    1 +
 src/main/resources/examples/HIV1.2008.pol.nex      |   37 +
 .../examples/Ribosomal_L5_PF00673/alignment        |   23 +
 .../resources/examples/Ribosomal_L5_PF00673/tree   |    9 +
 src/main/resources/filecluster8.conf.template      |    8 +
 src/main/resources/machines                        |    1 +
 src/main/resources/models/FLU                      |   22 +
 src/main/resources/mpj.tar.gz                      |  Bin 0 -> 3293593 bytes
 src/main/resources/prottest.properties             |  102 +
 src/main/resources/runProtTestHPC.sh               |    4 +
 src/main/resources/runXProtTestHPC.bat             |    1 +
 src/main/resources/runXProtTestHPC.sh              |    1 +
 src/test/resources/VertCOII.trees                  |    8 +
 src/test/resources/VertCOII.trprobs                |   26 +
 src/test/resources/testConsensus.sh                |    6 +
 src/test/resources/treeweights                     |   25 +
 210 files changed, 28987 insertions(+)

diff --git a/COPYING b/COPYING
new file mode 100755
index 0000000..d60c31a
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    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.
diff --git a/INSTALL b/INSTALL
new file mode 100755
index 0000000..0300dbb
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,16 @@
+Basic Installation
+==================
+
+1. Requirements:
+
+* Apache ant 
+	http://ant.apache.org/manual/install.html
+* Java JDK 1.6 
+	http://www.java.com/en/download
+
+2. In a command-line window type:
+
+$ cd $PROTTEST_HOME
+$ ant jar
+
+3. The distribution will be built in $PROTTEST_HOME/dist/
diff --git a/THIRDPARTYLICENSES b/THIRDPARTYLICENSES
new file mode 100755
index 0000000..e725d98
--- /dev/null
+++ b/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/build.xml b/build.xml
new file mode 100755
index 0000000..3c418a9
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<project name="ProtTest" default="default" basedir=".">
+    <description>Builds, tests, and runs the project ProtTest.</description>
+    <import file="buildconf/build-impl.xml"/>
+
+    <property name="src.resources.dir" value="src/main/resources"/>
+    <property name="prottest.lib" value="lib"/>
+
+    <target name="-post-jar">
+        <mkdir dir="${dist.dir}/bin"/>
+	<copy todir="${dist.dir}/bin">
+            <fileset dir="${dist.dir}/bin">
+	      	<include name="**/*"/>
+            </fileset>
+	</copy>
+	<copy todir="${dist.dir}">
+            <fileset dir="${src.resources.dir}">
+  	  	<include name="**/*"/>
+            </fileset>
+  	</copy>
+	<mkdir dir="${dist.dir}/lib"/>
+	<copy todir="${dist.dir}/lib">
+            <fileset dir="${prottest.lib}">
+  	  	<include name="**/*"/>
+            </fileset>
+  	</copy>
+	<chmod perm="755" dir="${dist.dir}/bin" includes="*"/>
+	<chmod perm="755" dir="${dist.dir}" includes="runProtTestHPC.sh"/>
+	<chmod perm="755" dir="${dist.dir}" includes="runXProtTestHPC.sh"/>
+                
+        <delete file="${dist.dir}/README.TXT"/>
+    </target>
+</project>
diff --git a/buildconf/build-impl.xml b/buildconf/build-impl.xml
new file mode 100755
index 0000000..87cdf6d
--- /dev/null
+++ b/buildconf/build-impl.xml
@@ -0,0 +1,707 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+  - initialization
+  - compilation
+  - jar
+  - execution
+  - debugging
+  - javadoc
+  - junit compilation
+  - junit execution
+  - junit debugging
+  - applet
+  - cleanup
+
+        -->
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="ProtTest-HPC-impl">
+    <fail message="Please build using Ant 1.7.1 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.7.1"/>
+            </not>
+        </condition>
+    </fail>
+    <target depends="jar,javadoc" description="Build and test whole project." name="default"/>
+    <!-- 
+                ======================
+                INITIALIZATION SECTION 
+                ======================
+            -->
+    <target name="-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init" name="-init-user">
+        <property file="${user.properties.file}"/>
+        <!-- The two properties below are usually overridden -->
+        <!-- by the active platform. Just a fallback. -->
+        <property name="default.javac.source" value="1.4"/>
+        <property name="default.javac.target" value="1.4"/>
+    </target>
+    <target depends="-pre-init,-init-user" name="-init-project">
+        <property file="buildconf/configs/${config}.properties"/>
+        <property file="buildconf/project.properties"/>
+    </target>
+    <target depends="-pre-init,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+        <available file="${manifest.file}" property="manifest.available"/>
+        <available file="${application.splash}" property="splashscreen.available"/>
+        <condition property="main.class.available">
+            <and>
+                <isset property="main.class"/>
+                <not>
+                    <equals arg1="${main.class}" arg2="" trim="true"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class">
+            <and>
+                <isset property="manifest.available"/>
+                <isset property="main.class.available"/>
+            </and>
+        </condition>
+        <condition property="do.mkdist">
+            <and>
+                <isset property="libs.CopyLibs.classpath"/>
+                <not>
+                    <istrue value="${mkdist.disabled}"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class+mkdist.available">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class+mkdist.available+splashscreen.available">
+            <and>
+                <istrue value="${manifest.available+main.class+mkdist.available}"/>
+                <istrue value="${splashscreen.available}"/>
+            </and>
+        </condition>
+        <condition property="do.archive">
+            <not>
+                <istrue value="${jar.archive.disabled}"/>
+            </not>
+        </condition>
+        <condition property="do.archive+manifest.available">
+            <and>
+                <isset property="manifest.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class+mkdist.available">
+            <and>
+                <istrue value="${manifest.available+main.class+mkdist.available}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class+mkdist.available+splashscreen.available">
+            <and>
+                <istrue value="${manifest.available+main.class+mkdist.available+splashscreen.available}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="have.tests">
+            <or/>
+        </condition>
+        <condition property="have.sources">
+            <or>
+                <available file="${src.java.dir}"/>
+            </or>
+        </condition>
+        <condition property="netbeans.home+have.tests">
+            <and>
+                <isset property="netbeans.home"/>
+                <isset property="have.tests"/>
+            </and>
+        </condition>
+        <condition property="no.javadoc.preview">
+            <and>
+                <isset property="javadoc.preview"/>
+                <isfalse value="${javadoc.preview}"/>
+            </and>
+        </condition>
+        <property name="run.jvmargs" value=""/>
+        <property name="javac.compilerargs" value=""/>
+        <property name="work.dir" value="${basedir}"/>
+        <condition property="no.deps">
+            <and>
+                <istrue value="${no.dependencies}"/>
+            </and>
+        </condition>
+        <property name="javac.debug" value="true"/>
+        <property name="javadoc.preview" value="true"/>
+        <property name="application.args" value=""/>
+        <property name="source.encoding" value="${file.encoding}"/>
+        <property name="runtime.encoding" value="${source.encoding}"/>
+        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+            <and>
+                <isset property="javadoc.encoding"/>
+                <not>
+                    <equals arg1="${javadoc.encoding}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <property name="javadoc.encoding.used" value="${source.encoding}"/>
+        <property name="includes" value="**"/>
+        <property name="excludes" value=""/>
+        <property name="do.depend" value="false"/>
+        <condition property="do.depend.true">
+            <istrue value="${do.depend}"/>
+        </condition>
+        <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+        <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+            <length length="0" string="${endorsed.classpath}" when="greater"/>
+        </condition>
+        <property name="javac.fork" value="false"/>
+        <property name="jar.index" value="false"/>
+        <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
+    </target>
+    <target name="-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init,-init-user,-init-project,-do-init" name="-init-check">
+        <fail unless="src.java.dir">Must set src.java.dir</fail>
+        <fail unless="build.dir">Must set build.dir</fail>
+        <fail unless="dist.dir">Must set dist.dir</fail>
+        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+        <fail unless="dist.jar">Must set dist.jar</fail>
+    </target>
+    <target name="-init-macrodef-property">
+        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${@{value}}"/>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.java.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <mkdir dir="@{apgeneratedsrcdir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <compilerarg value="-processorpath"/>
+                    <compilerarg path="@{processorpath}:${empty.dir}"/>
+                    <compilerarg line="${ap.processors.internal}"/>
+                    <compilerarg line="${annotation.processing.processor.options}"/>
+                    <compilerarg value="-s"/>
+                    <compilerarg path="@{apgeneratedsrcdir}"/>
+                    <compilerarg line="${ap.proc.none.internal}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.java.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
+        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.java.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <sequential>
+                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </depend>
+            </sequential>
+        </macrodef>
+        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <sequential>
+                <fail unless="javac.includes">Must set javac.includes</fail>
+                <pathconvert pathsep="," property="javac.includes.binary">
+                    <path>
+                        <filelist dir="@{destdir}" files="${javac.includes}"/>
+                    </path>
+                    <globmapper from="*.java" to="*.class"/>
+                </pathconvert>
+                <delete>
+                    <files includes="${javac.includes.binary}"/>
+                </delete>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-junit">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <sequential>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}"/>
+                    <classpath>
+                        <path path="${run.test.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="name"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <attribute default="" name="stopclassname"/>
+            <sequential>
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </nbjpdastart>
+            </sequential>
+        </macrodef>
+        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${build.classes.dir}" name="dir"/>
+            <sequential>
+                <nbjpdareload>
+                    <fileset dir="@{dir}" includes="${fix.classes}">
+                        <include name="${fix.includes}*.class"/>
+                    </fileset>
+                </nbjpdareload>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-debug-args">
+        <property name="version-output" value="java version "${ant.java.version}"/>
+        <condition property="have-jdk-older-than-1.4">
+            <or>
+                <contains string="${version-output}" substring="java version "1.0"/>
+                <contains string="${version-output}" substring="java version "1.1"/>
+                <contains string="${version-output}" substring="java version "1.2"/>
+                <contains string="${version-output}" substring="java version "1.3"/>
+            </or>
+        </condition>
+        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+            <istrue value="${have-jdk-older-than-1.4}"/>
+        </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-debug">
+        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-java">
+        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${run.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-copylibs">
+        <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+                <pathconvert property="run.classpath.without.build.classes.dir">
+                    <path path="${run.classpath}"/>
+                    <map from="${build.classes.dir.resolved}" to=""/>
+                </pathconvert>
+                <pathconvert pathsep=" " property="jar.classpath">
+                    <path path="${run.classpath.without.build.classes.dir}"/>
+                    <chainedmapper>
+                        <flattenmapper/>
+                        <globmapper from="*" to="lib/*"/>
+                    </chainedmapper>
+                </pathconvert>
+                <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+                <copylibs compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+                    <fileset dir="${build.classes.dir}"/>
+                    <manifest>
+                        <attribute name="Class-Path" value="${jar.classpath}"/>
+                        <customize/>
+                    </manifest>
+                </copylibs>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-presetdef-jar">
+        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
+                <j2seproject1:fileset dir="${build.classes.dir}"/>
+            </jar>
+        </presetdef>
+    </target>
+    <target name="-init-ap-cmdline-properties">
+        <property name="annotation.processing.enabled" value="true"/>
+        <property name="annotation.processing.processors.list" value=""/>
+        <property name="annotation.processing.processor.options" value=""/>
+        <property name="annotation.processing.run.all.processors" value="true"/>
+        <property name="javac.processorpath" value="${javac.classpath}"/>
+        <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+        <condition property="ap.supported.internal" value="true">
+            <not>
+                <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
+        <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+            <isfalse value="${annotation.processing.run.all.processors}"/>
+        </condition>
+        <condition else="" property="ap.proc.none.internal" value="-proc:none">
+            <isfalse value="${annotation.processing.enabled}"/>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+        <property name="ap.cmd.line.internal" value=""/>
+    </target>
+    <target depends="-pre-init,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+    <!--
+                ===================
+                COMPILATION SECTION
+                ===================
+            -->
+    <target name="-deps-jar-init" unless="built-jar.properties">
+        <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+        <delete file="${built-jar.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+        <echo level="warn" message="Cycle detected: ProtTest-HPC was already built"/>
+    </target>
+    <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-jar.properties}" verbose="false"/>
+        <property file="${built-jar.properties}" prefix="already.built.jar."/>
+        <antcall target="-warn-already-built-jar"/>
+        <propertyfile file="${built-jar.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+    <target depends="init" name="-check-automatic-build">
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+    </target>
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+        <antcall target="clean"/>
+    </target>
+    <target depends="init,deps-jar" name="-pre-pre-compile">
+        <mkdir dir="${build.classes.dir}"/>
+    </target>
+    <target name="-pre-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-depend">
+        <pathconvert property="build.generated.subdirs">
+            <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="*"/>
+            </dirset>
+        </pathconvert>
+        <j2seproject3:depend srcdir="${src.java.dir}:${build.generated.subdirs}"/>
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
+        <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.classes.dir}">
+            <fileset dir="${src.java.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target if="has.persistence.xml" name="-copy-persistence-xml">
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy todir="${build.classes.dir}/META-INF">
+            <fileset dir="${meta.inf.dir}" includes="persistence.xml"/>
+        </copy>
+    </target>
+    <target name="-post-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+    <target name="-pre-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile/>
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.java.dir}"/>
+    </target>
+    <target name="-post-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+    <!--
+                ====================
+                JAR BUILDING SECTION
+                ====================
+            -->
+    <target depends="init" name="-pre-pre-jar">
+        <dirname file="${dist.jar}" property="dist.jar.dir"/>
+        <mkdir dir="${dist.jar.dir}"/>
+    </target>
+    <target name="-pre-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive" name="-do-jar-without-manifest" unless="manifest.available">
+        <j2seproject1:jar/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
+        <j2seproject1:jar manifest="${manifest.file}"/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}">
+            <j2seproject1:manifest>
+                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
+            </j2seproject1:manifest>
+        </j2seproject1:jar>
+        <echo>To run this application from the command line without Ant, try:</echo>
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <pathconvert property="run.classpath.with.dist.jar">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+        </pathconvert>
+        <echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-init-macrodef-copylibs" if="do.archive+manifest.available+main.class+mkdist.available+splashscreen.available" name="-do-jar-with-libraries-and-splashscreen">
+        <basename file="${application.splash}" property="splashscreen.basename"/>
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
+        <j2seproject3:copylibs>
+            <customize>
+                <attribute name="Main-Class" value="${main.class}"/>
+                <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+            </customize>
+        </j2seproject3:copylibs>
+        <echo>To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo>java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-init-macrodef-copylibs" if="do.archive+manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries" unless="splashscreen.available">
+        <j2seproject3:copylibs>
+            <customize>
+                <attribute name="Main-Class" value="${main.class}"/>
+            </customize>
+        </j2seproject3:copylibs>
+        <echo>To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo>java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target name="-post-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries-and-splashscreen,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
+    <!--
+                =================
+                EXECUTION SECTION
+                =================
+            -->
+    <target depends="init,compile" description="Run a main class." name="run">
+        <j2seproject1:java>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <target name="-do-not-recompile">
+        <property name="javac.includes.binary" value=""/>
+    </target>
+    <target depends="init,compile-single" name="run-single">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}"/>
+    </target>
+    
+    <!--
+                ===============
+                JAVADOC SECTION
+                ===============
+            -->
+    <target depends="init" if="have.sources" name="-javadoc-build">
+        <mkdir dir="${dist.javadoc.dir}"/>
+        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+            <classpath>
+                <path path="${javac.classpath}"/>
+            </classpath>
+            <fileset dir="${src.java.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/*.java"/>
+            </fileset>
+        </javadoc>
+        <copy todir="${dist.javadoc.dir}">
+            <fileset dir="${src.java.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/doc-files/**"/>
+            </fileset>
+        </copy>
+    </target>
+    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+    </target>
+    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+   
+    <!--
+                ===============
+                CLEANUP SECTION
+                ===============
+            -->
+    <target name="-deps-clean-init" unless="built-clean.properties">
+        <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+        <delete file="${built-clean.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+        <echo level="warn" message="Cycle detected: ProtTest-HPC was already built"/>
+    </target>
+    <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-clean.properties}" verbose="false"/>
+        <property file="${built-clean.properties}" prefix="already.built.clean."/>
+        <antcall target="-warn-already-built-clean"/>
+        <propertyfile file="${built-clean.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init" name="-do-clean">
+        <delete dir="${build.dir}"/>
+        <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+    </target>
+    <target name="-post-clean">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+    <target name="-check-call-dep">
+        <property file="${call.built.properties}" prefix="already.built."/>
+        <condition property="should.call.dep">
+            <not>
+                <isset property="already.built.${call.subproject}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+        <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+            <propertyset>
+                <propertyref prefix="transfer."/>
+                <mapper from="transfer.*" to="*" type="glob"/>
+            </propertyset>
+        </ant>
+    </target>
+</project>
diff --git a/buildconf/project.properties b/buildconf/project.properties
new file mode 100755
index 0000000..1434886
--- /dev/null
+++ b/buildconf/project.properties
@@ -0,0 +1,79 @@
+application.homepage=http://darwin.uvigo.es
+application.title=ProtTest
+application.vendor=Diego Darriba
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+debug.classpath=\
+    ${run.classpath}
+debug.test.classpath=\
+    ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/prottest-3.4.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+excludes=
+file.reference.AbsoluteLayout.jar=lib/AbsoluteLayout.jar
+file.reference.appframework-1.0.3.jar=lib/appframework-1.0.3.jar
+file.reference.alter.jar=lib/alter.jar
+file.reference.mpj.jar=lib/mpj.jar
+file.reference.pal.jar=lib/pal.jar
+file.reference.ProtTest-HPC-src=src
+file.reference.swing-worker-1.1.jar=lib/swing-worker-1.1.jar
+includes=**
+jar.compress=false
+javac.classpath=\
+    ${file.reference.AbsoluteLayout.jar}:\
+    ${file.reference.appframework-1.0.3.jar}:\
+    ${file.reference.mpj.jar}:\
+    ${file.reference.pal.jar}:\
+    ${file.reference.alter.jar}:\
+    ${file.reference.swing-worker-1.1.jar}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=true
+javac.source=1.5
+javac.target=1.6
+javac.test.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}:\
+    ${libs.junit_4.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+# Property libs.absolutelayout.classpath is set here just to make sharing of project simpler.
+# The library definition has always preference over this property.
+libs.absolutelayout.classpath=lib/AbsoluteLayout.jar
+#libs.CopyLibs.classpath=lib/org-netbeans-modules-java-j2seproject-copylibstask.jar
+libs.CopyLibs.classpath=lib/copylibs.jar
+main.class=es.uvigo.darwin.prottest.ProtTest
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+platform.active=default_platform
+run.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project
+# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
+# or test-sys-prop.name=value to set system properties for unit tests):
+run.jvmargs=
+run.test.classpath=\
+    ${javac.test.classpath}:\
+    ${build.test.classes.dir}
+source.encoding=UTF-8
+src.java.dir=src/main/java
+test.java.dir=src/test/java
diff --git a/lib/AbsoluteLayout.jar b/lib/AbsoluteLayout.jar
new file mode 100755
index 0000000..2cd68a5
Binary files /dev/null and b/lib/AbsoluteLayout.jar differ
diff --git a/lib/copylibs.jar b/lib/copylibs.jar
new file mode 100755
index 0000000..47dcc3b
Binary files /dev/null and b/lib/copylibs.jar differ
diff --git a/lib/swing-worker-1.1.jar b/lib/swing-worker-1.1.jar
new file mode 100755
index 0000000..bcdd9d9
Binary files /dev/null and b/lib/swing-worker-1.1.jar differ
diff --git a/manifest.mf b/manifest.mf
new file mode 100755
index 0000000..cd51d93
--- /dev/null
+++ b/manifest.mf
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0
+Ant-Version: Apache Ant 1.7.1
+Created-By: 19.0-b09 (Sun Microsystems Inc.)
+Main-Class: es.uvigo.darwin.prottest.ProtTest
+Class-Path: lib/AbsoluteLayout.jar lib/appframework-1.0.3.jar lib/mpj.
+ jar lib/pal.jar lib/alter.jar lib/swing-worker-1.1.jar
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/src/main/java/META-INF/services/org.jdesktop.application.Application b/src/main/java/META-INF/services/org.jdesktop.application.Application
new file mode 100755
index 0000000..b104306
--- /dev/null
+++ b/src/main/java/META-INF/services/org.jdesktop.application.Application
@@ -0,0 +1 @@
+xprottest.XProtTestApp
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/prottest/ProtTest.java b/src/main/java/es/uvigo/darwin/prottest/ProtTest.java
new file mode 100755
index 0000000..0077f8b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/ProtTest.java
@@ -0,0 +1,363 @@
+/*
+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.prottest;
+
+import static es.uvigo.darwin.prottest.global.ApplicationGlobals.*;
+
+import es.uvigo.darwin.prottest.consensus.Consensus;
+import mpi.MPI;
+import es.uvigo.darwin.prottest.facade.ProtTestFacade;
+import es.uvigo.darwin.prottest.facade.ProtTestFacadeMPJ;
+import es.uvigo.darwin.prottest.facade.ProtTestFacadeSequential;
+import es.uvigo.darwin.prottest.facade.ProtTestFacadeThread;
+import es.uvigo.darwin.prottest.facade.TreeFacade;
+import es.uvigo.darwin.prottest.facade.TreeFacadeImpl;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ModelUpdaterObserver;
+import es.uvigo.darwin.prottest.observer.ObservableModelUpdater;
+import es.uvigo.darwin.prottest.selection.AIC;
+import es.uvigo.darwin.prottest.selection.AICc;
+import es.uvigo.darwin.prottest.selection.BIC;
+import es.uvigo.darwin.prottest.selection.DT;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.selection.LNL;
+import es.uvigo.darwin.prottest.selection.printer.PrintFramework;
+import es.uvigo.darwin.prottest.util.FixedBitSet;
+import es.uvigo.darwin.prottest.util.argumentparser.ProtTestArgumentParser;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.factory.ProtTestFactory;
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import es.uvigo.darwin.prottest.util.printer.ProtTestPrinter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import pal.misc.Identifier;
+import pal.tree.Tree;
+
+/**
+ * This is the main class of ProtTest. It calls the methods in the
+ * concrete facade to interact with the model layer of the application.
+ * 
+ * @author Diego Darriba
+ */
+public class ProtTest {
+
+    /** The Constant versionNumber. */
+    public static final String versionNumber = "3.4";
+    /** The Constant versionDate. */
+    public static final String versionDate = "23th January 2014";
+    /** 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;
+    /** The ProtTest factory. */
+    private static ProtTestFactory factory;
+
+    /**
+     * The main method. It initializes the MPJ runtime environment, parses 
+     * the application arguments, initializes the application options and 
+     * starts the analysis of the substitution models.
+     * 
+     * @param args the arguments
+     */
+    public static void main(String[] args) {
+
+        try {
+            args = ProtTestFactory.initialize(args);
+        } catch (IllegalArgumentException e) {
+            System.out.println("Illegal argument: " + e.getMessage());
+            finalize(1);
+        }
+        factory = ProtTestFactory.getInstance();
+
+        // initializing MPJ environment (if available)
+        try {
+            String[] argsApp = MPI.Init(args);
+            MPJ_ME = MPI.COMM_WORLD.Rank();
+            MPJ_SIZE = MPI.COMM_WORLD.Size();
+            MPJ_RUN = true;
+            args = argsApp;
+        } catch (Exception e) {
+            MPJ_ME = 0;
+            MPJ_SIZE = 1;
+            MPJ_RUN = false;
+        }
+
+        ProtTestLogger logger = ProtTestLogger.getDefaultLogger();
+        logger.setStdHandlerLevel(Level.INFO);
+        
+        // parse arguments
+        ApplicationOptions opts = new ApplicationOptions();
+
+        int numThreads = 1;
+        try {
+            // check arguments and get application options
+            numThreads = Integer.parseInt(
+                    factory.createProtTestArgumentParser(args, opts).
+                    getValue(ProtTestArgumentParser.PARAM_NUM_THREADS));
+        } catch (IllegalArgumentException e) {
+            if (MPJ_ME == 0) {
+                System.err.println("\n" + e.getMessage() + "\n");
+                ApplicationOptions.usage();
+            }
+            finalize(1);
+        } catch (ProtTestInternalException e) {
+            if (MPJ_ME == 0) {
+                System.err.println(e.getMessage());
+            }
+            finalize(1);
+        } catch (ExceptionInInitializerError e) {
+            if (MPJ_ME == 0) {
+                System.err.println("An error has occurred while initializing. Check your prottest.properties file.");
+            }
+            finalize(1);
+        }
+
+        if (MPJ_ME == 0) {
+            try {
+            	if (opts.isLogEnabled()) {
+	                Handler logHandler = factory.createLogHandler();
+	                if (logHandler != null) {
+	                    logger.addHandler(logHandler);
+	                }
+            	}
+            } catch (IOException ex) {
+                logger.severeln(ex.getMessage());
+            }
+        }
+        
+        // get the facade instance
+        TreeFacade treeFacade = new TreeFacadeImpl();
+        ProtTestFacade facade;
+        if (MPJ_RUN) {
+            facade = new ProtTestFacadeMPJ(MPJ_RUN, MPJ_ME, MPJ_SIZE);
+        } else if (numThreads > 1) {
+            facade = new ProtTestFacadeThread(numThreads);
+        } else {
+            facade = new ProtTestFacadeSequential();
+        }
+
+        /* if multiple models are optimized together, the execution will be
+        monitorized  */
+        if (MPJ_RUN || numThreads > 1) {
+            facade.addObserver(new ModelUpdaterObserver() {
+
+                @Override
+                public void update(ObservableModelUpdater o, Model model,
+                        ApplicationOptions options) {
+                    if (model.isComputed() && options != null) {
+                        System.out.println("Computed: " + model.getModelName() + " (" + model.getLk() + ")");
+                    } else {
+                        System.out.println("Computing " + model.getModelName() + "...");
+                    }
+
+                }
+            });
+        }
+
+        if (opts.isDebug()) {
+            logger.setStdHandlerLevel(Level.ALL);
+        }
+
+        if (MPJ_ME == 0) {
+            ProtTestPrinter.printHeader();
+            opts.reportComplete();
+        }
+
+        Model[] models;
+        try {
+
+            // model optimization
+            models = facade.startAnalysis(opts);
+
+            // analyze results
+            if (MPJ_ME == 0) {
+                ModelCollection allModelsList =
+                        new SingleModelCollection(models, opts.getAlignment());
+
+                InformationCriterion aic, aicc, bic, dt, lnc;
+                if (opts.isAIC()) {
+                    printCriterion(
+                            "AIC", new AIC(allModelsList, 1.0, opts.getSampleSize()),
+                            logger, opts, facade, treeFacade);
+                }
+                if (opts.isBIC()) {
+                    printCriterion(
+                            "BIC", new BIC(allModelsList, 1.0, opts.getSampleSize()),
+                            logger, opts, facade, treeFacade);
+                }
+                if (opts.isAICc()) {
+                    printCriterion(
+                            "AICc", new AICc(allModelsList, 1.0, opts.getSampleSize()),
+                            logger, opts, facade, treeFacade);
+                }
+                if (opts.isDT()) {
+                    printCriterion(
+                            "DT", new DT(allModelsList, 1.0, opts.getSampleSize()),
+                            logger, opts, facade, treeFacade);
+                }
+                if (!(opts.isAIC() | opts.isDT() | opts.isAICc() | opts.isDT())) {
+                    printCriterion(
+                            "lnL", new LNL(allModelsList, 1.0, opts.getSampleSize()),
+                            logger, opts, facade, treeFacade);
+                }
+
+                // display 7-framework comparison
+                if (opts.isAll()) {
+                    PrintFramework.printFrameworksComparison(allModelsList);
+                }
+
+            }
+
+        } catch (ProtTestInternalException e) {
+            logger.severeln(e.getMessage());
+            finalize(-1);
+        } catch (UnsupportedOperationException e) {
+            logger.severeln(e.getMessage());
+            finalize(-1);
+        }
+
+        // finalize execution
+
+        finalize(0);
+
+        if (MPJ_RUN) {
+            MPI.Finalize();
+        }
+    }
+
+    private static void printCriterion(String name, InformationCriterion ic, ProtTestLogger logger, ApplicationOptions opts,
+            ProtTestFacade facade, TreeFacade treeFacade) {
+        // let's print results:
+        facade.printModelsSorted(ic);
+
+        // display best model tree in ASCII
+        if (opts.isDisplayASCIITree()) {
+            ProtTestPrinter.printTreeHeader(ic.getBestModel().getModelName());
+            logger.infoln(treeFacade.toASCII(ic.getBestModel().getTree()));
+        }
+
+        // display best model tree in Newick
+        if (opts.isDisplayNewickTree()) {
+            if (!opts.isDisplayASCIITree()) {
+                ProtTestPrinter.printTreeHeader(ic.getBestModel().getModelName());
+            }
+            logger.infoln(treeFacade.toNewick(ic.getBestModel().getTree(), true, true, false));
+        }
+
+        // display consensus tree data
+        if (opts.isDisplayConsensusTree()) {
+
+            ProtTestPrinter.printTreeHeader("MODEL AVERAGED PHYLOGENY");
+            Consensus consensus = treeFacade.createConsensus(ic, opts.getConsensusThreshold());
+
+            logger.infoln("----------------------------------------");
+            logger.infoln("Selection criterion: . . . . " + name);
+            logger.infoln("Confidence interval: . . . . " + ic.getConfidenceInterval());
+            logger.infoln("Sample size: . . . . . . . . " + opts.getSampleSize());
+            logger.infoln("Consensus support threshold: " + opts.getConsensusThreshold());
+            logger.infoln("----------------------------------------");
+            logger.infoln("");
+
+            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 < opts.getConsensusThreshold()) {
+                        splitsOutFromConsensus.add(fbs);
+                    } else {
+                        splitsInConsensus.add(fbs);
+                    }
+                }
+            }
+
+            logger.infoln("# # # # # # # # # # # # # # # #");
+            logger.infoln(" ");
+            logger.infoln("Species in order:");
+            logger.infoln(" ");
+
+            for (int i = 0; i < consensus.getIdGroup().getIdCount(); i++) {
+                Identifier id = consensus.getIdGroup().getIdentifier(i);
+                logger.infoln("    " + (i + 1) + ". " + id.getName());
+            }
+            logger.infoln(" ");
+            logger.infoln("# # # # # # # # # # # # # # # #");
+            logger.infoln(" ");
+            logger.infoln("Sets included in the consensus tree");
+            logger.infoln(" ");
+
+            int numTaxa = consensus.getIdGroup().getIdCount();
+            logger.infoln(consensus.getSetsIncluded());
+
+            logger.infoln(" ");
+            logger.infoln("Sets NOT included in consensus tree");
+            logger.infoln(" ");
+
+            logger.infoln(consensus.getSetsNotIncluded());
+
+            logger.infoln(" ");
+            logger.infoln("# # # # # # # # # # # # # # # #");
+            logger.infoln(" ");
+            Tree consensusTree = consensus.getConsensusTree();
+            String newickTree = treeFacade.toNewick(consensusTree, true, true, true);
+            logger.infoln(newickTree);
+            logger.infoln(" ");
+            logger.infoln("# # # # # # # # # # # # # # # #");
+            logger.infoln(" ");
+            logger.infoln(treeFacade.toASCII(consensusTree));
+            logger.infoln("");
+            logger.infoln(treeFacade.branchInfo(consensusTree));
+            logger.infoln("");
+            logger.infoln(treeFacade.heightInfo(consensusTree));
+
+        }
+    }
+
+    /**
+     * 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);
+
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/consensus/Consensus.java b/src/main/java/es/uvigo/darwin/prottest/consensus/Consensus.java
new file mode 100755
index 0000000..de886d7
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/consensus/Consensus.java
@@ -0,0 +1,911 @@
+/*
+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.prottest.consensus;
+
+import es.uvigo.darwin.prottest.tree.WeightedTree;
+import es.uvigo.darwin.prottest.util.fileio.SimpleNewickTreeReader;
+import es.uvigo.darwin.prottest.util.fileio.NexusTreeReader;
+import es.uvigo.darwin.prottest.util.fileio.TreeReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.PriorityQueue;
+
+import pal.misc.IdGroup;
+import pal.tree.Node;
+import pal.tree.NodeFactory;
+import pal.tree.SimpleTree;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.selection.model.SelectionModel;
+import es.uvigo.darwin.prottest.tree.TreeUtils;
+import es.uvigo.darwin.prottest.util.FixedBitSet;
+import es.uvigo.darwin.prottest.util.Utilities;
+import es.uvigo.darwin.prottest.util.exception.ImportException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.fileio.NexusExporter;
+import es.uvigo.darwin.prottest.util.printer.ProtTestFormattedOutput;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+import pal.misc.Identifier;
+
+/**
+ * Phylogenetic consensus tree builder.
+ * 
+ * @author Diego Darriba
+ * @since 3.0
+ */
+public class Consensus {
+
+    /** Display branch suport as percent. */
+    final static public boolean SUPPORT_AS_PERCENT = false;
+    /** Calculate branch lengths as weighted average. */
+    final static public int BRANCH_LENGTHS_AVERAGE = 1;
+    /** Calculate branch lengths as weighted median. */
+    final static public int BRANCH_LENGTHS_MEDIAN = 2;
+    /** Default branch lengths algorithm */
+    private static final BranchDistances DEFAULT_BRANCH_DISTANCES =
+            BranchDistances.WeightedMedian;
+    /** The Constant FIRST (just for source code visibility). */
+    private static final int FIRST = 0;
+    /** The weighted trees in consensus. */
+    private List<WeightedTree> trees;
+    /** The cummulative weight. */
+    private double cumWeight = 0.0;
+    /** The number of taxa. */
+    private int numTaxa;
+    /** The common id group of the tree set. */
+    private IdGroup idGroup;
+    /** The set of clade supports. */
+    private Map<FixedBitSet, Support> support =
+            new HashMap<FixedBitSet, Support>();
+    /** The set of clade supports to get from outside this class. */
+    private Map<FixedBitSet, Double> cladeSupport;
+    /** The inner consensus tree. */
+    private Tree consensusTree;
+    /** The splits included in consensus tree */
+    private List<FixedBitSet> splitsInConsensus = new ArrayList<FixedBitSet>();
+    /** The splits not included in consensus tree */
+    private List<FixedBitSet> splitsOutFromConsensus = new ArrayList<FixedBitSet>();
+
+    /**
+     * Gets the clade support, with Support instances
+     * 
+     * @return the map of the support for each bitSet
+     */
+    private Map<FixedBitSet, Support> getSupport() {
+        return support;
+    }
+
+    /**
+     * Gets the double precision clade support
+     * 
+     * @return the map of the support for each bitSet
+     */
+    public Map<FixedBitSet, Double> getCladeSupport() {
+
+        if (cladeSupport == null) {
+            cladeSupport = new HashMap<FixedBitSet, Double>(support.size());
+            FixedBitSet[] keys = support.keySet().toArray(new FixedBitSet[0]);
+            Arrays.sort(keys);
+
+            for (FixedBitSet fbs : keys) {
+                cladeSupport.put(fbs, support.get(fbs).treesWeightWithClade / cumWeight);
+            }
+        }
+        return cladeSupport;
+    }
+
+    /**
+     * Gets the Id Group of the set of trees
+     * 
+     * @return the id group
+     */
+    public IdGroup getIdGroup() {
+        return idGroup;
+    }
+
+    /**
+     * Gets the consensus tree
+     * 
+     * @return the consensus tree
+     */
+    public Tree getConsensusTree() {
+        return consensusTree;
+    }
+
+    /**
+     * Gets the set of trees included in the consensus.
+     * 
+     * @return the trees
+     */
+    public Collection<WeightedTree> getTrees() {
+        return trees;
+    }
+
+    /**
+     * Adds a weighted tree to the set.
+     * 
+     * @param wTree the weighted tree
+     * 
+     * @return true, if successful
+     */
+    private boolean addTree(WeightedTree wTree) {
+        //check integrity
+        if (wTree.getTree() == null || wTree.getWeight() < 0.0) {
+            throw new ProtTestInternalException();
+        }
+        //check compatibility
+        if (trees.isEmpty()) {
+            trees.add(wTree);
+            numTaxa = wTree.getTree().getIdCount();
+            idGroup = pal.tree.TreeUtils.getLeafIdGroup(wTree.getTree());
+        } else {
+            if (wTree.getTree().getIdCount() != numTaxa) {
+                return false;
+            }
+            Tree pTree = trees.get(FIRST).getTree();
+            for (int i = 0; i < numTaxa; i++) {
+                boolean found = false;
+                for (int j = 0; j < numTaxa; j++) {
+                    if (wTree.getTree().getIdentifier(i).equals(pTree.getIdentifier(j))) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found) {
+                    System.out.println("NOT COMPATIBLE TREES");
+                    return false;
+                }
+            }
+            trees.add(wTree);
+        }
+        cumWeight += wTree.getWeight();
+        return true;
+    }
+
+    /**
+     * Instantiates a new consensus tree builder.
+     * 
+     * @param ic the information criterion to build the weighted trees
+     * @param supportThreshold the minimum support for a clade
+     */
+    public Consensus(InformationCriterion ic, double supportThreshold) {
+        this(ic, supportThreshold, 0);
+    }
+
+    /**
+     * Instantiates a new consensus tree builder.
+     * 
+     * @param ic the information criterion to build the weighted trees
+     * @param supportThreshold the minimum support for a clade
+     * @param branchDistances the method to get the consensus branch lengths
+     */
+    public Consensus(InformationCriterion ic, double supportThreshold, int branchDistances) {
+        this.trees = new ArrayList<WeightedTree>();
+        for (SelectionModel model : ic.getConfidenceModels()) {
+            WeightedTree wTree = new WeightedTree(
+                    model.getModel().getTree(),
+                    model.getWeightValue());
+            this.addTree(wTree);
+        }
+        consensusTree = buildTree(supportThreshold, getBranchDistances(branchDistances));
+    }
+
+    /**
+     * Instantiates a new unweighted consensus builder.
+     *
+     * @param trees the trees
+     * @param supportThreshold the minimum support for a clade
+     * @param branchDistances the method to get the consensus branch lengths
+     */
+    public Consensus(List<WeightedTree> trees, double supportThreshold, int branchDistances) {
+        this.trees = new ArrayList<WeightedTree>();
+        for (WeightedTree tree : trees) {
+            this.addTree(tree);
+        }
+
+        consensusTree = buildTree(supportThreshold, getBranchDistances(branchDistances));
+    }
+
+    /**
+     * Instantiates a new unweighted consensus builder.
+     * 
+     * @param treesFile the file with the set of trees in Newick format
+     * @param supportThreshold the minimum support for a clade
+     * @throws IOException 
+     */
+    public Consensus(File treesFile, double supportThreshold)
+            throws ProtTestInternalException, IOException {
+
+        this(treesFile, supportThreshold, 0);
+
+    }
+
+    /**
+     * Instantiates a new unweighted consensus builder.
+     * 
+     * @param treesFile the file with the set of trees in Newick format
+     * @param supportThreshold the minimum support for a clade
+     * @param branchDistances the method to get the consensus branch lengths
+     * @throws IOException 
+     */
+    public Consensus(File treesFile, double supportThreshold, int branchDistances)
+            throws ProtTestInternalException, IOException {
+
+        TreeReader treeReader;
+
+        try {
+            treeReader = new NexusTreeReader(treesFile);
+        } catch (ImportException ex) {
+            treeReader = new SimpleNewickTreeReader(treesFile);
+        }
+
+        this.trees = treeReader.getWeightedTreeList();
+        this.cumWeight = treeReader.getCumWeight();
+        this.numTaxa = treeReader.getNumTaxa();
+        this.idGroup = treeReader.getIdGroup();
+
+        consensusTree = buildTree(supportThreshold, getBranchDistances(branchDistances));
+
+        String fileName = treesFile.getName();
+        if (fileName.contains(".")) {
+            fileName = fileName.substring(0, fileName.lastIndexOf("."));
+        }
+
+        File resultDir = new File("results");
+        if (!resultDir.exists()) {
+            resultDir.mkdir();
+        }
+        File outFile = File.createTempFile(fileName, ".con", resultDir);
+
+        NexusExporter nw = new NexusExporter(outFile);
+        nw.printConsensusBlock(consensusTree, ((NexusTreeReader) treeReader).getNexusId());
+        nw.close();
+
+    }
+
+    /**
+     * Calculates rooted support.
+     * 
+     * @param wTree the weighted tree instance
+     * @param node the node
+     * @param support the support
+     * 
+     * @return the fixed bit set
+     */
+    private FixedBitSet rootedSupport(WeightedTree wTree, Node node, Map<FixedBitSet, Support> support) {
+        FixedBitSet clade = new FixedBitSet(numTaxa);
+        if (node.isLeaf()) {
+            clade.set(idGroup.whichIdNumber(node.getIdentifier().getName()));
+        } else {
+            for (int i = 0; i < node.getChildCount(); i++) {
+                Node n = node.getChild(i);
+                FixedBitSet childClade = rootedSupport(wTree, n, support);
+                clade.union(childClade);
+            }
+        }
+
+        Support s = support.get(clade);
+        if (s == null) {
+            s = new Support();
+            support.put(clade, s);
+        }
+        s.add(wTree.getWeight(), TreeUtils.safeNodeHeight(wTree.getTree(), node), node.getBranchLength());
+        return clade;
+    }
+
+    /**
+     * Detach the children of a tree.
+     * 
+     * @param tree the tree
+     * @param node the node to detach
+     * @param split the split
+     * 
+     * @return the node
+     */
+    public Node detachChildren(Tree tree, Node node, List<Integer> split) {
+        assert (split.size() > 1);
+
+        List<Node> detached = new ArrayList<Node>();
+
+        for (int n : split) {
+            detached.add(node.getChild(n));
+        }
+
+        Node saveRoot = tree.getRoot();
+
+        List<Integer> toRemove = new ArrayList<Integer>();
+        for (int i = 0; i < node.getChildCount(); i++) {
+            Node n = node.getChild(i);
+            if (detached.contains(n)) {
+                toRemove.add(0, i);
+            }
+        }
+        for (int i : toRemove) {
+            node.removeChild(i);
+        }
+
+        Node dnode = NodeFactory.createNode(detached.toArray(new Node[0]));
+        node.addChild(dnode);
+
+        tree.setRoot(saveRoot);
+
+        return dnode;
+    }
+
+    /**
+     * Builds the consensus tree over a set of weighted trees.
+     * 
+     * @param supportThreshold the minimum support to consider a split into the consensus tree
+     * 
+     * @return the consensus tree
+     */
+    private Tree buildTree(double supportThreshold, BranchDistances branchDistances) {
+
+        if (trees.isEmpty()) {
+            throw new ProtTestInternalException("There are no trees to consense");
+        }
+
+        if (supportThreshold < 0.5 || supportThreshold > 1.0) {
+            throw new ProtTestInternalException("Invalid threshold value: " + supportThreshold);
+        }
+        
+        double effectiveThreshold = supportThreshold;
+        if (supportThreshold == 0.5) {
+            effectiveThreshold += 1.0/(numTaxa+1);
+        } else if (supportThreshold == 1.0) {
+            effectiveThreshold -= 1.0/(numTaxa+1);
+        }
+
+        // establish support
+        support = new HashMap<FixedBitSet, Support>();
+        int k = 0;
+        for (WeightedTree wTree : trees) {
+            rootedSupport(wTree, wTree.getTree().getRoot(), support);
+
+            ++k;
+
+        }
+
+        Tree cons = new SimpleTree();
+
+        // Contains all internal nodes in the tree so far, ordered so descendants
+        // appear later than ancestors
+        List<Node> internalNodes = new ArrayList<Node>(numTaxa);
+
+        // For each internal node, a bit-set with the complete set of tips for it's clade
+        List<FixedBitSet> internalNodesTips = new ArrayList<FixedBitSet>(numTaxa);
+        assert idGroup.getIdCount() == numTaxa;
+
+        // establish a tree with one root having all tips as descendants
+        internalNodesTips.add(new FixedBitSet(numTaxa));
+        FixedBitSet rooNode = internalNodesTips.get(0);
+        Node[] nodes = new Node[numTaxa];
+        for (int nt = 0; nt < numTaxa; ++nt) {
+            nodes[nt] = NodeFactory.createNode(idGroup.getIdentifier(nt));
+            rooNode.set(nt);
+        }
+
+        Node rootNode = NodeFactory.createNode(nodes);
+        internalNodes.add(rootNode);
+        cons.setRoot(rootNode);
+        // sorts support from largest to smallest
+        final Comparator<Map.Entry<FixedBitSet, Support>> comparator = new Comparator<Map.Entry<FixedBitSet, Support>>() {
+
+            @Override
+            public int compare(Map.Entry<FixedBitSet, Support> o1, Map.Entry<FixedBitSet, Support> o2) {
+                double diff = o2.getValue().treesWeightWithClade - o1.getValue().treesWeightWithClade;
+                if (diff > 0.0) {
+                    return 1;
+                } else if (diff < 0.0) {
+                    return -1;
+                } else {
+                    return 0;
+                }
+            }
+        };
+
+        // add everything to queue
+        PriorityQueue<Map.Entry<FixedBitSet, Support>> queue =
+                new PriorityQueue<Map.Entry<FixedBitSet, Support>>(support.size(), comparator);
+
+        for (Map.Entry<FixedBitSet, Support> se : support.entrySet()) {
+            Support s = se.getValue();
+            FixedBitSet clade = se.getKey();
+            final int cladeSize = clade.cardinality();
+            if (cladeSize == numTaxa) {
+                // root
+                cons.getRoot().setNodeHeight(s.sumBranches / trees.size());
+                cons.getRoot().setBranchLength(branchDistances.build(s.branchLengths));
+                continue;
+            }
+
+            if (Math.abs(s.treesWeightWithClade - this.cumWeight) < 1e-5 && cladeSize == 1) {
+                // leaf/external node
+                final int nt = clade.nextOnBit(FIRST);
+                final Node leaf = cons.getExternalNode(nt);
+                leaf.setNodeHeight(s.sumBranches / trees.size());
+                leaf.setBranchLength(branchDistances.build(s.branchLengths));
+            } else {
+                queue.add(se);
+            }
+        }
+
+        while (queue.peek() != null) {
+            Map.Entry<FixedBitSet, Support> e = queue.poll();
+            final Support s = e.getValue();
+
+            final double psupport = (1.0 * s.treesWeightWithClade) / cumWeight;
+            if (psupport < effectiveThreshold) {
+                break;
+            }
+
+            final FixedBitSet cladeTips = e.getKey();
+
+            boolean found = false;
+
+            /* locate the node containing the clade. going in reverse order 
+            ensures the lowest one is hit first */
+            for (int nsub = internalNodesTips.size() - 1; nsub >= 0; --nsub) {
+
+                FixedBitSet allNodeTips = internalNodesTips.get(nsub);
+
+                // size of intersection between tips & split
+                final int nSplit = allNodeTips.intersectCardinality(cladeTips);
+
+                if (nSplit == cladeTips.cardinality()) {
+                    // node contains all of clade
+
+                    // Locate node descendants containing the split
+                    found = true;
+                    List<Integer> split = new ArrayList<Integer>();
+
+                    Node n = internalNodes.get(nsub);
+                    int l = 0;
+
+                    for (int j = 0; j < n.getChildCount(); j++) {
+                        Node ch = n.getChild(j);
+
+                        if (ch.isLeaf()) {
+                            if (cladeTips.contains(idGroup.whichIdNumber(ch.getIdentifier().getName()))) {
+                                split.add(l);
+                            }
+                        } else {
+                            // internal
+                            final int o = internalNodes.indexOf(ch);
+                            final int i = internalNodesTips.get(o).intersectCardinality(cladeTips);
+                            if (i == internalNodesTips.get(o).cardinality()) {
+                                split.add(l);
+                            } else if (i > 0) {
+                                // Non compatible
+                                found = false;
+                                break;
+                            }
+                        }
+                        ++l;
+                    }
+
+
+                    if (!(found && split.size() < n.getChildCount())) {
+                        found = false;
+                        break;
+                    }
+
+                    if (split.isEmpty()) {
+                        System.err.println("Bug??");
+                        assert (false);
+                    }
+
+                    final Node detached = detachChildren(cons, n, split);
+
+                    final double height = s.sumBranches / s.nTreesWithClade;
+                    detached.setNodeHeight(height);
+                    detached.setBranchLength(branchDistances.build(s.branchLengths));
+
+                    cons.setAttribute(detached, TreeUtils.TREE_CLADE_SUPPORT_ATTRIBUTE, SUPPORT_AS_PERCENT ? 100 * psupport : psupport);
+
+                    // insert just after parent, so before any descendants
+                    internalNodes.add(nsub + 1, detached);
+                    internalNodesTips.add(nsub + 1, new FixedBitSet(cladeTips));
+
+                    break;
+                }
+            }
+        }
+
+        TreeUtils.insureConsistency(cons, cons.getRoot());
+
+        String thresholdAsPercent = String.valueOf(supportThreshold * 100);
+        cons.setAttribute(cons.getRoot(), TreeUtils.TREE_NAME_ATTRIBUTE,
+                "cons_" + thresholdAsPercent + "_majRule");
+
+        Set<FixedBitSet> keySet = getSupport().keySet();
+        FixedBitSet[] keys = keySet.toArray(new FixedBitSet[0]);
+        Arrays.sort(keys);
+
+        for (FixedBitSet fbs : keys) {
+            if (fbs.cardinality() > 1) {
+                double psupport = (1.0 * getSupport().get(fbs).getTreesWeightWithClade()) / cumWeight;
+                if (psupport < effectiveThreshold) {
+                    splitsOutFromConsensus.add(fbs);
+                } else {
+                    splitsInConsensus.add(fbs);
+                }
+            }
+        }
+
+        return cons;
+
+    }
+
+    /**
+     * Enum to calculate the branch lengths
+     */
+    private enum BranchDistances {
+
+        WeightedAverage {
+
+            /**
+             * Calculates the weighted average.
+             * 
+             * @param values the weighted values
+             * @param cumWeight the sum of weights
+             * 
+             * @return the weighted average of the set
+             */
+            @Override
+            public double build(List<WeightLengthPair> values) {
+                double avg = 0.0;
+                double cumWeight = 0.0;
+                for (WeightLengthPair pair : values) {
+                    avg += pair.branchLength * pair.weight;
+                    cumWeight += pair.weight;
+                }
+                avg /= cumWeight;
+                return avg;
+            }
+        },
+        WeightedMedian {
+
+            /**
+             * Calculates the weighted median.
+             * 
+             * @param values the weighted values
+             * @param cumWeight the sum of weights
+             * 
+             * @return the weighted median of the set
+             */
+            @Override
+            public double build(List<WeightLengthPair> values) {
+                Collections.sort(values);
+                double median = -1;
+                double cumWeight = 0.0;
+                for (WeightLengthPair pair : values) {
+                    cumWeight += pair.weight;
+                }
+                double halfWeight = cumWeight / 2.0;
+                double cumValue = 0.0;
+                for (WeightLengthPair pair : values) {
+                    cumValue += pair.weight;
+                    if (cumValue >= halfWeight) {
+                        median = pair.branchLength;
+                        break;
+                    }
+                }
+                return median;
+            }
+        };
+
+        public abstract double build(List<WeightLengthPair> values);
+    }
+
+    /**
+     * One clade support.
+     */
+    static final class Support {
+
+        /** number of trees containing the clade. */
+        private int nTreesWithClade;
+        /** The trees weight with clade. */
+        private double treesWeightWithClade;
+        /** The branch lengths. */
+        private ArrayList<WeightLengthPair> branchLengths;
+        /** Sum of node heights of trees containing the clade. */
+        private double sumBranches;
+
+        public double getTreesWeightWithClade() {
+            return treesWeightWithClade;
+        }
+
+        /**
+         * Instantiates a new support.
+         */
+        Support() {
+            sumBranches = 0.0;
+            treesWeightWithClade = 0.0;
+            nTreesWithClade = 0;
+            branchLengths = new ArrayList<WeightLengthPair>();
+        }
+
+        /**
+         * Adds the branch to the map of branch lengths.
+         * 
+         * @param weight the weight
+         * @param height the height
+         * @param branchLength the branch length
+         */
+        public final void add(double weight, double height, double branchLength) {
+            sumBranches += height;
+            branchLengths.add(new WeightLengthPair(weight, branchLength));
+            treesWeightWithClade += weight;
+            ++nTreesWithClade;
+
+            double testW = 0.0;
+            for (WeightLengthPair wlp : branchLengths) {
+                testW += wlp.weight;
+            }
+        }
+    }
+
+    static class WeightLengthPair implements Comparable<WeightLengthPair> {
+
+        private double weight;
+        private double branchLength;
+
+        WeightLengthPair(double weight, double branchLength) {
+            this.weight = weight;
+            this.branchLength = branchLength;
+        }
+
+        @Override
+        public int compareTo(WeightLengthPair o) {
+            if (branchLength < o.branchLength) {
+                return -1;
+            } else if (branchLength > o.branchLength) {
+                return 1;
+            }
+            return 0;
+        }
+    }
+
+    /**
+     * A extension of Weighted tree but every tree
+     * has the same weight.
+     */
+    static class UnweightedTree extends WeightedTree {
+
+        /**
+         * Instantiates a new unweighted tree.
+         * 
+         * @param tree the tree
+         */
+        UnweightedTree(Tree tree) {
+            super(tree, 1.0);
+        }
+    }
+
+    /**
+     * The main method. This method allows testing of consensus tree
+     * building. It requires at least 2 arguments.
+     * 
+     * @param args Tree set filename (Newick's), threshold, [avg | median]
+     */
+    public static void main(String[] args) {
+
+        PrintWriter out = new PrintWriter(System.out);
+
+        if (args.length < 2 || args[0].contains("help")) {
+            out.println("This class requires at least 2 arguments: Tree set filename, Threshold value" + " and optionally the branch length calculation method [avg (default), median]");
+            out.println("The file format should be:");
+            out.println("    · (Newick's tree)[Weight];");
+            out.println("    · Nexus format tree set");
+            out.flush();
+            System.exit(-1);
+        }
+
+        String filename = args[0];
+        Double threshold = Double.parseDouble(args[1]);
+        File f = new File(filename);
+        try {
+            Consensus consensus;
+            if (args.length >= 3) {
+                if (args[2].equalsIgnoreCase("median")) {
+                    consensus = new Consensus(f, threshold, BRANCH_LENGTHS_MEDIAN);
+                } else if (args[2].equalsIgnoreCase("avg")) {
+                    consensus = new Consensus(f, threshold, BRANCH_LENGTHS_AVERAGE);
+                } else {
+                    consensus = new Consensus(f, threshold);
+                }
+            } else {
+                consensus = new Consensus(f, threshold);
+            }
+            Tree consensusTree = consensus.getConsensusTree();
+            out.println("");
+
+            Set<FixedBitSet> keySet = consensus.getSupport().keySet();
+            FixedBitSet[] keys = keySet.toArray(new FixedBitSet[0]);
+            List<FixedBitSet> splitsInConsensus = new ArrayList<FixedBitSet>();
+            List<FixedBitSet> splitsOutFromConsensus = new ArrayList<FixedBitSet>();
+
+            Arrays.sort(keys);
+
+            for (FixedBitSet fbs : keys) {
+                if (fbs.cardinality() > 1) {
+                    double psupport = (1.0 * consensus.getSupport().get(fbs).getTreesWeightWithClade()) / consensus.cumWeight;
+                    if (psupport < threshold) {
+                        splitsOutFromConsensus.add(fbs);
+                    } else {
+                        splitsInConsensus.add(fbs);
+                    }
+                }
+            }
+
+            out.println("# # # # # # # # # # # # # # # #");
+            out.println(" ");
+            out.println("Species in order:");
+            out.println(" ");
+
+            for (int i = 0; i < consensus.getIdGroup().getIdCount(); i++) {
+                Identifier id = consensus.getIdGroup().getIdentifier(i);
+                out.println("    " + (i + 1) + ". " + id.getName());
+            }
+            out.println(" ");
+            out.println("# # # # # # # # # # # # # # # #");
+            out.println(" ");
+            out.println("Sets included in the consensus tree");
+            out.println(" ");
+            out.print("    ");
+
+            int numTaxa = consensus.getIdGroup().getIdCount();
+            for (int i = 0; i < consensus.getIdGroup().getIdCount(); i++) {
+                out.print(String.valueOf(i + 1).charAt(0));
+            }
+            out.println(" ");
+            if (numTaxa >= 10) {
+                ProtTestFormattedOutput.space(4 + 9, ' ');
+                for (int i = 9; i < consensus.getIdGroup().getIdCount(); i++) {
+                    out.print(String.valueOf(i + 1).charAt(1));
+                }
+            }
+            out.println(" ");
+            for (FixedBitSet fbs : splitsInConsensus) {
+                out.println("    " + fbs.splitRepresentation() + " ( " + Utilities.round(consensus.getSupport().get(fbs).getTreesWeightWithClade(), 3) + " )");
+            }
+            out.println(" ");
+            out.println("Sets NOT included in consensus tree");
+            out.println(" ");
+            out.print("    ");
+            for (int i = 0; i < consensus.getIdGroup().getIdCount(); i++) {
+                out.print(i + 1);
+            }
+            out.println(" ");
+            for (FixedBitSet fbs : splitsOutFromConsensus) {
+                out.println("    " + fbs.splitRepresentation() + " ( " + Utilities.round(consensus.getSupport().get(fbs).getTreesWeightWithClade(), 3) + " )");
+            }
+            out.println(" ");
+            out.println("# # # # # # # # # # # # # # # #");
+
+            TreeUtils.printASCII(consensusTree, out);
+            out.println(" ");
+            TreeUtils.printBranchInfo(consensusTree, out);
+            out.println(" ");
+            TreeUtils.heightInfo(consensusTree, out);
+            out.println(" ");
+            out.println("# # # # # # # # # # # # # # # #");
+            out.println(" ");
+            out.println(TreeUtils.toNewick(consensusTree, true, true, true));
+            out.println(" ");
+            out.println("# # # # # # # # # # # # # # # #");
+            out.println(" ");
+        } catch (FileNotFoundException e) {
+            out.println("File not found: " + filename);
+        } catch (IOException e1) {
+            out.println("IO Error: " + e1.getMessage());
+        }
+        out.flush();
+    }
+
+    public String getTaxaHeader() {
+        StringBuilder taxaHeader = new StringBuilder();
+        for (int i = 0; i < numTaxa; i++) {
+            taxaHeader.append(String.valueOf(i + 1).charAt(0));
+        }
+        if (numTaxa >= 10) {
+            taxaHeader.append('\n');
+            taxaHeader.append(ProtTestFormattedOutput.space(4 + 9, ' '));
+            for (int i = 9; i < numTaxa; i++) {
+                taxaHeader.append(String.valueOf(i + 1).charAt(1));
+            }
+        }
+        if (numTaxa >= 100) {
+            taxaHeader.append('\n');
+            taxaHeader.append(ProtTestFormattedOutput.space(4 + 99, ' '));
+            for (int i = 99; i < numTaxa; i++) {
+                taxaHeader.append(String.valueOf(i + 1).charAt(2));
+            }
+        }
+        if (numTaxa >= 1000) {
+            taxaHeader.append('\n');
+            taxaHeader.append(ProtTestFormattedOutput.space(4 + 999, ' '));
+            for (int i = 999; i < numTaxa; i++) {
+                taxaHeader.append(String.valueOf(i + 1).charAt(3));
+            }
+        }
+
+        return taxaHeader.toString();
+    }
+
+    public String getSetsIncluded() {
+        StringBuilder setsIncluded = new StringBuilder();
+        setsIncluded.append("    ");
+        setsIncluded.append(getTaxaHeader());
+
+        setsIncluded.append('\n');
+        for (FixedBitSet fbs : splitsInConsensus) {
+            setsIncluded.append("    ")
+                    .append(fbs.splitRepresentation())
+                    .append(" ( ")
+                    .append(Utilities.round(getCladeSupport().get(fbs), 5))
+                    .append(" )")
+                    .append('\n');
+        }
+        return setsIncluded.toString();
+    }
+
+    public String getSetsNotIncluded() {
+        StringBuilder setsIncluded = new StringBuilder();
+        setsIncluded.append("    ");
+        setsIncluded.append(getTaxaHeader());
+
+        setsIncluded.append('\n');
+        for (FixedBitSet fbs : splitsOutFromConsensus) {
+            setsIncluded.append("    ")
+                    .append(fbs.splitRepresentation())
+                    .append(" ( ")
+                    .append(Utilities.round(getCladeSupport().get(fbs), 5))
+                    .append(" )")
+                    .append('\n');
+        }
+        return setsIncluded.toString();
+    }
+
+    private BranchDistances getBranchDistances(int value) {
+        BranchDistances bd;
+        switch (value) {
+            case BRANCH_LENGTHS_AVERAGE:
+                bd = BranchDistances.WeightedAverage;
+                break;
+            case BRANCH_LENGTHS_MEDIAN:
+                bd = BranchDistances.WeightedMedian;
+                break;
+            default:
+                // Weighted average
+                bd = DEFAULT_BRANCH_DISTANCES;
+        }
+        return bd;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/consensus/package.html b/src/main/java/es/uvigo/darwin/prottest/consensus/package.html
new file mode 100755
index 0000000..00ab6e5
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/consensus/package.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Provides the classes to build consensus trees.
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/AminoAcidRunEstimator.java b/src/main/java/es/uvigo/darwin/prottest/exe/AminoAcidRunEstimator.java
new file mode 100755
index 0000000..18621e1
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/AminoAcidRunEstimator.java
@@ -0,0 +1,66 @@
+/*
+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.prottest.exe;
+
+
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+
+/**
+ * A generic optimizer for amino-acid models
+ * 
+ * @author Federico Abascal
+ * @author Diego Darriba
+ * @since 3.0
+ */
+public abstract class AminoAcidRunEstimator extends RunEstimatorImpl {
+	
+	/**
+	 * Instantiates a new generic optimizer for amino-acid models.
+	 * 
+	 * @param options the application options instance
+	 * @param model the amino-acid model to optimize
+	 */
+	public AminoAcidRunEstimator(ApplicationOptions options, Model model) {
+		super(options, model);
+	}
+        
+        /**
+	 * Instantiates a new generic optimizer for amino-acid models.
+	 * 
+	 * @param options the application options instance
+	 * @param model the amino-acid model to optimize
+         * @param numberOfThreads the number of threads to use in the optimization
+	 */
+	public AminoAcidRunEstimator(ApplicationOptions options, Model model, int numberOfThreads) {
+		super(options, model, numberOfThreads);
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.exe.RunEstimator#report()
+	 */
+	public void printReport () {
+		model.printReport();
+		if (time != null)
+			ProtTestLogger.getDefaultLogger().info("     (" + time + ")\n");
+                ProtTestLogger.getDefaultLogger().info("\n");
+                ProtTestLogger.getDefaultLogger().flush();
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/ExternalExecutionManager.java b/src/main/java/es/uvigo/darwin/prottest/exe/ExternalExecutionManager.java
new file mode 100755
index 0000000..8f40fb2
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/ExternalExecutionManager.java
@@ -0,0 +1,108 @@
+/*
+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.prottest.exe;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * A thrid-party applications manager to control proccesses running on
+ * the machine and kill them when necessary.
+ * 
+ * @author Diego Darriba
+ * @since 3.0
+ */
+public class ExternalExecutionManager {
+
+    /** Unique instance of the manager */
+    private static ExternalExecutionManager instance;
+    /** Collection of running processes */
+    private final Collection<Process> processes;
+
+    /**
+     * Instantiates a new execution manager
+     */
+    private ExternalExecutionManager() {
+        this.processes = new ArrayList<Process>();
+    }
+
+    /**
+     * Gets the unique instance of the class
+     * 
+     * @return the ExternalExecutionManager instance
+     */
+    public static ExternalExecutionManager getInstance() {
+        if (instance == null) {
+            instance = new ExternalExecutionManager();
+        }
+        return instance;
+    }
+
+    /**
+     * Adds a process in execution to the collection
+     * 
+     * @param proc the running process
+     * 
+     * @return true, if succesfully added the process
+     */
+    public boolean addProcess(Process proc) {
+        boolean result = false;
+        if (!processes.contains(proc)) {
+            result = processes.add(proc);
+        }
+        return result;
+    }
+
+    /**
+     * Removes a process from the collection
+     * 
+     * @param proc the process to remove
+     * 
+     * @return true, if succesfully removed the process
+     */
+    public boolean removeProcess(Process proc) {
+        boolean result = false;
+        if (processes.contains(proc)) {
+            result = processes.remove(proc);
+        }
+        return result;
+    }
+
+    /**
+     * Kills all running processes in the collection
+     */
+    public void killProcesses() {
+        for (final Process proc : processes) {
+            if (proc != null) {
+                try {
+                    proc.exitValue();
+                } catch (IllegalThreadStateException e) {
+                    // The process is executing, so we should kill it
+                    Runtime.getRuntime().addShutdownHook(
+                            new Thread(new Runnable() {
+
+                        public void run() {
+                            proc.destroy();
+                        }
+                    }));
+                }
+            }
+        }
+        processes.clear();
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/ExternalExecutor.java b/src/main/java/es/uvigo/darwin/prottest/exe/ExternalExecutor.java
new file mode 100755
index 0000000..6629754
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/ExternalExecutor.java
@@ -0,0 +1,97 @@
+/*
+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
+*/
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package es.uvigo.darwin.prottest.exe;
+
+import es.uvigo.darwin.prottest.exe.util.TemporaryFileManager;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException.ExternalExecutionException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+
+/**
+ *
+ * @author diego
+ */
+public class ExternalExecutor {
+
+    private static final int STATE_NULL = 0;
+    private static final int STATE_INITIALIZED = 1;
+    private static final int STATE_EXECUTED = 2;
+    
+    private static final int OUTPUT_STANDARD = 1;
+    private static final int OUTPUT_TEMPORARY = 2;
+    
+    private String command;
+    private Process proc = null;
+    private OutputStream logOutput;
+    
+    private int internal_state = STATE_NULL;
+    
+    public ExternalExecutor(String command, int outLogFormat) 
+            throws ExternalExecutionException {
+        try {
+            this.command = command;
+
+            switch (outLogFormat) {
+                case OUTPUT_STANDARD:
+                    logOutput = System.out;
+                    break;
+                case OUTPUT_TEMPORARY:
+                    logOutput = new FileOutputStream(TemporaryFileManager.getInstance().
+                            getLogFilename(Thread.currentThread()));
+            }
+            this.internal_state = STATE_INITIALIZED;
+        } catch (FileNotFoundException ex) {
+            throw new ExternalExecutionException("I/O error: " + ex.getMessage());
+        }
+    }
+    
+    public void run() throws ExternalExecutionException {
+
+        if (!checkState(STATE_INITIALIZED) || checkState(STATE_EXECUTED)) {
+            throw new ProtTestInternalException("Invalid executor internal state");
+        }
+        
+        try {
+            Runtime runtime = Runtime.getRuntime();
+            proc = runtime.exec(command);
+
+            ExternalExecutionManager.getInstance().addProcess(proc);
+        } catch (IOException ex) {
+            throw new ProtTestInternalException(ex.getMessage());
+        }
+        
+        try {    
+            int exitVal = proc.waitFor();
+        } catch (InterruptedException ex) {
+            throw new ExternalExecutionException("Interrupted execution: " + ex.getMessage());
+        }
+    }
+    
+    private boolean checkState(int state) {
+        return internal_state >= state;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/ParallelModelEstimator.java b/src/main/java/es/uvigo/darwin/prottest/exe/ParallelModelEstimator.java
new file mode 100755
index 0000000..7a3b130
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/ParallelModelEstimator.java
@@ -0,0 +1,154 @@
+/*
+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
+*/
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package es.uvigo.darwin.prottest.exe;
+
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ModelUpdaterObserver;
+import es.uvigo.darwin.prottest.observer.ObservableModelUpdater;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import pal.alignment.Alignment;
+
+/**
+ * Allows the execution of many model optimizations in a thread pool
+ * 
+ * @author Diego Darriba
+ * @since 3.0
+ */
+public class ParallelModelEstimator extends ObservableModelUpdater
+        implements ModelUpdaterObserver {
+
+    /** The runtime **/
+    private Runtime runtime = Runtime.getRuntime();
+    /** The size of parallel tasks **/
+    private int maxNumberOfTasks;
+    /** The list of model estimators **/
+    private List<RunEstimator> 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 ParallelModelEstimator 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 ParallelModelEstimator(Alignment alignment) {
+
+        this(-1, alignment);
+
+    }
+
+    /**
+     * Instantiates a new ParallelModelEstimator with a set of models to optimize
+     * The size of the thread pool is equal to the number of available cores in the machine.
+     * 
+     * @param modelCollection the collection of models to optimize in the pool
+     */
+    public ParallelModelEstimator(ModelCollection modelCollection) {
+
+        this(-1, modelCollection);
+
+    }
+
+    /**
+     * Instantiates a new ParallelModelEstimator 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 ParallelModelEstimator(int availableThreads, Alignment alignment) {
+
+        if (availableThreads < 0) {
+            availableThreads = runtime.availableProcessors();
+        }
+        this.maxNumberOfTasks = availableThreads;
+        this.estimatorList = new ArrayList<RunEstimator>(maxNumberOfTasks);
+        this.threadPool = Executors.newFixedThreadPool(maxNumberOfTasks);
+    }
+
+    /**
+     * Instantiates a new ParallelModelEstimator with a set of models to optimize and
+     * a fixed size of the thread pool
+     *
+     * @param availableThreads the size of the thread pool
+     * @param modelCollection the collection of models to optimize in the pool
+     */
+    public ParallelModelEstimator(int availableThreads, ModelCollection modelCollection) {
+
+        if (availableThreads < 0) {
+            availableThreads = runtime.availableProcessors();
+        }
+        this.estimatorList = new ArrayList<RunEstimator>(maxNumberOfTasks);
+
+    }
+
+    /**
+     * Executes the model optimization
+     * 
+     * @param estimator the model estimator to execute
+     * 
+     * @return if succesfully added the task
+     */
+    public boolean execute(RunEstimator estimator) {
+        estimator.addObserver(this);
+
+        boolean added = estimatorList.add(estimator);
+        c.add(Executors.callable(estimator));
+        Collection<Future<Object>> futures = null;
+
+        threadPool.execute(estimator);
+
+        return added;
+    }
+
+    /* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.observer.ModelUpdaterObserver#update(es.uvigo.darwin.prottest.observer.ObservableModelUpdater, es.uvigo.darwin.prottest.model.Model, es.uvigo.darwin.prottest, es.uvigo.darwin.prottest.global.options.ApplicationOptions)
+	 */
+    public void update(ObservableModelUpdater o, Model model, ApplicationOptions options) {
+        notifyObservers(model, options);
+    }
+
+    /**
+     * Checks if exist more tasks in the task queue
+     * 
+     * @return true, if exist more tasks to execute
+     */
+    public boolean hasMoreTasks() {
+        for (RunEstimator estimator : estimatorList) {
+            if (!estimator.getModel().isComputed()) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/PhyMLv3AminoAcidRunEstimator.java b/src/main/java/es/uvigo/darwin/prottest/exe/PhyMLv3AminoAcidRunEstimator.java
new file mode 100755
index 0000000..7967ace
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/PhyMLv3AminoAcidRunEstimator.java
@@ -0,0 +1,464 @@
+/*
+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.prottest.exe;
+
+import static es.uvigo.darwin.prottest.global.ApplicationGlobals.APPLICATION_PROPERTIES;
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.OPTIMIZE_BIONJ;
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.OPTIMIZE_FIXED_BIONJ;
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.OPTIMIZE_ML;
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.OPTIMIZE_USER;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+
+import pal.tree.ReadTree;
+import pal.tree.TreeParseException;
+import es.uvigo.darwin.prottest.exe.util.TemporaryFileManager;
+import es.uvigo.darwin.prottest.global.ApplicationGlobals;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.AminoAcidModel;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.Utilities;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException.ModelNotFoundException;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException.OSNotSupportedException;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException.PhyMLExecutionException;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException.StatsFileFormatException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.exception.TreeFormatException;
+
+/**
+ * The Class PhyMLAminoAcidRunEstimator. It optimizes Amino-Acid
+ * model parameters using PhyML 3.0.
+ * 
+ * @author Federico Abascal
+ * @author Diego Darriba
+ * @since 3.0
+ */
+public class PhyMLv3AminoAcidRunEstimator extends AminoAcidRunEstimator {
+
+    /** The PhyML implemented matrices. */
+    public static String[] IMPLEMENTED_MATRICES = {
+        "JTT",
+        "LG",
+        "DCMut",
+        "MtREV",
+        "MtMam",
+        "MtArt",
+        "Dayhoff",
+        "WAG",
+        "RtREV",
+        "CpREV",
+        "Blosum62",
+        "VT",
+        "HIVb",
+        "HIVw"
+    };
+    /** Suffix for temporary statistic files. */
+    private static final String STATS_FILE_SUFFIX = "_phyml_stats.txt";
+    /** Suffix for temporary tree files. */
+    private static final String TREE_FILE_SUFFIX = "_phyml_tree.txt";
+    /** Alignment filename. */
+    private String workAlignment;
+    /** Custom model substitution matrix file**/
+    private File modelFile;
+
+    /**
+     * Instantiates a new optimizer for amino-acid models
+     * using PhyML.
+     * 
+     * @param options the application options instance
+     * @param model the amino-acid model to optimize
+     */
+    public PhyMLv3AminoAcidRunEstimator(ApplicationOptions options, Model model) {
+        this(options, model, 1);
+    }
+
+    /**
+     * Instantiates a new optimizer for amino-acid models
+     * using PhyML.
+     * 
+     * @param options the application options instance
+     * @param model the amino-acid model to optimize
+     * @param numberOfThreads the number of threads to use in the optimization
+     */
+    public PhyMLv3AminoAcidRunEstimator(ApplicationOptions options, Model model, int numberOfThreads) {
+        super(options, model, numberOfThreads);
+        this.numberOfCategories = options.ncat;
+
+        try {
+            this.model = (AminoAcidModel) model;
+            // check if there is any matrix file
+            modelFile = new File(ApplicationGlobals.PATH + File.separator + "models" + File.separator + model.getMatrix());
+
+        } catch (ClassCastException cce) {
+            throw new ProtTestInternalException("Wrong model type");
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.exe.RunEstimator#optimizeModel(es.uvigo.darwin.prottest.global.options.ApplicationOptions)
+     */
+    @Override
+    public boolean runEstimator()
+            throws ModelOptimizationException {
+        //let's call Phyml with the proper command line
+
+        this.workAlignment = TemporaryFileManager.getInstance().getAlignmentFilename(Thread.currentThread());
+
+        String inv = "0.0";
+        if (model.isInv()) {
+            inv = "e";
+        }
+
+        String rateCathegories = "1";
+
+        String alpha = "";
+        if (model.isGamma()) {
+            rateCathegories = "" + model.getNumberOfTransitionCategories();//options.ncat;
+            alpha = "e";
+        }
+        String tr = "BIONJ";
+
+        String F = "d";
+        if (model.isPlusF()) {
+            F = "e";
+        }
+        String topo = "lr";
+        switch (options.strategyMode) {
+            case OPTIMIZE_BIONJ:
+                tr = "BIONJ";
+                topo = "lr";
+                break;
+            case OPTIMIZE_FIXED_BIONJ:
+                if (TemporaryFileManager.getInstance().getTreeFilename(Thread.currentThread()) != null) {
+                    tr = TemporaryFileManager.getInstance().getTreeFilename(Thread.currentThread());
+                    topo = "lr";
+                } else {
+                    topo = "r";
+                }
+                break;
+            case OPTIMIZE_ML:
+                topo = "tlr";
+                break;
+            case OPTIMIZE_USER:
+                tr = TemporaryFileManager.getInstance().getTreeFilename(Thread.currentThread());
+                topo = "lr";
+        }
+        try {
+            Runtime runtime = Runtime.getRuntime();
+
+            String str[] = new String[31];
+            for (int i = 0; i < str.length; i++) {
+                str[i] = "";
+            }
+
+            boolean phymlGlobal = APPLICATION_PROPERTIES.getProperty("global-phyml-exe", "false").equalsIgnoreCase("true");
+            		
+            File exeFilesDir = new File(APPLICATION_PROPERTIES.getProperty("exe-dir", ApplicationGlobals.PATH));
+            if (!exeFilesDir.isAbsolute()) {
+            	exeFilesDir = new File(ApplicationGlobals.PATH + File.separator + APPLICATION_PROPERTIES.getProperty("exe-dir", "bin"));	
+            }
+            		
+            File phymlBin;
+            
+           	phymlBin = new File(exeFilesDir.getAbsolutePath() + File.separator + "phyml");
+           	
+            String phymlBinName;
+            if (phymlGlobal) {
+            	phymlBinName = "phyml";
+            } else {
+	            if (phymlBin.exists() && phymlBin.canExecute()) {
+	                phymlBinName = phymlBin.getAbsolutePath();
+	            } else {
+	                phymlBinName = exeFilesDir.getAbsolutePath() + File.separator + getPhymlVersion();
+	            }
+            }
+
+            if (phymlBinName != null) {
+
+                //     phyml -i seq_file_name -d aa ¿-q? -f d/e (d para -F y e para +F) -v 0/e (para -I o +I) -a e (para estimar alpha)
+                //         -c 0/4/8 (num rate categories) -u user_tree_file (opcional)
+                //         -o tlr/lr (dependiendo de si optimizamos la topología o no)
+                //         -m WAG (default) | JTT | MtREV | Dayhoff | DCMut | RtREV | CpREV | VT | Blosum62 | MtMam | MtArt | HIVw |  HIVb | custom
+
+                str[0] = phymlBinName;
+
+                // input alignment
+                str[4] = "-i";
+                str[5] = workAlignment;
+
+                // number of rate categories
+                str[6] = "-c";
+                str[7] = rateCathegories;
+
+                // the model
+                str[8] = "-m";
+                if (!Arrays.asList(IMPLEMENTED_MATRICES).contains(model.getMatrix())) {
+                    // check matrix file
+                    if (!modelFile.exists()) {
+                        throw new ModelNotFoundException(model.getMatrix());
+                    }
+                    str[9] = "custom";
+                    str[27] = "--aa_rate_file";
+                    str[28] = modelFile.getAbsolutePath();
+                } else {
+                    str[9] = model.getMatrix();
+                }
+
+                // proportion of invariable sites
+                str[10] = "-v";
+                str[11] = inv;
+
+                // value of the gamma shape parameter (if gamma distribution)
+                if (!alpha.equals("")) {
+                    str[12] = "-a";
+                    str[13] = alpha;
+                }
+
+                // topology optimization
+                str[14] = "-o";
+                str[15] = topo;
+
+                // amino-acid frequencies
+                str[16] = "-f";
+                str[17] = F;
+
+                // starting tree file
+                if (!tr.equals("BIONJ")) {
+                    str[18] = "-u";
+                    str[19] = tr;
+                }
+
+                // data type
+                str[20] = "-d";
+                str[21] = "aa";
+
+                // bootstrapping
+                str[22] = "-b";
+                str[23] = "0";
+
+                if (APPLICATION_PROPERTIES.getProperty("phyml_thread_scheduling", "false").equalsIgnoreCase("true")) {
+                    str[24] = "--num_threads";
+                    str[25] = String.valueOf(numberOfThreads);
+                }
+                if (APPLICATION_PROPERTIES.getProperty("no-memory-check", "no").equalsIgnoreCase("yes")) {
+                    str[26] = "--no_memory_check";
+                }
+                
+                if (options.strategyMode == OPTIMIZE_ML) {
+                	str[29] = "-s";
+                	str[30] = options.getTreeSearchOperation();
+                } else {
+                	str[29] = str[30] = "";
+                }
+                model.setCommandLine(str);
+                proc = runtime.exec(str);
+                proc.getOutputStream().write(modelFile.getPath().getBytes());
+                ExternalExecutionManager.getInstance().addProcess(proc);
+
+            } else {
+                OSNotSupportedException e =
+                        new OSNotSupportedException("PhyML");
+                throw e;
+            }
+            proc.getOutputStream().close();
+
+            StreamGobbler errorGobbler = new PhymlStreamGobbler(new InputStreamReader(proc.getErrorStream()), "Phyml-Error", true, RunEstimator.class);
+            StreamGobbler outputGobbler = new PhymlStreamGobbler(new InputStreamReader(proc.getInputStream()), "Phyml-Output", true, RunEstimator.class);
+            errorGobbler.start();
+            outputGobbler.start();
+            int exitVal = proc.waitFor();
+            ExternalExecutionManager.getInstance().removeProcess(proc);
+
+            pfine("Phyml's command-line: ");
+            for (int i = 0; i < str.length; i++) {
+                pfine(str[i] + " ");
+            }
+            pfineln("");
+
+            if (exitVal != 0) {
+                errorln("Phyml's exit value: " + exitVal + " (there was probably some error)");
+                error("Phyml's command-line: ");
+                for (int i = 0; i < str.length; i++) {
+                    error(str[i] + " ");
+                }
+                errorln("");
+
+                errorln("Please, take a look at the Phyml's log below:");
+                String line;
+                try {
+                    FileReader input = new FileReader(TemporaryFileManager.getInstance().getLogFilename(Thread.currentThread()));
+                    BufferedReader br = new BufferedReader(input);
+                    while ((line = br.readLine()) != null) {
+                        errorln(line);
+                    }
+                } catch (IOException e) {
+                    errorln("Unable to read the log file: " + TemporaryFileManager.getInstance().getLogFilename(Thread.currentThread()));
+                }
+            }
+        } catch (InterruptedException e) {
+            throw new PhyMLExecutionException("Interrupted execution: " + e.getMessage());
+        } catch (IOException e) {
+            throw new PhyMLExecutionException("I/O error: " + e.getMessage());
+        }
+
+
+        if (!(readStatsFile() && readTreeFile())) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Read the temporary statistics file.
+     * 
+     * @return true, if successful
+     */
+    private boolean readStatsFile()
+            throws ModelOptimizationException {
+
+        String line;
+
+        try {
+            FileReader input = new FileReader(workAlignment + STATS_FILE_SUFFIX);
+            BufferedReader br = new BufferedReader(input);
+            while ((line = br.readLine()) != null) {
+                pfinerln("[DEBUG] PHYML: " + line);
+
+                if (line.length() > 0) {
+                    if (line.startsWith(". Model of amino acids substitution")) {
+                        String matrixName = Utilities.lastToken(line);
+                        
+                        //TODO: This line exists due to a bug in the phyml latest versions
+                        //      where the HIVw matrix is shown as HIVb in the stats file
+                        if (!model.getMatrix().equals("HIVw"))
+                        if (!(model.getMatrix().equals(matrixName) || (modelFile.exists() &&
+                                !Arrays.asList(IMPLEMENTED_MATRICES).contains(model.getMatrix())))) {
+                            String errorMsg = "Matrix names doesn't match";
+                            errorln("PHYML: " + line);
+                            errorln("Last token: " + Utilities.lastToken(line));
+                            errorln("It should be: " + model.getMatrix());
+                            errorln(errorMsg);
+                            throw new ModelNotFoundException(model.getMatrix());
+                        }
+                    } else if (line.startsWith(". Log-likelihood")) {
+                        model.setLk(Double.parseDouble(Utilities.lastToken(line)));
+                    } else if (line.startsWith(". Discrete gamma model")) {
+                        if (Utilities.lastToken(line).equals("Yes")) {
+                            line = br.readLine();
+
+                            pfinerln("[DEBUG] PHYML: " + line);
+
+                            if (model.getNumberOfTransitionCategories() != Integer.parseInt(Utilities.lastToken(line))) {
+                                String errorMsg = "There were errors in the number of transition categories: " + model.getNumberOfTransitionCategories() + " vs " + Integer.parseInt(Utilities.lastToken(line));
+                                errorln(errorMsg);
+
+                                throw new StatsFileFormatException("PhyML", errorMsg);
+                            //prottest.setCurrentModel(-2);
+                            }
+                            line = br.readLine();
+
+                            pfinerln("[DEBUG] PHYML: " + line);
+
+                            model.setAlpha(Double.parseDouble(Utilities.lastToken(line)));
+                        }
+                    } else if (line.startsWith(". Proportion of invariant:")) {
+                        model.setInv(Double.parseDouble(Utilities.lastToken(line)));
+                    } else if (line.startsWith(". Time used")) {
+                        time = Utilities.lastToken(line);
+                    }
+                }
+            }
+        } catch (IOException e) {
+            throw new StatsFileFormatException("PhyML", e.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * Read the temporary tree file.
+     * 
+     * @return true, if successful
+     * 
+     * @throws TreeFormatException the tree format exception
+     */
+    private boolean readTreeFile()
+            throws TreeFormatException {
+
+        try {
+            model.setTree(new ReadTree(workAlignment + TREE_FILE_SUFFIX));
+        } catch (TreeParseException e) {
+            String errorMsg = "ProtTest: wrong tree format, exiting...";
+            throw new TreeFormatException(errorMsg);
+        } catch (IOException e) {
+            String errorMsg = "Error: File not found (IO error), exiting...";
+            throw new TreeFormatException(errorMsg);
+        }
+        return true;
+    }
+
+    /**
+     * Delete temporary files.
+     * 
+     * @return true, if successful
+     */
+    @Override
+    protected boolean deleteTemporaryFiles() {
+        File f;
+        f = new File(workAlignment + STATS_FILE_SUFFIX);
+        f.delete();
+        f = new File(workAlignment + TREE_FILE_SUFFIX);
+        f.delete();
+        f = new File(TemporaryFileManager.getInstance().getLogFilename(Thread.currentThread()));
+        f.delete();
+        return true;
+    }
+
+    /**
+     * Gets the PhyML executable name for the current Operating System.
+     * 
+     * @return the PhyML executable name
+     */
+    private String getPhymlVersion() {
+        String os = System.getProperty("os.name");
+        String oa = System.getProperty("os.arch");
+        if (os.startsWith("Mac")) {
+            if (oa.startsWith("ppc")) {
+                return "phyml-prottest-macppc";
+            } else {
+                return "phyml-prottest-macintel";
+            }
+        } else if (os.startsWith("Linux")) {
+        	if (oa.contains("md64")) {
+        		return "phyml-prottest-linux64";
+        	} else {
+        		return "phyml-prottest-linux";
+        	}
+        } else if (os.startsWith("Window")) {
+            return "phyml-prottest-windows.exe";
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/PhymlStreamGobbler.java b/src/main/java/es/uvigo/darwin/prottest/exe/PhymlStreamGobbler.java
new file mode 100755
index 0000000..c2b8f5d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/PhymlStreamGobbler.java
@@ -0,0 +1,65 @@
+/*
+Copyright (C) 2004  Federico Abascal
+
+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.prottest.exe;
+
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * Allows the asynchronous logging of an input stream.
+ *
+ * @author Federico Abascal
+ */
+public class PhymlStreamGobbler extends StreamGobbler {
+
+    /**
+     * Instantiates a new StreamGobbler
+     *
+     * @param isr the input stream reader to evaluate
+     * @param type the prefix of the output lines
+     * @param printIt true, if the errors should be logged
+     * @param caller the caller
+     */
+    public PhymlStreamGobbler(InputStreamReader isr, String type, boolean printIt, Class caller) {
+        super(isr,type,printIt,caller);
+    }
+
+        @Override
+    /* (non-Javadoc)
+     * @see java.lang.Thread#run()
+     */
+    public void run() {
+        try {
+            //InputStreamReader isr = new InputStreamReader(is);
+            BufferedReader br = new BufferedReader(isr);
+            String line = null;
+            while ((line = br.readLine()) != null) {
+            	ProtTestLogger.lowLevelLog(line);
+               if (printIt && line.startsWith(". Err")) {
+                    ProtTestLogger.severeln(type + ">" + line, caller);
+               } else {
+                    ProtTestLogger.finestln(type + ">" + line, caller);
+               }
+            }
+        } catch (IOException ioe) {
+
+        }
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/RaxMLAminoAcidRunEstimator.java b/src/main/java/es/uvigo/darwin/prottest/exe/RaxMLAminoAcidRunEstimator.java
new file mode 100755
index 0000000..bc6f6cb
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/RaxMLAminoAcidRunEstimator.java
@@ -0,0 +1,341 @@
+/*
+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.prottest.exe;
+
+import static es.uvigo.darwin.prottest.global.RaxmlAminoAcidApplicationGlobals.*;
+import es.uvigo.darwin.prottest.exe.util.TemporaryFileManager;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.AminoAcidModel;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.Utilities;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException.ModelNotFoundException;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException.OSNotSupportedException;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException.PhyMLExecutionException;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException.StatsFileFormatException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.exception.TreeFormatException;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import pal.tree.ReadTree;
+import pal.tree.TreeParseException;
+
+
+/**
+ * The Class RAxMLAminoAcidRunEstimator. It optimizes Amino-Acid
+ * model parameters using RAxML.
+ *
+ * This implementation fits with RAxML 7.0.4.
+ */
+public class RaxMLAminoAcidRunEstimator extends AminoAcidRunEstimator {
+
+    public static final String PARSIMONY_TREE_PREFIX = "RAxML_parsimonyTree.";
+    public static final String FINAL_TREE_PREFIX = "RAxML_result.";
+    public static final String STATS_PREFIX = "RAxML_info.";
+    public static final String LOG_PREFIX = "RAxML_log.";
+
+    /** Alignment filename. */
+    private String workAlignment;
+    /** Custom model substitution matrix file**/
+    private File modelFile;
+
+    private String outputAppend;
+
+    /**
+     * Instantiates a new optimizer for amino-acid models
+     * using RaxML.
+     *
+     * @param options the application options instance
+     * @param model the amino-acid model to optimize
+     */
+    public RaxMLAminoAcidRunEstimator(ApplicationOptions options, Model model) {
+        this(options, model, 1);
+    }
+
+     /**
+     * Instantiates a new optimizer for amino-acid models
+     * using RaxML.
+     *
+     * @param options the application options instance
+     * @param model the amino-acid model to optimize
+     * @param numberOfThreads the number of threads to use in the optimization
+     */
+    public RaxMLAminoAcidRunEstimator(ApplicationOptions options, Model model, int numberOfThreads) {
+        super(options, model, numberOfThreads);
+
+                this.numberOfCategories = options.ncat;
+
+        try {
+            this.model = (AminoAcidModel) model;
+            // check if there is any matrix file
+            modelFile = new File("models" + File.separator + model.getMatrix());
+
+        } catch (ClassCastException cce) {
+            throw new ProtTestInternalException("Wrong model type");
+        }
+                
+        this.outputAppend = model.getModelName().replace('+', 'P');
+        System.out.println(" MODEL, OUTPUT " + model.getModelName() + " " + outputAppend);
+
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.exe.RunEstimator#optimizeModel(es.uvigo.darwin.prottest.global.options.ApplicationOptions)
+     */
+    @Override
+    public boolean runEstimator() throws ModelOptimizationException {
+
+        //let's call Phyml with the proper command line
+
+        this.workAlignment = TemporaryFileManager.getInstance().getAlignmentFilename(Thread.currentThread());
+
+        
+        switch (options.strategyMode) {
+            case OPTIMIZE_BIONJ:
+                break;
+            case OPTIMIZE_FIXED_BIONJ:
+                if (TemporaryFileManager.getInstance().getTreeFilename(Thread.currentThread()) != null) {
+                } else {
+                }
+                break;
+            case OPTIMIZE_ML:
+                break;
+            case OPTIMIZE_USER:
+        }
+        try {
+            Runtime runtime = Runtime.getRuntime();
+
+            String str[] = new String[26];
+            for (int i = 0; i < str.length; i++) {
+                str[i] = "";
+            }
+
+            String raxmlBinName = "raxmlHPC";
+
+            if (raxmlBinName != null) {
+
+                //     raxml -s seq_file_name -n output -m model d/e (d para -F y e para +F) -v 0/e (para -I o +I) -a e (para estimar alpha)
+                //         -c 0/4/8 (num rate categories) -u user_tree_file (opcional)
+                //         -o tlr/lr (dependiendo de si optimizamos la topología o no)
+                //         -m WAG (default) | JTT | MtREV | Dayhoff | DCMut | RtREV | CpREV | VT | Blosum62 | MtMam | MtArt | HIVw |  HIVb | custom
+
+                str[0] = raxmlBinName;
+
+                // input alignment
+                str[1] = "-s";
+                str[2] = workAlignment;
+                File f = new File(workAlignment);
+
+                str[5] = "-n";
+                str[6] = outputAppend;
+
+                StringBuilder modelName = new StringBuilder("PROT");
+                if (model.isGamma())
+                    modelName.append("GAMMA");
+                else {
+                    modelName.append("MIX");
+                }
+                if (model.isInv())
+                    modelName.append("I");
+
+                modelName.append(model.getMatrix().toUpperCase());
+                
+                if (model.isPlusF())
+                    modelName.append("F");
+
+                // the model
+                str[3] = "-m";
+//                if (!Arrays.asList(RAXML_MATRICES).contains(model.getMatrix())) {
+//                    // check matrix file
+//                    if (!modelFile.exists()) {
+//                        throw new ModelNotFoundException(model.getMatrix());
+//                    }
+//                    str[9] = "custom";
+//                } else {
+                    str[4] =  modelName.toString();
+//                }
+
+//                if (APPLICATION_PROPERTIES.getProperty("phyml_thread_scheduling", "false").equalsIgnoreCase("true")) {
+//                    str[24] = "-t";
+//                    str[25] = String.valueOf(numberOfThreads);
+//                }
+                System.out.print("COMMAND: ");
+                for (String tok : str)
+                    System.out.print(tok + " ");
+                System.out.println(" ");
+                model.setCommandLine(str);
+                proc = runtime.exec(str);
+                proc.getOutputStream().write(modelFile.getPath().getBytes());
+                ExternalExecutionManager.getInstance().addProcess(proc);
+
+            } else {
+                OSNotSupportedException e =
+                        new OSNotSupportedException("PhyML");
+                throw e;
+            }
+            proc.getOutputStream().close();
+
+            StreamGobbler errorGobbler = new RaxMLStreamGobbler(new InputStreamReader(proc.getErrorStream()), "RAxML-Error", true, RunEstimator.class);
+            StreamGobbler outputGobbler = new RaxMLStreamGobbler(new InputStreamReader(proc.getInputStream()), "RAxML-Output", true, RunEstimator.class);
+            errorGobbler.start();
+            outputGobbler.start();
+            int exitVal = proc.waitFor();
+            ExternalExecutionManager.getInstance().removeProcess(proc);
+
+            pfine("RAxML command-line: ");
+            for (int i = 0; i < str.length; i++) {
+                pfine(str[i] + " ");
+            }
+            pfineln("");
+
+            if (exitVal != 0) {
+                errorln("RAxML exit value: " + exitVal + " (there was probably some error)");
+                error("RAxML command-line: ");
+                for (int i = 0; i < str.length; i++) {
+                    error(str[i] + " ");
+                }
+                errorln("");
+
+                errorln("Please, take a look at the RAxML log below:");
+                String line;
+                try {
+                    FileReader input = new FileReader(TemporaryFileManager.getInstance().getLogFilename(Thread.currentThread()));
+                    BufferedReader br = new BufferedReader(input);
+                    while ((line = br.readLine()) != null) {
+                        errorln(line);
+                    }
+                } catch (IOException e) {
+                    errorln("Unable to read the log file: " + TemporaryFileManager.getInstance().getLogFilename(Thread.currentThread()));
+                }
+            }
+        } catch (InterruptedException e) {
+            throw new PhyMLExecutionException("Interrupted execution: " + e.getMessage());
+        } catch (IOException e) {
+            throw new PhyMLExecutionException("I/O error: " + e.getMessage());
+        }
+
+
+        if (!(readStatsFile() && readTreeFile())) {
+            return false;
+        }
+
+        return true;
+
+    }
+
+    /**
+     * Delete temporary files.
+     *
+     * @return true, if successful
+     */
+    @Override
+    protected boolean deleteTemporaryFiles() {
+        return true;
+        //throw new UnsupportedOperationException("RAxML is not supported yet. Sorry.");
+    }
+
+    /**
+     * Read the temporary statistics file.
+     *
+     * @return true, if successful
+     */
+    private boolean readStatsFile()
+            throws ModelOptimizationException {
+
+        //Output files:
+        //
+        // Extension given by the -n argument
+        //
+        // RAxML_parsimonyTree.*    Parsimony input tree
+        // RAxML_result.*       Final tree
+        // RAxML_info.*         Results
+        // RAxML_log.*          Log
+        String line;
+
+        String alpha, inv, logLK;
+        alpha = inv = logLK = null;
+        try {
+            FileReader input = new FileReader(STATS_PREFIX + outputAppend);
+            BufferedReader br = new BufferedReader(input);
+            while ((line = br.readLine()) != null) {
+                pfinerln("[DEBUG] RAXML: " + line);
+
+                if (line.length() > 0) {
+                    if (line.startsWith("Substitution Matrix:")) {
+                        String matrixName = Utilities.lastToken(line);
+                        if (!model.getMatrix().equalsIgnoreCase(matrixName)) {
+                            String errorMsg = "Matrix names doesn't match";
+                            errorln("RAXML: " + line);
+                            errorln("Last token: " + Utilities.lastToken(line));
+                            errorln("It should be: " + model.getMatrix());
+                            errorln(errorMsg);
+                            throw new ModelNotFoundException(model.getMatrix());
+                        }
+                    } else if (line.startsWith("Likelihood   :")) {
+                        logLK = Utilities.lastToken(line);
+                    } else if (line.startsWith("Inference[0]")) {
+                        alpha = Utilities.nextToken(line, "alpha[0]:");
+                        inv = Utilities.nextToken(line, "invar[0]:");
+
+                        pfinerln("[DEBUG] RAXML: " + line);
+
+                    } else if (line.startsWith("Overall Time")) {
+                        time = Utilities.lastToken(line);
+                    }
+                }
+            }
+
+            model.setLk(Double.parseDouble(logLK));
+            if (alpha != null) {
+                model.setAlpha(Double.parseDouble(alpha));
+            }
+            if (inv != null) {
+                model.setInv(Double.parseDouble(inv));
+            }
+            
+        } catch (IOException e) {
+            throw new StatsFileFormatException("RAxML", e.getMessage());
+        }
+        return true;
+    }
+
+    /**
+     * Read the temporary tree file.
+     *
+     * @return true, if successful
+     *
+     * @throws TreeFormatException the tree format exception
+     */
+    private boolean readTreeFile()
+            throws TreeFormatException {
+
+        try {
+            model.setTree(new ReadTree(FINAL_TREE_PREFIX + outputAppend));
+        } catch (TreeParseException e) {
+            String errorMsg = "ProtTest: wrong tree format, exiting...";
+            throw new TreeFormatException(errorMsg);
+        } catch (IOException e) {
+            String errorMsg = "Error: File not found (IO error), exiting...";
+            throw new TreeFormatException(errorMsg);
+        }
+        return true;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/RaxMLStreamGobbler.java b/src/main/java/es/uvigo/darwin/prottest/exe/RaxMLStreamGobbler.java
new file mode 100755
index 0000000..3ac7793
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/RaxMLStreamGobbler.java
@@ -0,0 +1,60 @@
+/*
+Copyright (C) 2004  Federico Abascal
+
+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.prottest.exe;
+
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * Allows the asynchronous logging of an input stream.
+ *
+ * @author Federico Abascal
+ */
+public class RaxMLStreamGobbler extends StreamGobbler {
+
+    /**
+     * Instantiates a new StreamGobbler
+     *
+     * @param isr the input stream reader to evaluate
+     * @param type the prefix of the output lines
+     * @param printIt true, if the errors should be logged
+     * @param caller the caller
+     */
+    public RaxMLStreamGobbler(InputStreamReader isr, String type, boolean printIt, Class caller) {
+        super(isr,type,printIt,caller);
+    }
+
+        @Override
+    /* (non-Javadoc)
+     * @see java.lang.Thread#run()
+     */
+    public void run() {
+        try {
+            //InputStreamReader isr = new InputStreamReader(is);
+            BufferedReader br = new BufferedReader(isr);
+            String line = null;
+            while ((line = br.readLine()) != null) {
+                ProtTestLogger.finestln(type + ">" + line, caller);
+            }
+        } catch (IOException ioe) {
+
+        }
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/RunEstimator.java b/src/main/java/es/uvigo/darwin/prottest/exe/RunEstimator.java
new file mode 100755
index 0000000..5a26786
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/RunEstimator.java
@@ -0,0 +1,60 @@
+/*
+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.prottest.exe;
+
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ModelUpdaterObserver;
+
+/**
+ * The Interface RunEstimator. Should be implemented by any class which launches
+ * an external likelihood calculator or directly calculates likelihood for any 
+ * kind of model.
+ * 
+ * @author Federico Abascal
+ * @author Diego Darriba
+ * @since 3.0
+ */
+public interface RunEstimator extends Runnable {
+
+	/**
+	 * Gets the inner optimized model.
+	 * 
+	 * @return the model
+	 */
+	public Model getModel();
+	
+	/**
+	 * Optimizes the parameters of the model.
+	 * 
+	 * @return true, if there is no error in the execution of the optimizer
+	 */
+	public boolean optimizeModel();
+	
+	/**
+	 * Reports out the result of the optimization into the application loggers: 
+         * the optimized parameters of the model.
+	 */
+	public void report();
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.observer.ObservableModelUpdater#addObserver(es.uvigo.darwin.prottest.observer.ObservableModelUpdater)
+	 */
+	public void addObserver(ModelUpdaterObserver o);
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/RunEstimatorImpl.java b/src/main/java/es/uvigo/darwin/prottest/exe/RunEstimatorImpl.java
new file mode 100755
index 0000000..f1137e2
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/RunEstimatorImpl.java
@@ -0,0 +1,212 @@
+/*
+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.prottest.exe;
+
+
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ObservableModelUpdater;
+import es.uvigo.darwin.prottest.util.exception.ModelOptimizationException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+import static es.uvigo.darwin.prottest.util.logging.ProtTestLogger.*;
+
+/**
+ * Template implementation for every subclass applying the
+ * observer pattern into the analyzers. 
+ * 
+ * @author Federico Abascal
+ * @author Diego Darriba
+ * @since 3.0
+ */
+public abstract class RunEstimatorImpl
+        extends ObservableModelUpdater
+        implements RunEstimator {
+
+    /** The application options instance. */
+    protected ApplicationOptions options;
+    /** The inner model to optimize. */
+    protected Model model;
+    /** Indicates if the inner model is yet optimized. */
+    private boolean optimized;
+    /** The time taken for the optimization. */
+    protected String time;
+    /** The number of rate categories. */
+    protected int numberOfCategories;
+    /** The independent process. */
+    protected Process proc = null;
+    /** The number of threads for parallel execution **/
+    protected int numberOfThreads = 1;
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.exe.RunEstimator#getModel()
+     */
+    public Model getModel() {
+        return model;
+    }
+
+    /**
+     * Gets the thread pool size.
+     * 
+     * @return the thread pool size
+     */
+    protected int getPoolSize() {
+        return 1;
+    }
+
+    /**
+     * Gets the time taken to compute.
+     * 
+     * @return the time
+     */
+    public String getTime() {
+        if (optimized) {
+            return time;
+        } else {
+            throw new ProtTestInternalException("The model is not optimized");
+        }
+    }
+
+    /**
+     * Instantiates a new generic optimizer.
+     * 
+     * @param options the application options instance
+     * @param model the amino-acid model to optimize
+     */
+    public RunEstimatorImpl(ApplicationOptions options, Model model) {
+        this(options, model, 1);
+    }
+
+    /**
+     * Instantiates a new generic optimizer.
+     * 
+     * @param options the application options instance
+     * @param model the amino-acid model to optimize
+     * @param numberOfThreads the number of threads to use in the optimization
+     */
+    public RunEstimatorImpl(ApplicationOptions options, Model model, int numberOfThreads) {
+        this.options = options;
+        this.model = model;
+        this.optimized = model.isComputed();
+        this.numberOfThreads = numberOfThreads;
+    }
+    
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.exe.RunEstimator#optimizeModel(es.uvigo.darwin.prottest.global.options.ApplicationOptions)
+     */
+    public boolean optimizeModel() {
+
+        // notify task computation
+        notifyObservers(getModel(),null);
+        
+        boolean result = true;
+        try {
+            if (!optimized) {
+                result = runEstimator();
+            }
+        } catch (ModelOptimizationException ex) {
+            
+            severeln(ex.getMessage(), RunEstimator.class);
+            
+        } finally {
+            // notify results
+            notifyObservers(getModel(), options);
+            deleteTemporaryFiles();
+        }
+
+        optimized = result;
+
+        return result;
+
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.exe.RunEstimator#report()
+     */
+    public void report() {
+
+        if (optimized) {
+            printReport();
+        } else {
+            throw new ProtTestInternalException("The model is not optimized");
+        }
+
+    }
+
+    /**
+     * Runs the estimator.
+     * 
+     * @return true, if successful
+     */
+    public abstract boolean runEstimator()
+            throws ModelOptimizationException;
+
+    /**
+     * Prints a report of the execution.
+     */
+    public abstract void printReport();
+
+    /**
+     * Deletes temporary files of the execution.
+     * 
+     * @return true, if successful
+     */
+    protected abstract boolean deleteTemporaryFiles();
+
+    /* (non-Javadoc)
+     * @see java.lang.Runnable#run()
+     */
+    public void run() {
+
+        if (!this.optimizeModel()) {
+            throw new ProtTestInternalException("Optimization error");
+        }
+    }
+
+    protected void print(String message) {
+        info(message, RunEstimator.class);
+    }
+
+    protected void println(String message) {
+        infoln(message, RunEstimator.class);
+    }
+
+    protected void error(String message) {
+        severe(message, RunEstimator.class);
+    }
+
+    protected void errorln(String message) {
+        severeln(message, RunEstimator.class);
+    }
+    
+    protected void pfine(String message) {
+        fine(message, RunEstimator.class);
+    }
+
+    protected void pfineln(String message) {
+        fineln(message, RunEstimator.class);
+    }
+    
+    protected void pfiner(String message) {
+        finer(message, RunEstimator.class);
+    }
+
+    protected void pfinerln(String message) {
+        finerln(message, RunEstimator.class);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/StreamGobbler.java b/src/main/java/es/uvigo/darwin/prottest/exe/StreamGobbler.java
new file mode 100755
index 0000000..f3a553a
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/StreamGobbler.java
@@ -0,0 +1,53 @@
+/*
+Copyright (C) 2004  Federico Abascal
+
+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.prottest.exe;
+
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ * Allows the asynchronous logging of an input stream.
+ * 
+ * @author Federico Abascal
+ */
+public abstract class StreamGobbler extends Thread {
+
+    protected InputStreamReader isr;
+    protected String type;
+    protected boolean printIt;
+    protected Class caller;
+
+    /**
+     * Instantiates a new StreamGobbler
+     * 
+     * @param isr the input stream reader to evaluate
+     * @param type the prefix of the output lines
+     * @param printIt true, if the errors should be logged
+     * @param caller the caller
+     */
+    public StreamGobbler(InputStreamReader isr, String type, boolean printIt, Class caller) {
+        this.isr = isr;
+        this.type = type;
+        this.printIt = printIt;
+        this.caller = caller;
+    }
+
+}
+
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/package.html b/src/main/java/es/uvigo/darwin/prottest/exe/package.html
new file mode 100755
index 0000000..6029212
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/package.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+<p>
+Contains all classes related to model optimization. The <code>RunEstimator</code> interface
+contains the method signatures which every optimizer must implement. There is a generic
+class with common method implementations: <code>RunEstimatorImpl</code>, but every specific
+strategy to optimize the models should extend this class or at least implement the interface.
+</p>
+<p>
+For example, <code>PhyML</code> optimizer has his own implementation <code>PhyMLv3AminoAcidRunEstimator</code>.
+In future versions this vertical hierarchy, which could allow extension to support Nucleotide models,
+should be transformed following a Bridge Pattern.
+</p>
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/util/TemporaryFileManager.java b/src/main/java/es/uvigo/darwin/prottest/exe/util/TemporaryFileManager.java
new file mode 100755
index 0000000..4db5dcb
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/util/TemporaryFileManager.java
@@ -0,0 +1,256 @@
+/*
+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.prottest.exe.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import pal.alignment.Alignment;
+import pal.alignment.AlignmentUtils;
+import pal.tree.Tree;
+import pal.tree.TreeUtils;
+import es.uvigo.darwin.prottest.facade.thread.ThreadPoolSynchronizer;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+/**
+ * A singleton class to manage the temporary files usage in the
+ * application. It should be accessible for every thread that gets
+ * part in the execution.
+ */
+public class TemporaryFileManager {
+
+	/** The Constant BASE_ALIGNMENT_FILE_NAME. */
+	private static final String BASE_ALIGNMENT_FILE_NAME = "prottest_alignment_";
+	
+	/** The Constant BASE_TREE_FILE_NAME. */
+	private static final String BASE_TREE_FILE_NAME = "prottest_tree_";
+	
+	/** The Constant BASE_LOG_FILE_NAME. */
+	private static final String BASE_LOG_FILE_NAME = "prottest_";
+	
+	/** The unique instance. */
+	private static TemporaryFileManager instance;
+	
+	/** The alignment temporary files. */
+	private File[] alignmentTempFile;
+	
+	/** The log temporary files. */
+	private File[] logTempFile;
+	
+	/** The tree temporary file. */
+	private File treeTempFile;
+	
+	/** The thread pool synchronizer. */
+	private ThreadPoolSynchronizer synchronizer;
+	
+	/** The alignment. */
+	private Alignment alignment;
+	
+	/** The tree. */
+	private Tree tree;
+	
+	/**
+	 * Gets the alignment filename.
+	 * 
+	 * @param thread the thread
+	 * 
+	 * @return the alignment filename
+	 */
+	public String getAlignmentFilename(Thread thread) {
+		int threadId = synchronizer.getThreadId(thread);
+		return alignmentTempFile[threadId].getAbsolutePath();
+	}
+	
+	/**
+	 * Gets the log filename.
+	 * 
+	 * @param thread the thread
+	 * 
+	 * @return the log filename
+	 */
+	public String getLogFilename(Thread thread) {
+		int threadId = synchronizer.getThreadId(thread);
+		return logTempFile[threadId].getAbsolutePath();
+	}
+	
+	/**
+	 * Gets the tree filename for a thread.
+	 * 
+	 * @param thread the thread
+	 * 
+	 * @return the tree filename
+	 */
+	public String getTreeFilename(Thread thread) {
+		if (tree == null)
+			return null;
+		return treeTempFile.getAbsolutePath();
+	}
+	
+	/**
+	 * Checks if is synchronized.
+	 * 
+	 * @return true, if is synchronized
+	 */
+	public static boolean isSynchronized() {
+		return instance != null;
+	}
+	
+	/**
+	 * Sets the input tree. For each manager sync, the input tree should be set just 
+	 * once, or all the trees must be the same (i.e., this method can be used to
+	 * check consistency between processes) 
+	 * 
+	 * @param tree the new tree
+	 * 
+	 * @throws ProtTestInternalException when attempting to set different trees
+	 */
+	public void setTree(Tree tree) {
+		if (this.tree == null) {
+			convertTree(tree, treeTempFile);
+			this.tree = tree;
+		} else {
+			if (!tree.equals(this.tree)) {
+				throw new ProtTestInternalException("Attempting to set different trees");
+			}
+		}
+			
+	}
+	
+	/**
+	 * Gets the input tree.
+	 * 
+	 * @return the tree
+	 */
+	public Tree getTree() {
+		return tree;
+	}
+	
+	/**
+	 * Gets the input alignment.
+	 * 
+	 * @return the alignment
+	 */
+	public Alignment getAlignment() {
+		return alignment;
+	}
+	
+	/**
+	 * Instantiates a new temporary file manager.
+	 * 
+	 * @param path the path
+	 * @param alignment the alignment
+	 * @param tree the tree
+	 * @param poolSize the pool size
+	 */
+	private TemporaryFileManager(Alignment alignment, Tree tree, int poolSize) {
+		
+		alignmentTempFile = new File[poolSize];
+		logTempFile = new File[poolSize];
+		this.alignment = alignment;
+		this.tree = tree;
+
+		try {
+		    for (int i = 0; i < poolSize; i++) {
+		    	alignmentTempFile[i] = File.createTempFile(BASE_ALIGNMENT_FILE_NAME, null);
+		    	alignmentTempFile[i].deleteOnExit();
+		    	logTempFile[i] = File.createTempFile(BASE_LOG_FILE_NAME, null);
+		    	logTempFile[i].deleteOnExit();
+		        convertAlignment(alignment, alignmentTempFile[i]);
+	        }
+		    treeTempFile = File.createTempFile(BASE_TREE_FILE_NAME, null);
+		    treeTempFile.deleteOnExit();
+		    if (tree != null)
+	        	convertTree(tree, treeTempFile);
+		} catch (IOException e) {
+			throw new ProtTestInternalException("Cannot create temporary files");
+		}
+	    ThreadPoolSynchronizer.synchronize(poolSize);
+	    synchronizer = ThreadPoolSynchronizer.getInstance();
+	}
+	
+	/**
+	 * Gets the single instance of TemporaryFileManager.
+	 * 
+	 * @return single instance of TemporaryFileManager
+	 */
+	public static TemporaryFileManager getInstance() {
+		if (instance == null) {
+			throw new ProtTestInternalException("TemporaryFileManager out of sync");
+		}
+		return instance;
+	}
+	
+	/**
+	 * Synchronizes this manager.
+	 * 
+	 * @param alignment the input alignment
+	 * @param tree the input tree
+	 * @param poolSize the pool size
+	 */
+	public static void synchronize(Alignment alignment, Tree tree, int poolSize) {
+		instance = new TemporaryFileManager(alignment, tree, poolSize);
+	}
+	
+	/**
+	 * Converts an alignment into a file.
+	 * 
+	 * @param alignment the input alignment
+	 * @param outputFile the output file
+	 * 
+	 * @return true, if successful
+	 */
+	private boolean convertAlignment(Alignment alignment, File outputFile) {
+		try {
+			FileOutputStream fo = new FileOutputStream(outputFile);
+			PrintWriter output              = new PrintWriter(fo);
+			//AlignmentUtils.printSequential(alignment, output);
+			AlignmentUtils.printInterleaved(alignment, output);
+			output.flush();
+			output.close();
+		} catch (IOException e) {
+			throw new ProtTestInternalException();
+		}
+		return true;
+	}
+
+	/**
+	 * Converts a tree into a file.
+	 * 
+	 * @param tree the input tree
+	 * @param outputFile the output file
+	 * 
+	 * @return true, if successful
+	 */
+	private boolean convertTree(Tree tree, File outputFile) {
+		if (tree != null) {
+			try {
+				FileOutputStream fo = new FileOutputStream(outputFile);
+				PrintWriter output  = new PrintWriter(fo);
+				TreeUtils.printNH(tree, output);
+				output.flush();
+				output.close();
+			} catch (IOException e) {
+				throw new ProtTestInternalException();
+			}
+		}
+		return true;
+	}
+	
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/exe/util/package.html b/src/main/java/es/uvigo/darwin/prottest/exe/util/package.html
new file mode 100755
index 0000000..4a1e447
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/exe/util/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains common utils related to model optimization.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacade.java b/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacade.java
new file mode 100755
index 0000000..0e30b7a
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacade.java
@@ -0,0 +1,144 @@
+/*
+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.prottest.facade;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import pal.alignment.Alignment;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.facade.util.ProtTestParameterVO;
+import es.uvigo.darwin.prottest.facade.util.SelectionChunk;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ModelUpdaterObserver;
+import es.uvigo.darwin.prottest.observer.ObservableModelUpdater;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.util.exception.AlignmentParseException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.exception.TreeFormatException;
+import java.io.FileNotFoundException;
+
+/**
+ * Declaration of general services of ProtTest-HPC
+ * 
+ * @author Diego Darriba
+ * 
+ * @since 3.0
+ */
+public interface ProtTestFacade extends ModelUpdaterObserver {
+
+	// **********************************************************
+	// ALIGNMENT ANALYSIS SERVICES
+	// **********************************************************
+	/**
+	 * Starts the analysis of the alignment having the application options given
+	 * in the command line. It will also print results as given in the
+	 * application options.
+	 * 
+	 * @param options
+	 *            the execution options
+	 * 
+	 * @return set of optimized models
+	 */
+	public Model[] startAnalysis(ApplicationOptions options);
+
+	// **********************************************************
+	// RESULT ANALYSIS SERVICES
+	// **********************************************************
+	/**
+	 * Prints the models sorted according to the selected information criterion.
+	 * 
+	 * @param informationCriterion
+	 *            the information criterion to sort the models
+	 */
+	public void printModelsSorted(InformationCriterion informationCriterion);
+
+	/**
+	 * Calculates a Information Criterion wrapped into a Selection chunk object,
+	 * which is a value-object
+	 * 
+	 * @param alignment
+	 *            the alignment.
+	 * @param models
+	 *            the optimized models .
+	 * @param criterion
+	 *            the Information Criterion Constant.
+	 * @param confidenceInterval
+	 *            the confidence interval.
+	 */
+	public SelectionChunk computeInformationCriterion(Alignment alignment,
+			Model[] models, int criterion, double confidenceInterval);
+
+	// **********************************************************
+	// INPUT SERVICES
+	// **********************************************************
+	/**
+	 * Read alignment.
+	 * 
+	 * @param filename
+	 *            the filename
+	 * @param debug
+	 *            the debug
+	 * 
+	 * @return the alignment
+	 * 
+	 * @throws AlignmentParseException
+	 *             the alignment parse exception
+	 * @throws IOException
+	 *             Signals that an I/O exception has occurred.
+	 */
+	public Alignment readAlignment(String filename, boolean debug)
+			throws AlignmentParseException, FileNotFoundException, IOException;
+
+	/**
+	 * Read alignment.
+	 * 
+	 * @param out
+	 *            the out
+	 * @param filename
+	 *            the filename
+	 * @param debug
+	 *            the debug
+	 * 
+	 * @return the alignment
+	 * 
+	 * @throws AlignmentParseException
+	 *             the alignment parse exception
+	 * @throws IOException
+	 *             Signals that an I/O exception has occurred.
+	 */
+	public Tree readTree(PrintWriter out, String filename, boolean debug)
+			throws TreeFormatException, FileNotFoundException, IOException;
+
+	// **********************************************************
+	// MISC SERVICES
+	// **********************************************************
+	public ApplicationOptions configure(ProtTestParameterVO parameters)
+			throws IOException, AlignmentParseException,
+			ProtTestInternalException;
+
+	public void addObserver(ModelUpdaterObserver o);
+
+	public void update(ObservableModelUpdater o, Model model,
+			ApplicationOptions options);
+
+	public int getNumberOfThreads();
+
+	public void setNumberOfThreads(int numThreads);
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeImpl.java b/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeImpl.java
new file mode 100755
index 0000000..0605191
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeImpl.java
@@ -0,0 +1,276 @@
+/*
+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.prottest.facade;
+
+import static es.uvigo.darwin.prottest.global.ApplicationGlobals.*;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Properties;
+
+import pal.alignment.Alignment;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.exe.RunEstimator;
+import es.uvigo.darwin.prottest.exe.util.TemporaryFileManager;
+import es.uvigo.darwin.prottest.facade.util.ProtTestParameterVO;
+import es.uvigo.darwin.prottest.facade.util.SelectionChunk;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ObservableModelUpdater;
+import es.uvigo.darwin.prottest.selection.AIC;
+import es.uvigo.darwin.prottest.selection.AICc;
+import es.uvigo.darwin.prottest.selection.BIC;
+import es.uvigo.darwin.prottest.selection.DT;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.selection.LNL;
+import es.uvigo.darwin.prottest.selection.printer.AminoAcidPrintFramework;
+import es.uvigo.darwin.prottest.selection.printer.PrintFramework;
+import es.uvigo.darwin.prottest.util.ProtTestAlignment;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import es.uvigo.darwin.prottest.util.exception.AlignmentParseException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.exception.TreeFormatException;
+import es.uvigo.darwin.prottest.util.factory.ProtTestFactory;
+import es.uvigo.darwin.prottest.util.fileio.AlignmentReader;
+
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import java.io.StringWriter;
+import static es.uvigo.darwin.prottest.util.logging.ProtTestLogger.*;
+
+/**
+ * An abstract implementation of the ProtTest facade.
+ */
+public abstract class ProtTestFacadeImpl
+        extends ObservableModelUpdater
+        implements ProtTestFacade {
+
+//	/** The options. */
+//	protected ApplicationOptions options;
+    /** The Constant AIC. */
+    public static final int AIC = SelectionChunk.AIC;
+    /** The Constant BIC. */
+    public static final int BIC = SelectionChunk.BIC;
+    /** The Constant AICC. */
+    public static final int AICC = SelectionChunk.AICC;
+    /** The Constant DT. */
+    public static final int DT = SelectionChunk.DT;
+    /** The Constant LK. */
+    public static final int LNL = SelectionChunk.LNL;
+
+    /**
+     * Instantiates a new prot test facade implementation.
+     */
+    public ProtTestFacadeImpl() {
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#printModelsSorted(es.uvigo.darwin.prottest.selection.InformationCriterion, java.io.PrintWriter)
+     */
+    public void printModelsSorted(InformationCriterion informationCriterion) {
+
+        PrintFramework printFramework = new AminoAcidPrintFramework();
+
+        printFramework.printModelsSorted(informationCriterion);
+
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#readAlignment(java.io.PrintWriter, java.lang.String, boolean)
+     */
+    public Alignment readAlignment(String filename, boolean debug)
+            throws AlignmentParseException, FileNotFoundException, IOException {
+
+        StringWriter sw = new StringWriter();
+        Alignment alignment = AlignmentReader.readAlignment(new PrintWriter(sw), filename, debug);
+        
+        sw.flush();
+        ProtTestLogger.getDefaultLogger().infoln(sw.toString());
+        
+        return alignment;
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#readTree(java.io.PrintWriter, java.lang.String, boolean)
+     */
+    public Tree readTree(PrintWriter out, String filename, boolean debug)
+            throws TreeFormatException, FileNotFoundException, IOException {
+
+        return AlignmentReader.readTree(out, filename, debug);
+    
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#update(es.uvigo.darwin.prottest.observer.Observable, java.lang.Object)
+     */
+    public void update(ObservableModelUpdater o, Model model, ApplicationOptions options) {
+        notifyObservers(model, options);
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#computeInformationCriterion(pal.alignment.Alignment, es.uvigo.darwin.prottest.model.Model[], int, int, double)
+     */
+    public SelectionChunk computeInformationCriterion(Alignment alignment, Model[] models,
+            int criterion,
+            double confidenceInterval) {
+
+        ModelCollection modelCollection = new SingleModelCollection(models, alignment);
+
+        InformationCriterion informationCriterion;
+
+        double calculatedSampleSize = ProtTestAlignment.calculateSampleSize(alignment);
+
+        switch (criterion) {
+            case AIC:
+                informationCriterion = new AIC(modelCollection, confidenceInterval, calculatedSampleSize);
+                break;
+            case BIC:
+                informationCriterion = new BIC(modelCollection, confidenceInterval, calculatedSampleSize);
+                break;
+            case AICC:
+                informationCriterion = new AICc(modelCollection, confidenceInterval, calculatedSampleSize);
+                break;
+            case DT:
+                informationCriterion = new DT(modelCollection, confidenceInterval, calculatedSampleSize);
+                break;
+            case LNL:
+                informationCriterion = new LNL(modelCollection, confidenceInterval, calculatedSampleSize);
+                break;
+            default:
+                throw new ProtTestInternalException("Unexistent information criterion");
+        }
+
+        return new SelectionChunk(informationCriterion);
+
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#getNumberOfThreads()
+     */
+    public int getNumberOfThreads() {
+        // single thread (default)
+        return 1;
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#setNumberOfThreads(int)
+     */
+    public void setNumberOfThreads(int numThreads) {
+        throw new ProtTestInternalException("No threading support");
+    }
+
+    protected Tree calculateBionjJTT(ApplicationOptions options) {
+
+        Model jttModel = ProtTestFactory.getInstance().createModel("JTT", options.getDistribution("Uniform"), new Properties(),
+                options.getAlignment(), null, 0);
+        TemporaryFileManager.synchronize(
+                options.getAlignment(), null, 1);
+        RunEstimator treeEstimator = ProtTestFactory.getInstance().createRunEstimator(options, jttModel);
+        treeEstimator.run();
+
+        return jttModel.getTree();
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#startAnalysis(es.uvigo.darwin.prottest.util.printer.ProtTestPrinter)
+     */
+    public Model[] startAnalysis(ApplicationOptions options) {
+
+        if (options.getTreeFile() == null) {
+            // this way, the starting topology is the same for every model
+            if (options.strategyMode == OPTIMIZE_FIXED_BIONJ) {
+                // use JTT BIONJ Tree
+                Tree jttTree = calculateBionjJTT(options);
+
+                options.setTree(jttTree);
+            }
+        }
+        TemporaryFileManager.synchronize(options.getAlignment(), options.getTree(),
+                getNumberOfThreads());
+        Model[] models = analyze(options);
+
+        return models;
+    }
+
+    /**
+     * Analyze.
+     * 
+     * @param options the execution options
+     * 
+     * @return the set of optimized models
+     */
+    public abstract Model[] analyze(ApplicationOptions options);
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#configure(es.uvigo.darwin.prottest.facade.util.ProtTestParameterVO)
+     */
+    public ApplicationOptions configure(ProtTestParameterVO parameters)
+            throws IOException, AlignmentParseException, ProtTestInternalException {
+        ApplicationOptions options = new ApplicationOptions();
+        if (parameters.getAlignment() != null) {
+            options.setAlignment(parameters.getAlignment());
+            options.setAlignmentFilename(parameters.getAlignmentFilePath());
+        } else {
+            options.setAlignment(parameters.getAlignmentFilePath());
+        }
+        options.setNumberOfCategories(parameters.ncat);
+        for (String matrix : parameters.getMatrices()) {
+            options.addMatrix(matrix);
+        }
+        for (String distribution : parameters.getDistributions()) {
+            options.addDistribution(distribution);
+        }
+        options.setPlusF(parameters.isPlusF());
+        options.setTreeFile(parameters.getTreeFilePath());
+        options.setStrategyMode(parameters.getStrategyMode());
+        return options;
+    }
+
+    protected void print(String message) {
+        info(message, ProtTestFacade.class);
+    }
+
+    protected void println(String message) {
+        infoln(message, ProtTestFacade.class);
+    }
+
+    protected void error(String message) {
+        severe(message, ProtTestFacade.class);
+    }
+
+    protected void errorln(String message) {
+        severeln(message, ProtTestFacade.class);
+    }
+    
+    protected void warnln(String message) {
+        warningln(message, ProtTestFacade.class);
+    }
+
+    protected void verbose(String message) {
+        fine(message, ProtTestFacade.class);
+    }
+
+    protected void verboseln(String message) {
+        fineln(message, ProtTestFacade.class);
+    }
+
+    protected void flush() {
+        ProtTestLogger.flush(ProtTestFacade.class);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeMPJ.java b/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeMPJ.java
new file mode 100755
index 0000000..8789c40
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeMPJ.java
@@ -0,0 +1,210 @@
+/*
+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.prottest.facade;
+
+import static es.uvigo.darwin.prottest.global.ApplicationGlobals.APPLICATION_PROPERTIES;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
+import mpi.MPI;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.exe.util.TemporaryFileManager;
+import es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy;
+import es.uvigo.darwin.prottest.facade.strategy.DynamicDistributionStrategy;
+import es.uvigo.darwin.prottest.facade.strategy.HybridDistributionStrategy;
+import es.uvigo.darwin.prottest.facade.strategy.ImprovedDynamicDistributionStrategy;
+import es.uvigo.darwin.prottest.facade.strategy.StaticDistributionStrategy;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.ProtTestAlignment;
+import es.uvigo.darwin.prottest.util.Utilities;
+import es.uvigo.darwin.prottest.util.checkpoint.CheckPointManager;
+import es.uvigo.darwin.prottest.util.checkpoint.status.ProtTestStatus;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import es.uvigo.darwin.prottest.util.comparator.AminoAcidModelNaturalComparator;
+import es.uvigo.darwin.prottest.util.comparator.ModelDistributionHeuristic;
+
+/**
+ * A parallel implementation of the ProtTest facade.
+ */
+public class ProtTestFacadeMPJ extends ProtTestFacadeImpl {
+
+    /** The parallel distribution strategy. */
+    private DistributionStrategy strategy;
+    /** Boolean variable to show if MPJ environment is running. Some
+     * distribution strategies can be used even if the execution is
+     * sequential. */
+    private boolean mpjRun;
+    /** The MPJ rank of the process. It is only useful if MPJ is running. */
+    private int mpjMe;
+    /** The MPJ size of the communicator. It is only useful if MPJ is running. */
+    private int mpjSize;
+    /** The thread pool size. */
+    private int poolSize = 1;
+    private CheckPointManager cpManager;
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#getNumberOfThreads()
+     */
+    @Override
+    public int getNumberOfThreads() {
+        return poolSize;
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#setNumberOfThreads(int)
+     */
+    @Override
+    public void setNumberOfThreads(int numThreads) {
+//		options.setNumberOfThreads(numThreads);
+        this.poolSize = numThreads;
+    }
+    
+    /**
+     * Instantiates a new parallel ProtTest facade.
+     * 
+     * @param mpjRun the running state of MPJ
+     * @param mpjMe the rank of the current process in MPJ
+     * @param mpjSize the size of the MPJ communicator
+     */
+    public ProtTestFacadeMPJ(boolean mpjRun, int mpjMe, int mpjSize) {
+        this.mpjRun = mpjRun;
+        this.mpjMe = mpjMe;
+        this.mpjSize = mpjSize;
+    }
+
+    @Override
+    protected Tree calculateBionjJTT(ApplicationOptions options) {
+        Tree[] t = new Tree[1];
+        if (mpjMe == 0) {
+            t[0] = super.calculateBionjJTT(options);
+        }
+        MPI.COMM_WORLD.Bcast(t, 0, 1, MPI.OBJECT, 0);
+        return t[0];
+    }
+
+    public Model[] analyze(ApplicationOptions options) {
+
+        ModelCollection arrayListModel = null;
+        if (mpjMe == 0) {
+            //Adding support for checkpointing
+            ProtTestStatus initialStatus = new ProtTestStatus(null, options);
+
+            cpManager = new CheckPointManager();
+            if (cpManager.loadStatus(initialStatus)) {
+                arrayListModel = new SingleModelCollection(
+                        ((ProtTestStatus) cpManager.getLastCheckpoint()).getModels(),
+                        options.getAlignment());
+            } else {
+                arrayListModel = new SingleModelCollection(options.getAlignment());
+                Properties modelProperties = new Properties();
+                if (options.isPlusF()) {
+                    modelProperties.setProperty(Model.PROP_PLUS_F, "true");
+                }
+                arrayListModel.addModelCartesian(options.getMatrices(), options.getDistributions(), modelProperties,
+                        options.getAlignment(), options.getTree(), options.ncat);
+            }
+        }
+        String strategyProp = APPLICATION_PROPERTIES.getProperty("parallel_strategy", "static");
+
+        if (strategyProp.equals("dynamic")) {
+            strategy = new DynamicDistributionStrategy(mpjMe, mpjSize, options, cpManager);
+        } else if (strategyProp.equals("dynamic_improved")) {
+            strategy = new ImprovedDynamicDistributionStrategy(mpjMe, mpjSize, options, cpManager);
+        } else if (strategyProp.equals("hybrid")) {
+            int numberOfThreads;
+            try {
+                numberOfThreads = Integer.parseInt(APPLICATION_PROPERTIES.getProperty("number_of_threads", 
+                    String.valueOf(Runtime.getRuntime().availableProcessors())));
+            } catch (NumberFormatException ex) {
+                numberOfThreads = Runtime.getRuntime().availableProcessors();
+            }
+            setNumberOfThreads(numberOfThreads);
+            strategy = new HybridDistributionStrategy(mpjMe, mpjSize, options, cpManager, getNumberOfThreads());
+            TemporaryFileManager.synchronize(options.getAlignment(), options.getTree(),
+                getNumberOfThreads());
+        } else {
+            strategy = new StaticDistributionStrategy(mpjMe, mpjSize, options);
+        }
+        strategy.addObserver(this);
+
+        Model[] allModels = null;
+
+        //For each model, for each distribution,... optimize the model and calculate some statistics:
+        if (mpjMe == 0) {
+            println("**********************************************************");
+            //this is only for doing output prettier
+            println("Observed number of invariant sites: " + ProtTestAlignment.calculateInvariableSites(options.getAlignment(), false));
+            StringWriter sw = new StringWriter();
+            ProtTestAlignment.printFrequencies(ProtTestAlignment.getFrequencies(options.getAlignment()), new PrintWriter(sw));
+            sw.flush();
+            println(sw.toString());
+            println("**********************************************************");
+            println("");
+
+            allModels = strategy.distribute(arrayListModel, new ModelDistributionHeuristic());
+        } else {
+            strategy.request();
+        }
+        long startTime = strategy.getStartTime();
+        long endTime = strategy.getEndTime();
+        if (mpjRun) {
+
+            long[] runtime = {endTime - startTime};
+            long[] runtimes = new long[mpjSize];
+            // gathering run times
+            MPI.COMM_WORLD.Gather(runtime, 0, 1, MPI.LONG,
+                    runtimes, 0, 1, MPI.LONG, 0);
+            if (mpjMe == 0) {
+                List<Model> sortedModels = new SingleModelCollection(allModels, options.getAlignment());
+                Collections.sort(sortedModels, new AminoAcidModelNaturalComparator());
+                for (Model model : sortedModels) {
+                    println("");
+                    model.printReport();
+                    println("");
+                }
+                println("************************************************************");
+                println("Date: " + (new Date()).toString());
+                for (int i = 0; i < mpjSize; i++) {
+                    println("Runtime processor " + i + ":  " + Utilities.arrangeRuntime(runtimes[i]));
+                }
+                println("Minimum runtime: " + Utilities.arrangeRuntime(Utilities.getMin(runtimes)));
+                println("Maximum runtime: " + Utilities.arrangeRuntime(Utilities.getMax(runtimes)));
+                println("Average runtime: " + Utilities.arrangeRuntime(Utilities.getAverage(runtimes)));
+                println("");
+                println("");
+                flush();
+            }
+        } else {
+            println("************************************************************");
+            String runtimeStr = Utilities.calculateRuntime(startTime, endTime);
+            println("Date   :  " + (new Date()).toString());
+            println("Runtime:  " + runtimeStr);
+            println("");
+            println("");
+        }
+
+        return allModels;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeSequential.java b/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeSequential.java
new file mode 100755
index 0000000..a9ce4b7
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeSequential.java
@@ -0,0 +1,135 @@
+/*
+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.prottest.facade;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Date;
+import java.util.Properties;
+
+import es.uvigo.darwin.prottest.exe.RunEstimator;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ObservableModelUpdater;
+import es.uvigo.darwin.prottest.util.ProtTestAlignment;
+import es.uvigo.darwin.prottest.util.Utilities;
+import es.uvigo.darwin.prottest.util.checkpoint.CheckPointManager;
+import es.uvigo.darwin.prottest.util.checkpoint.status.ProtTestStatus;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import es.uvigo.darwin.prottest.util.factory.ProtTestFactory;
+
+/**
+ * A sequential implementation of the ProtTest facade.
+ */
+public class ProtTestFacadeSequential extends ProtTestFacadeImpl {
+
+    private CheckPointManager cpManager;
+    private ModelCollection modelSet;
+    /** The ProtTest factory to instantiate some application objects. */
+    private ProtTestFactory factory = ProtTestFactory.getInstance();
+
+    public Model[] analyze(ApplicationOptions options) {
+
+        //For each model, for each distribution,... optimize the model and calculate some statistics:
+
+        println("**********************************************************");
+        //this is only for doing output prettier
+        println("Observed number of invariant sites: " + ProtTestAlignment.calculateInvariableSites(options.getAlignment(), false));
+        StringWriter sw = new StringWriter();
+        ProtTestAlignment.printFrequencies(ProtTestAlignment.getFrequencies(options.getAlignment()),
+                new PrintWriter(sw));
+        sw.flush();
+        println(sw.toString());
+        println("**********************************************************");
+        println("");
+
+        //TimeStamp timer = new TimeStamp();
+        Date startDate = new Date();
+        long startTime = startDate.getTime();
+
+        int numberOfModels = 0;
+
+        ModelCollection arrayListModel = new SingleModelCollection(options.getAlignment());
+
+        //Adding support for checkpointing
+        ProtTestStatus initialStatus = new ProtTestStatus(null, options);
+        cpManager = new CheckPointManager();
+
+        if (cpManager.loadStatus(initialStatus)) {
+            arrayListModel = new SingleModelCollection(
+                    ((ProtTestStatus) cpManager.getLastCheckpoint()).getModels(),
+                    options.getAlignment());
+        } else {
+            Properties modelProperties = new Properties();
+
+            if (options.isPlusF()) {
+                modelProperties.setProperty(Model.PROP_PLUS_F, "true");
+            }
+            arrayListModel.addModelCartesian(options.getMatrices(), options.getDistributions(), modelProperties,
+                    options.getAlignment(), options.getTree(), options.ncat);
+        }
+        numberOfModels = arrayListModel.size();
+        modelSet = arrayListModel;
+
+        flush();
+
+        RunEstimator[] runenv = new RunEstimator[modelSet.size()];
+
+        int current = 0;
+        for (Model model : modelSet) {
+
+            runenv[current] = factory.createRunEstimator(options, model);
+            runenv[current].addObserver(this);
+            runenv[current].run();
+
+            runenv[current].report();
+            flush();
+            current++;
+
+        }
+
+        long endTime = System.currentTimeMillis();
+
+        Model[] allModels = new Model[numberOfModels];
+
+        println("************************************************************");
+        String runtimeStr = Utilities.calculateRuntime(startTime, endTime);
+        println("Date   :  " + (new Date()).toString());
+        println("Runtime:  " + runtimeStr);
+        println("");
+        println("");
+        allModels = modelSet.toArray(new Model[0]);
+
+        cpManager.done();
+        return allModels;
+    }
+
+    @Override
+    public void update(ObservableModelUpdater o, Model model, ApplicationOptions options) {
+
+        if (model.isComputed() && options != null) {
+            if (cpManager != null) {
+                ProtTestStatus newStatus = new ProtTestStatus(modelSet.toArray(new Model[0]), options);
+                cpManager.setStatus(newStatus);
+            }
+        }
+
+        super.update(o, model, options);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeThread.java b/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeThread.java
new file mode 100755
index 0000000..0545ba7
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/ProtTestFacadeThread.java
@@ -0,0 +1,231 @@
+/*
+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.prottest.facade;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Properties;
+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.prottest.exe.RunEstimator;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ObservableModelUpdater;
+import es.uvigo.darwin.prottest.util.ProtTestAlignment;
+import es.uvigo.darwin.prottest.util.Utilities;
+import es.uvigo.darwin.prottest.util.checkpoint.CheckPointManager;
+import es.uvigo.darwin.prottest.util.checkpoint.status.ProtTestStatus;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import es.uvigo.darwin.prottest.util.comparator.AminoAcidModelNaturalComparator;
+import es.uvigo.darwin.prottest.util.comparator.ModelDistributionHeuristic;
+import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
+import es.uvigo.darwin.prottest.util.factory.ProtTestFactory;
+
+/**
+ * A parallel implementation of the ProtTest facade.
+ */
+public class ProtTestFacadeThread
+        extends ProtTestFacadeImpl {
+
+    private CheckPointManager cpManager;
+    private ModelCollection modelSet;
+    /** The thread pool size. */
+    private int poolSize;
+    /** The ProtTest factory to instantiate some application objects. */
+    private ProtTestFactory factory = ProtTestFactory.getInstance();
+    private ExecutorService threadPool;
+
+    /**
+     * Instantiates a new parallel ProtTest facade.
+     * 
+     * @param poolSize the number of parallel processes
+     */
+    public ProtTestFacadeThread(int poolSize) {
+        this.poolSize = poolSize;
+//		options.setNumberOfThreads(poolSize);
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#getNumberOfThreads()
+     */
+    @Override
+    public int getNumberOfThreads() {
+        return poolSize;
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#setNumberOfThreads(int)
+     */
+    @Override
+    public void setNumberOfThreads(int numThreads) {
+//		options.setNumberOfThreads(numThreads);
+        this.poolSize = numThreads;
+    }
+
+    public Model[] analyze(ApplicationOptions options) {
+
+        this.threadPool = Executors.newFixedThreadPool(this.poolSize);
+
+        //For each model, for each distribution,... optimize the model and calculate some statistics:
+
+        println("**********************************************************");
+        //this is only for doing output prettier
+        println("Observed number of invariant sites: " + ProtTestAlignment.calculateInvariableSites(options.getAlignment(), false));
+        StringWriter sw = new StringWriter();
+        ProtTestAlignment.printFrequencies(ProtTestAlignment.getFrequencies(options.getAlignment()), new PrintWriter(sw));
+        sw.flush();
+        println(sw.toString());
+        println("**********************************************************");
+        println("");
+
+        //TimeStamp timer = new TimeStamp();
+        Date startDate = new Date();
+        long startTime = startDate.getTime();
+
+        int numberOfModels = 0;
+
+        ModelCollection arrayListModel;
+        //Adding support for checkpointing
+        ProtTestStatus initialStatus = new ProtTestStatus(null, options);
+
+        cpManager = new CheckPointManager();
+        if (cpManager.loadStatus(initialStatus)) {
+            arrayListModel = new SingleModelCollection(
+                    ((ProtTestStatus) cpManager.getLastCheckpoint()).getModels(),
+                    options.getAlignment());
+        } else {
+            arrayListModel = new SingleModelCollection(options.getAlignment());
+            Properties modelProperties = new Properties();
+            if (options.isPlusF()) {
+                modelProperties.setProperty(Model.PROP_PLUS_F, "true");
+            }
+            arrayListModel.addModelCartesian(options.getMatrices(), options.getDistributions(), modelProperties,
+                    options.getAlignment(), options.getTree(), options.ncat);
+        }
+
+        ModelWeightComparator comparator = new ModelDistributionHeuristic();
+        Collections.sort(arrayListModel, comparator);
+
+        numberOfModels = arrayListModel.size();
+        modelSet = arrayListModel;
+
+        flush();
+
+        RunEstimator[] runenv = new RunEstimator[modelSet.size()];
+        Collection<Callable<Object>> c = new ArrayList<Callable<Object>>();
+
+        int current = 0;
+        for (Model model : modelSet) {
+
+            runenv[current] = factory.createRunEstimator(options, model);
+            runenv[current].addObserver(this);
+
+            c.add(Executors.callable(runenv[current]));
+            current++;
+
+        }
+
+        boolean errorsFound = false;
+        Collection<Future<Object>> futures = null;
+        try {
+            futures = threadPool.invokeAll(c);
+        } catch (InterruptedException e) {
+        }
+        if (futures != null) {
+            for (Future<Object> f : futures) {
+                try {
+                    f.get();
+                                    } catch (InterruptedException ex) {
+                    errorsFound = true;
+                } catch (ExecutionException ex) {
+                    // Internal exception while computing model.
+                    // Let's continue with errors
+                    errorsFound = true;
+                }
+            }
+        }
+
+        long endTime = System.currentTimeMillis();
+
+        //check all models and remove those with errors
+        for (current = 0; current < runenv.length; current++) {
+            Model model = runenv[current].getModel();
+            if (!model.isComputed()) {
+                arrayListModel.remove(model);
+                numberOfModels--;
+                warnln("There were errors computing model " + model.getModelName());
+            }
+        }
+
+        println("");
+        println("");
+
+        // print optimization reports sorted
+        Collections.sort(arrayListModel, new AminoAcidModelNaturalComparator());
+        for (Model model : arrayListModel) {
+            for (current = 0; current < runenv.length; current++) {
+                if (runenv[current].getModel().equals(model)) {
+                    runenv[current].report();
+                    break;
+                }
+            }
+        }
+        flush();
+
+        Model[] allModels = new Model[numberOfModels];
+
+        println("************************************************************");
+        String runtimeStr = Utilities.calculateRuntime(startTime, endTime);
+        println("Date   :  " + (new Date()).toString());
+        println("Runtime:  " + runtimeStr);
+        println("");
+        println("");
+        allModels = arrayListModel.toArray(new Model[0]);
+
+        cpManager.done();
+        return allModels;
+    }
+
+//	public ApplicationOptions configure(ProtTestParameterVO parameters) 
+//	throws IOException, AlignmentParseException, ProtTestInternalException {
+//		ApplicationOptions.synchronize();
+////		options.setNumberOfThreads(poolSize);
+//		return super.configure(parameters);
+//	}
+    @Override
+    public synchronized void update(ObservableModelUpdater o, Model model, ApplicationOptions options) {
+
+        if (model.isComputed() && options != null) {
+            if (cpManager != null) {
+                ProtTestStatus newStatus = new ProtTestStatus(modelSet.toArray(new Model[0]), options);
+                cpManager.setStatus(newStatus);
+            }
+        }
+
+        super.update(o, model, options);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/TreeFacade.java b/src/main/java/es/uvigo/darwin/prottest/facade/TreeFacade.java
new file mode 100755
index 0000000..cec3b29
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/TreeFacade.java
@@ -0,0 +1,96 @@
+/*
+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.prottest.facade;
+
+import es.uvigo.darwin.prottest.consensus.Consensus;
+import java.util.List;
+
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.tree.WeightedTree;
+
+/**
+ * Declaration of services related to phylogenetic tree management.
+ * 
+ * @author Diego Darriba
+ * 
+ * @since 3.0
+ */
+public interface TreeFacade {
+
+    //	**********************************************************
+    //		  TREE SERVICES
+    //**********************************************************
+
+    /**
+     * Gets ASCII representation of a Tree instance.
+     * 
+     * @param tree the tree
+     */
+    public String toASCII(Tree tree);
+
+    /**
+     * Gets branch information of a Tree instance.
+     * 
+     * @param tree the tree
+     */
+    public String branchInfo(Tree tree);
+
+    /**
+     * Gets height information of a Tree instance.
+     * 
+     * @param tree the tree
+     */
+    public String heightInfo(Tree tree);
+
+    /**
+     * Gets newick representation of a Tree instance.
+     * 
+     * @param tree the tree
+     * @param printLengths if branch lengths should be included
+     * @param printInternalLabels if internal labels should be included
+     * @param printCladeSupport if clade support should be included
+     */
+    public String toNewick(Tree tree, boolean printLengths,
+            boolean printInternalLabels, boolean printCladeSupport);
+
+    /**
+     * Create a consensus tree from a list of trees.
+     * 
+     * @param treeCollection the trees and its weights to build consensus
+     * @param threshold the minimum clade support
+     */
+    public Tree createConsensusTree(List<WeightedTree> treeCollection, double threshold);
+
+    /**
+     * Create a weighted consensus tree from an information criterion.
+     * 
+     * @param ic the weighted models with the trees to build consensus
+     * @param threshold the minimum clade support
+     */
+    public Tree createConsensusTree(InformationCriterion ic, double threshold);
+    
+    /**
+     * Create a weighted consensus instance from an information criterion.
+     * 
+     * @param ic the weighted models with the trees to build consensus
+     * @param threshold the minimum clade support
+     */
+    public Consensus createConsensus(InformationCriterion ic, double threshold);
+    
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/TreeFacadeImpl.java b/src/main/java/es/uvigo/darwin/prottest/facade/TreeFacadeImpl.java
new file mode 100755
index 0000000..f555f51
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/TreeFacadeImpl.java
@@ -0,0 +1,93 @@
+/*
+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.prottest.facade;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.consensus.Consensus;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.tree.TreeUtils;
+import es.uvigo.darwin.prottest.tree.WeightedTree;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import java.io.StringWriter;
+
+/**
+ * Generic implementation of the Tree Facade services
+ * 
+ * @author Diego Darriba
+ * 
+ * @since 3.0
+ */
+public class TreeFacadeImpl implements TreeFacade {
+
+    public String toASCII(Tree tree) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        TreeUtils.printASCII(tree, pw);
+        pw.flush();
+        return sw.toString();
+    }
+
+    public String branchInfo(Tree tree) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        TreeUtils.printBranchInfo(tree, pw);
+        pw.flush();
+        return sw.toString();
+    }
+
+    public String heightInfo(Tree tree) {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        TreeUtils.heightInfo(tree, pw);
+        pw.flush();
+        return sw.toString();
+    }
+
+    public String toNewick(Tree tree, boolean printLengths,
+            boolean printInternalLabels, boolean printCladeSupport) {
+        return TreeUtils.toNewick(tree, printLengths, printInternalLabels, printCladeSupport);
+    }
+
+    public Tree createConsensusTree(List<WeightedTree> treeColection,
+            double threshold) {
+
+        if (threshold < 0.5 || threshold > 1.0) {
+            throw new ProtTestInternalException("Invalid threshold value: " + threshold);
+        }
+        Consensus consensus = new Consensus(treeColection, threshold, Consensus.BRANCH_LENGTHS_MEDIAN);
+        Tree cons = consensus.getConsensusTree();
+        return cons;
+    }
+
+    public Tree createConsensusTree(InformationCriterion ic, double threshold) {
+        Consensus consensus = createConsensus(ic, threshold);
+        Tree cons = consensus.getConsensusTree();
+        return cons;
+    }
+    
+    public Consensus createConsensus(InformationCriterion ic, double threshold) {
+        if (threshold < 0.5 || threshold > 1.0) {
+            throw new ProtTestInternalException("Invalid threshold value: " + threshold);
+        }
+        Consensus consensus = new Consensus(ic, threshold);
+        return consensus;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/package.html b/src/main/java/es/uvigo/darwin/prottest/facade/package.html
new file mode 100755
index 0000000..7a3069e
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/package.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains the facade definitions and implementations. This classes contains
+all service definitions and one or more implementations. For instance, the
+main facade, <code>ProtTestFacade</code>, has three concrete implementations,
+one for each execution strategy: sequential execution, threaded execution on
+shared memory, taking advantage of a thread pool, and one more for the
+distributed memory strategy within MPJ Express.
+
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/strategy/DistributionStrategy.java b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/DistributionStrategy.java
new file mode 100755
index 0000000..4c451c1
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/DistributionStrategy.java
@@ -0,0 +1,147 @@
+/*
+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.prottest.facade.strategy;
+
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ObservableModelUpdater;
+import es.uvigo.darwin.prottest.observer.ModelUpdaterObserver;
+import es.uvigo.darwin.prottest.util.checkpoint.CheckPointManager;
+import es.uvigo.darwin.prottest.util.checkpoint.status.ProtTestStatus;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.factory.ProtTestFactory;
+
+/**
+ * This class provides the strategy template for distribute the models amongst processors,
+ * the concrete classes should both distribute models and compute likelihood values.
+ */
+public abstract class DistributionStrategy extends ObservableModelUpdater implements ModelUpdaterObserver {
+ 
+	/** The application options instance. */
+	protected ApplicationOptions options;
+	
+	/** The model set to compute. */
+	protected ModelCollection modelSet;
+	
+	/** The number of models to compute. */
+	protected int numberOfModels;
+	
+	/** The number of models per processor. It will be necessary
+	 * by the root process to do the non-uniform gathering */
+	protected int[] itemsPerProc;
+	
+	/** The array of displacements after the distribution.
+	 * It will be necessary by the root process to do the non-uniform gathering */
+	protected int[] displs;
+	
+	/** The ProtTest factory instance. */
+	protected ProtTestFactory factory = ProtTestFactory.getInstance();
+	
+	/** MPJ Rank of the processor. */
+	protected int mpjMe;
+	
+	/** MPJ Size of the communicator. */
+	protected int mpjSize;
+	
+	/** The absolute start time of the main computation in milliseconds. It should be filled by
+	 * the classes which extends this one 
+	 * @see System#currentTimeMillis()
+	 * */
+	protected long startTime;
+	
+	/** The absolute end time of the main computation in milliseconds. It should be filled by
+	 * the classes which extends this one 
+	 * @see System#currentTimeMillis()
+	 * */
+	protected long endTime;
+	
+	private CheckPointManager cpManager;
+	
+	/**
+	 * Instantiates a new distribution strategy with Checkpointing support.
+	 * 
+	 * @param mpjMe the rank of the current process in MPJ
+	 * @param mpjSize the size of the MPJ communicator
+	 * @param options the application options
+	 * @param cpManager the checkpoint manager, it can be null if checkpointing is not supported
+	 */
+	public DistributionStrategy(int mpjMe, int mpjSize, ApplicationOptions options,
+			CheckPointManager cpManager) {
+		this.options = options;
+		this.mpjMe = mpjMe;
+		this.mpjSize = mpjSize;
+		this.cpManager = cpManager;
+	}
+	
+	/**
+	 * Method called by the root process in order to distribute the models
+	 * amongst processors.
+	 * 
+	 * @param modelSet the models to distribute
+	 * @param comparator implementation of the heuristic algorithm for sort and distribute models
+	 * 
+	 * @return the array of models after computing likelihood
+	 */
+	public abstract Model[] distribute(ModelCollection modelSet, ModelWeightComparator comparator);
+	
+	/**
+	 * Method called by non-root processors in order to request and compute
+	 * their assigned models.
+	 */
+	public abstract void request();
+	
+	/**
+	 * Gets the absolute start time of computing in milliseconds.
+	 * 
+	 * @return the start time in milliseconds
+	 */
+	public long getStartTime() { return startTime; }
+	
+	/**
+	 * Gets the absolute end time of computing in milliseconds.
+	 * 
+	 * @return the end time in milliseconds
+	 */
+	public long getEndTime() { return endTime; }
+	
+	public void update(ObservableModelUpdater o, Model model, ApplicationOptions options) {
+		
+		notifyObservers(model, options);
+		
+	}
+	
+	protected void setCheckpoint(ModelCollection modelSet) {
+		
+		if (mpjMe > 0)
+			throw new ProtTestInternalException("Only root process can set checkpoints");
+
+		if (cpManager != null) {
+			ProtTestStatus newStatus = new ProtTestStatus(modelSet.toArray(new Model[0]), options);
+			cpManager.setStatus(newStatus);
+		}
+	}
+	
+	protected void computationDone() {
+		if (mpjMe > 0)
+			throw new ProtTestInternalException("Only root process can set checkpoints");
+		
+		cpManager.done();
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/strategy/Distributor.java b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/Distributor.java
new file mode 100755
index 0000000..5652bb3
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/Distributor.java
@@ -0,0 +1,203 @@
+/*
+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.prottest.facade.strategy;
+
+import java.util.Collections;
+
+import mpi.MPI;
+import mpi.Request;
+import mpi.Status;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+/**
+ * This class distributes wrok load in an MPJ-Express environment.
+ * Its behavior is inherently coupled to 
+ * ImprovedDynamicDistributionStrategy's, providing the root process with
+ * the possibility of distribute the models and also computing likelihood
+ * values asynchronously.
+ * 
+ * @see ImprovedDynamicDistributionStrategy
+ */
+public class Distributor implements Runnable {
+
+	/** MPJ Tag for requesting a new model. */
+	private static final int TAG_SEND_REQUEST = 1;
+	
+	/** MPJ Tag for sending a new model. */
+	private static final int TAG_SEND_MODEL = 2;
+
+	/** MPJ Rank of the processor. */
+	private int mpjMe;
+	
+	/** MPJ Size of the communicator. */
+	private int mpjSize;
+
+	/** The improved dynamic distribution strategy who calls this instance. */
+	private ImprovedDynamicDistributionStrategy caller;
+	
+	/** The collection of all models to distribute. */
+	private ModelCollection modelCollection;
+	
+	/** The heuristic algorithm to compare models. */
+	private ModelWeightComparator comparator;
+	
+	/** 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;
+
+/**
+ * Gets the array of items per processor.
+ * 
+ * @return the array of items per processor
+ */
+public int[] getItemsPerProc() { return itemsPerProc; }
+	
+	/**
+	 * Gets the array of displacements. The root process needs this attribute
+	 * in order to do the non-uniform gathering.
+	 * 
+	 * @return the array of displacements
+	 */
+	public int[] getDispls() { return displs; }
+	
+	/**
+	 * Instantiates a new distributor. The root process needs this attribute
+	 * in order to do the non-uniform gathering.
+	 * 
+	 * @param caller the ImprovedDynamicDistributionStrategy instance which calls this constructor
+	 * @param modelCollection the models to distribute amongst processors
+	 * @param mpjMe the rank of the current process in MPJ
+	 * @param mpjSize the size of the MPJ communicator
+	 */
+	public Distributor(ImprovedDynamicDistributionStrategy caller,
+			ModelCollection modelCollection, ModelWeightComparator comparator,
+			int mpjMe, int mpjSize) {
+		this.comparator = comparator;
+		this.modelCollection = modelCollection;
+		this.mpjMe = mpjMe;
+		this.mpjSize = mpjSize;
+		this.caller = caller;
+	}
+
+	/* (non-Javadoc)
+	 * @see java.lang.Runnable#run()
+	 */
+	public void run() {
+		
+		distribute(modelCollection, comparator);
+			
+	}
+	
+	/**
+	 * Distributes the whole model collection amongst the processors in
+	 * the communicator. This method should be synchronized with the
+	 * request method in the Improved Dynamic Distribution Strategy.
+	 * 
+	 * @see es.uvigo.darwin.prottest.facade.strategy.ImprovedDynamicDistributionStrategy#request()
+	 * 
+	 * @param modelSet the model collection to distribute amongst processors
+	 * @param comparator implementation of the heuristic algorithm for sort and distribute models
+	 */
+	private void distribute(ModelCollection modelSet, ModelWeightComparator comparator) {
+
+		itemsPerProc = new int[mpjSize];
+		displs = new int[mpjSize];
+		
+		Collections.sort(modelSet, comparator);
+		
+		for (Model model : modelSet) {
+			// 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) {
+				if (caller.rootModel != null) {
+					caller.setCheckpoint(modelSet);
+				}
+				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) {
+					// set checkpoint
+					int index = modelSet.indexOf(computedModel[0]);
+					modelSet.set(index, computedModel[0]);
+					caller.setCheckpoint(modelSet);
+				}
+				// send model
+				Request modelSend = MPI.COMM_WORLD.Isend(modelToSend, 0, 1, MPI.OBJECT, requestStatus.source, TAG_SEND_MODEL);
+				// update structures
+				itemsPerProc[requestStatus.source]++;
+				// wait for send
+				modelSend.Wait();
+			}
+		}
+		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) {
+				// set checkpoint
+				int index = modelSet.indexOf(computedModel[0]);
+				modelSet.set(index, computedModel[0]);
+				caller.setCheckpoint(modelSet);
+			}
+			// 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 new ProtTestInternalException("Thread interrupted");
+			}
+		}
+		caller.rootModel = null;
+		caller.rootModelRequest = false;
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/strategy/DynamicDistributionStrategy.java b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/DynamicDistributionStrategy.java
new file mode 100755
index 0000000..1e31bbe
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/DynamicDistributionStrategy.java
@@ -0,0 +1,162 @@
+/*
+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.prottest.facade.strategy;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import mpi.MPI;
+import mpi.Request;
+import mpi.Status;
+import es.uvigo.darwin.prottest.exe.RunEstimator;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.checkpoint.CheckPointManager;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+/**
+ * This strategy distributes the workload in a dynamic way.
+ */
+public class DynamicDistributionStrategy extends DistributionStrategy {
+
+	/** MPJ Tag for requesting a new model. */
+	private static final int TAG_SEND_REQUEST = 1;
+	
+	/** MPJ Tag for sending a new model. */
+	private static final int TAG_SEND_MODEL = 2;
+	
+	/**
+	 * Instantiates a new dynamic distribution strategy.
+	 * 
+	 * @param mpjMe the rank of the current process in MPJ
+	 * @param mpjSize the size of the MPJ communicator
+	 * @param options the application options
+	 * @param cpManager the checkpoint manager, it can be null if checkpointing is not supported
+	 */
+	public DynamicDistributionStrategy(int mpjMe, int mpjSize, ApplicationOptions options, CheckPointManager cpManager) {
+		super(mpjMe, mpjSize, options, cpManager);
+		if (mpjSize == 1) {
+			throw new ProtTestInternalException("Dynamic Distribution Strategy" +
+					" requires at least 2 processors");
+		}
+		itemsPerProc = new int[mpjSize];
+		displs = new int[mpjSize];
+		modelSet = new SingleModelCollection(options.getAlignment());
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy#distribute(es.uvigo.darwin.prottest.util.collection.ModelCollection)
+	 */
+	public Model[] distribute(ModelCollection arrayListModel, ModelWeightComparator comparator) {
+
+		numberOfModels = arrayListModel.size();
+		Collections.sort(arrayListModel, comparator);
+		for (Model model : arrayListModel) {
+			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) {
+				// set checkpoint
+				int index = arrayListModel.indexOf(computedModel[0]);
+				arrayListModel.set(index, computedModel[0]);
+				setCheckpoint(arrayListModel);
+			}
+			// send model
+			Request modelSend = MPI.COMM_WORLD.Isend(modelToSend, 0, 1, MPI.OBJECT, requestStatus.source, TAG_SEND_MODEL);
+			// update structures
+			itemsPerProc[requestStatus.source]++;
+			// wait for send
+			modelSend.Wait();
+		}
+		itemsPerProc[0] = modelSet.size();
+		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];
+			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) {
+				// set checkpoint
+				int index = arrayListModel.indexOf(computedModel[0]);
+				arrayListModel.set(index, computedModel[0]);
+				setCheckpoint(arrayListModel);
+			}
+			// send null model
+			Request modelSend = MPI.COMM_WORLD.Isend(modelToSend, 0, 1, MPI.OBJECT, requestStatus.source, TAG_SEND_MODEL);
+
+			modelSend.Wait();
+		}
+		
+		computationDone();
+		return arrayListModel.toArray(new Model[0]);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy#request()
+	 */
+	public void request() {
+		
+		startTime = System.currentTimeMillis();
+		
+		List<RunEstimator> runenvList = new ArrayList<RunEstimator>();
+		
+		Model[] lastComputedModel = new Model[1];
+		while (true) {
+			// send request to root
+			Request modelRequest = MPI.COMM_WORLD.Isend(lastComputedModel, 0, 1, MPI.OBJECT, 0, TAG_SEND_REQUEST);
+			// prepare reception
+			Model[] modelToReceive = new Model[1];
+			// wait for request
+			modelRequest.Wait();
+			// receive model
+			Request modelReceive = MPI.COMM_WORLD.Irecv(modelToReceive, 0, 1, MPI.OBJECT, 0, TAG_SEND_MODEL);
+			modelReceive.Wait();
+			Model model = modelToReceive[0];
+			if (model == null)
+				break;
+			else {
+				// compute
+				modelSet.add(model);
+				RunEstimator runenv =
+					factory.createRunEstimator(options, model);
+				runenv.addObserver(this);
+				
+				if(!runenv.optimizeModel())
+					throw new ProtTestInternalException("Optimization error");
+				runenvList.add(runenv);
+				lastComputedModel[0] = runenv.getModel();
+			}
+		}
+		
+		endTime = System.currentTimeMillis();
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/strategy/HybridDistributionStrategy.java b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/HybridDistributionStrategy.java
new file mode 100755
index 0000000..e28cf5d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/HybridDistributionStrategy.java
@@ -0,0 +1,230 @@
+/*
+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.prottest.facade.strategy;
+
+import es.uvigo.darwin.prottest.exe.ParallelModelEstimator;
+
+import mpi.MPI;
+import mpi.Request;
+import es.uvigo.darwin.prottest.exe.RunEstimator;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ObservableModelUpdater;
+import es.uvigo.darwin.prottest.util.checkpoint.CheckPointManager;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+/**
+ * The Class ImprovedDynamicDistributionStrategy.
+ */
+public class HybridDistributionStrategy extends DistributionStrategy {
+
+    /** The Constant TAG_SEND_REQUEST. */
+    private static final int TAG_SEND_REQUEST = 1;
+    /** MPJ Tag for sending a new model. */
+    private static final int TAG_EXIST_MORE_MODELS = 2;
+    /** The Constant TAG_SEND_MODEL. */
+    private static final int TAG_SEND_MODEL = 3;
+    private int maxPEs;
+    /** The number of available PEs. */
+    int availablePEs;
+    /** The root model request. */
+    boolean rootModelRequest;
+    /** The root model. */
+    Model rootModel;
+    private ParallelModelEstimator pme;
+    private Model[] computedModels;
+    private MultipleDistributor distributor;
+
+    /**
+     * Instantiates a new improved dynamic distribution strategy.
+     *
+     * @param mpjMe the rank of the current process in MPJ
+     * @param mpjSize the size of the MPJ communicator
+     * @param options the application options
+     * @param cpManager the checkpoint manager, it can be null if checkpointing is not supported
+     */
+    public HybridDistributionStrategy(int mpjMe, int mpjSize, ApplicationOptions options, CheckPointManager cpManager) {
+        this(mpjMe, mpjSize, options, cpManager, Runtime.getRuntime().availableProcessors());
+    }
+
+    /**
+     * Instantiates a new improved dynamic distribution strategy.
+     *
+     * @param mpjMe the rank of the current process in MPJ
+     * @param mpjSize the size of the MPJ communicator
+     * @param options the application options
+     * @param cpManager the checkpoint manager, it can be null if checkpointing is not supported
+     */
+    public HybridDistributionStrategy(int mpjMe, int mpjSize, ApplicationOptions options, CheckPointManager cpManager, int numberOfThreads) {
+        super(mpjMe, mpjSize, options, cpManager);
+        if (mpjSize == 1) {
+            throw new ProtTestInternalException("Dynamic Distribution Strategy" + " requires at least 2 processors");
+        }
+        itemsPerProc = new int[mpjSize];
+        displs = new int[mpjSize];
+        modelSet = new SingleModelCollection(options.getAlignment());
+        maxPEs = numberOfThreads;
+        availablePEs = maxPEs;
+        pme = new ParallelModelEstimator(maxPEs, options.getAlignment());
+        pme.addObserver(this);
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy#distribute(es.uvigo.darwin.prottest.util.collection.ModelCollection)
+     */
+    public Model[] distribute(ModelCollection arrayListModel, ModelWeightComparator comparator) {
+
+        distributor = new MultipleDistributor(this, arrayListModel, comparator, mpjMe, mpjSize);
+        Thread distributorThread = new Thread(distributor);
+        distributorThread.start();
+        numberOfModels = arrayListModel.size();
+        request();
+
+        computationDone();
+
+        return computedModels;
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy#request()
+     */
+    public void request() {
+
+        startTime = System.currentTimeMillis();
+
+//        List<RunEstimator> runenvList = new ArrayList<RunEstimator>();
+
+        while (true) {
+            // send request to root
+            Model[] modelToReceive = null;
+            Model model = null;
+            if (mpjMe > 0) {
+                int[] sendMessage = {availablePEs};
+                Request modelRequest = MPI.COMM_WORLD.Isend(sendMessage, 0, 1, MPI.INT, 0, 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, TAG_EXIST_MORE_MODELS);
+                notifyRecv.Wait();
+
+                if (notification[0]) {
+                    // receive model
+                    Request modelReceive = MPI.COMM_WORLD.Irecv(modelToReceive, 0, 1, MPI.OBJECT, 0, 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 amongst this class and Distributor, having to define two
+                // public attributes: rootModelRequest and rootModel.
+                rootModelRequest = true;
+                while (rootModelRequest) {
+                    try {
+                        Thread.sleep(200);
+                    } catch (InterruptedException e) {
+                        throw new ProtTestInternalException("Thread interrupted");
+                    }
+                }
+                model = rootModel;
+                if (model == null) {
+                    break;
+                }
+            }
+
+            if (model != null) {
+                availablePEs -= MultipleDistributor.getPEs(model, maxPEs);
+                // compute
+                modelSet.add(model);
+                RunEstimator runenv =
+                        factory.createRunEstimator(options, model, MultipleDistributor.getPEs(model, maxPEs));
+//                runenv.addObserver(this);
+                pme.execute(runenv);
+
+                while (availablePEs <= 0) {
+                    try {
+                        Thread.sleep(200);
+                    } catch (InterruptedException e) {
+                        throw new ProtTestInternalException("Thread interrupted");
+                    }
+                }
+            }
+        }
+
+        endTime = System.currentTimeMillis();
+
+        while (pme.hasMoreTasks()) {
+            try {
+                Thread.sleep(400);
+            } catch (InterruptedException e) {
+                throw new ProtTestInternalException("Thread interrupted");
+            }
+        }
+
+        if (mpjMe > 0) {
+            gather();
+        } else {
+            computedModels = gather();
+        }
+
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.facade.ProtTestFacade#update(es.uvigo.darwin.prottest.observer.Observable, java.lang.Object)
+     */
+    @Override
+    public void update(ObservableModelUpdater o, Model model, ApplicationOptions options) {
+        if (options != null && model.isComputed()) {
+            availablePEs += MultipleDistributor.getPEs(model, maxPEs);
+        }
+        super.update(o, model, options);
+    }
+
+    /**
+     * 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() {
+
+        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(modelSet.toArray(new Model[0]), 0, modelSet.size(), MPI.OBJECT,
+                allModels, 0, itemsPerProc, displs, MPI.OBJECT, 0);
+
+        return allModels;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/strategy/ImprovedDynamicDistributionStrategy.java b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/ImprovedDynamicDistributionStrategy.java
new file mode 100755
index 0000000..2fc7ebc
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/ImprovedDynamicDistributionStrategy.java
@@ -0,0 +1,147 @@
+/*
+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.prottest.facade.strategy;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import mpi.MPI;
+import mpi.Request;
+import es.uvigo.darwin.prottest.exe.RunEstimator;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.checkpoint.CheckPointManager;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+/**
+ * This class improves the dynamic behaviour adding a distributor
+ * thread.
+ */
+public class ImprovedDynamicDistributionStrategy extends DistributionStrategy {
+
+	/** The Constant TAG_SEND_REQUEST. */
+	private static final int TAG_SEND_REQUEST = 1;
+	
+	/** The Constant TAG_SEND_MODEL. */
+	private static final int TAG_SEND_MODEL = 2;
+	
+	/** The root model request. */
+	boolean rootModelRequest;
+	
+	/** The root model. */
+	Model rootModel;
+	
+	/**
+	 * Instantiates a new improved dynamic distribution strategy.
+	 * 
+	 * @param mpjMe the rank of the current process in MPJ
+	 * @param mpjSize the size of the MPJ communicator
+	 * @param options the application options
+	 * @param cpManager the checkpoint manager, it can be null if checkpointing is not supported
+	 */
+	public ImprovedDynamicDistributionStrategy(int mpjMe, int mpjSize, ApplicationOptions options, CheckPointManager cpManager) {
+		super(mpjMe, mpjSize, options, cpManager);
+		if (mpjSize == 1) {
+			throw new ProtTestInternalException("Dynamic Distribution Strategy" +
+					" requires at least 2 processors");
+		}
+		itemsPerProc = new int[mpjSize];
+		displs = new int[mpjSize];
+		modelSet = new SingleModelCollection(options.getAlignment());
+	}
+		
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy#distribute(es.uvigo.darwin.prottest.util.collection.ModelCollection)
+	 */
+	public Model[] distribute(ModelCollection arrayListModel, ModelWeightComparator comparator) {
+
+		Distributor distributor = new Distributor(this, arrayListModel, comparator, mpjMe, mpjSize);
+		Thread distributorThread = new Thread(distributor);
+		distributorThread.start();
+		numberOfModels = arrayListModel.size();
+		request();
+		itemsPerProc = distributor.getItemsPerProc();
+		displs = distributor.getDispls();
+		
+		computationDone();
+		return arrayListModel.toArray(new Model[0]);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy#request()
+	 */
+	public void request() {
+		
+		startTime = System.currentTimeMillis();
+		
+		List<RunEstimator> runenvList = new ArrayList<RunEstimator>();
+		
+		Model[] lastComputedModel = new Model[1];
+		while (true) {
+			// send request to root
+			Model[] modelToReceive = null;
+			Model model = null;
+			if (mpjMe > 0) {
+				Request modelRequest = MPI.COMM_WORLD.Isend(lastComputedModel, 0, 1, MPI.OBJECT, 0, 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, 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 amongst this class and Distributor, having to define two 
+				// public attributes: rootModelRequest and rootModel.
+				rootModelRequest = true;
+				while (rootModelRequest) {
+					try {
+						Thread.sleep(200);
+					} catch (InterruptedException e) {
+						throw new ProtTestInternalException("Thread interrupted");
+					}
+				}
+				model = rootModel;
+			}
+			if (model == null)
+				break;
+			else {
+				// compute
+				modelSet.add(model);
+				RunEstimator runenv =
+					factory.createRunEstimator(options, model);
+				runenv.addObserver(this);
+				
+				if(!runenv.optimizeModel())
+					throw new ProtTestInternalException("Optimization error");
+
+				runenvList.add(runenv);
+				lastComputedModel[0] = runenv.getModel();
+			}
+		}
+		
+		endTime = System.currentTimeMillis();
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/strategy/MultipleDistributor.java b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/MultipleDistributor.java
new file mode 100755
index 0000000..c2d65a1
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/MultipleDistributor.java
@@ -0,0 +1,246 @@
+/*
+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.prottest.facade.strategy;
+
+import java.util.Collections;
+
+import mpi.MPI;
+import mpi.Request;
+import mpi.Status;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+/**
+ * This class depends on MPJ-Express. Its behavior is inherently coupled to 
+ * ImprovedDynamicDistributionStrategy's, providing the root process with
+ * the possibility of distribute the models and also computing likelihood
+ * values asynchronously.
+ * 
+ * @see ImprovedDynamicDistributionStrategy
+ */
+public class MultipleDistributor implements Runnable {
+
+    /** MPJ Tag for requesting a new model. */
+    private static final int TAG_SEND_REQUEST = 1;
+    /** MPJ Tag for sending a new model. */
+    private static final int TAG_EXIST_MORE_MODELS = 2;
+    /** MPJ Tag for sending a new model. */
+    private static final int TAG_SEND_MODEL = 3;
+    /** MPJ Rank of the processor. */
+    private int mpjMe;
+    /** MPJ Size of the communicator. */
+    private int mpjSize;
+    /** The improved dynamic distribution strategy who calls this instance. */
+    private HybridDistributionStrategy caller;
+    /** The collection of all models to distribute. */
+    private ModelCollection modelsToSend;
+    /** The heuristic algorithm to compare models. */
+    private ModelWeightComparator comparator;
+    /** 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;
+
+    //For now, we use a static number of available threads
+    //TODO: Make this dynamically filled for each node
+    private int maxAvailableThreads = 8;
+
+    /**
+     * Gets the array of items per processor.
+     * 
+     * @return the array of items per processor
+     */
+    public int[] getItemsPerProc() {
+        return itemsPerProc;
+    }
+
+    /**
+     * Gets the array of displacements. The root process needs this attribute
+     * in order to do the non-uniform gathering.
+     * 
+     * @return the array of displacements
+     */
+    public int[] getDispls() {
+        return displs;
+    }
+
+    /**
+     * Instantiates a new distributor. The root process needs this attribute
+     * in order to do the non-uniform gathering.
+     * 
+     * @param caller the ImprovedDynamicDistributionStrategy instance which calls this constructor
+     * @param modelCollection the models to distribute amongst processors
+     * @param mpjMe the rank of the current process in MPJ
+     * @param mpjSize the size of the MPJ communicator
+     */
+    public MultipleDistributor(HybridDistributionStrategy caller,
+            ModelCollection modelCollection, ModelWeightComparator comparator,
+            int mpjMe, int mpjSize) {
+        this.comparator = comparator;
+        this.modelsToSend = modelCollection.clone();
+        Collections.sort(this.modelsToSend, comparator);
+        this.mpjMe = mpjMe;
+        this.mpjSize = mpjSize;
+        this.caller = caller;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Runnable#run()
+     */
+    public void run() {
+
+        distribute();
+
+    }
+
+    /**
+     * Distributes the whole model collection amongst the processors in
+     * the communicator. This method should be synchronized with the
+     * request method in the Improved Dynamic Distribution Strategy.
+     * 
+     * @see es.uvigo.darwin.prottest.facade.strategy.ImprovedDynamicDistributionStrategy#request()
+     * 
+     * @param modelSet the model collection to distribute amongst processors
+     * @param comparator implementation of the heuristic algorithm for sort and distribute models
+     */
+    private void distribute() {
+
+        itemsPerProc = new int[mpjSize];
+        Status requestStatus = null;
+        displs = new int[mpjSize];
+        int[] freePEs = new int[1];
+        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);
+                if (rootModel != null) {
+                    caller.rootModel = rootModel;
+                    caller.rootModelRequest = false;
+                    itemsPerProc[mpjMe]++;
+                }
+            } else {
+                // getModel request
+                if (sended) {
+                    modelRequest = MPI.COMM_WORLD.Irecv(freePEs, 0, 1, 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]);
+                    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) {
+                    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) {
+                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, 1, 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();
+
+        }
+        
+    }
+
+    private Model getNextModel(int numPEs) {
+        Model nextModel = null;
+        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.isGamma()) {
+            numberOfThreads = 4;
+        } else if (model.isInv()) {
+            numberOfThreads = 2;
+        } else {
+            numberOfThreads = 1;
+        }
+        return Math.min(maxAvailableThreads, numberOfThreads);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/strategy/StaticDistributionStrategy.java b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/StaticDistributionStrategy.java
new file mode 100755
index 0000000..bfc6891
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/StaticDistributionStrategy.java
@@ -0,0 +1,145 @@
+/*
+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.prottest.facade.strategy;
+
+import mpi.MPI;
+import mpi.Request;
+import es.uvigo.darwin.prottest.exe.RunEstimator;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.ParallelModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+/**
+ * This distribution strategy makes an static distribution of the models amongst the
+ * processors. This mean the model distribution it is completely and heuristically done 
+ * before computing any likelihood value. 
+ */
+public class StaticDistributionStrategy extends DistributionStrategy {
+	
+	/**
+	 * Instantiates a new static distribution strategy.
+	 * 
+	 * @param mpjMe the rank of the current process in MPJ
+	 * @param mpjSize the size of the MPJ communicator
+	 * @param options the application options
+	 */
+	public StaticDistributionStrategy(int mpjMe, int mpjSize, ApplicationOptions options) {
+		super(mpjMe, mpjSize, options, null);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy#distribute(es.uvigo.darwin.prottest.util.collection.ModelCollection)
+	 */
+	public Model[] distribute(ModelCollection arrayListModel, ModelWeightComparator comparator) {
+
+		itemsPerProc = new int[mpjSize];
+		displs = new int [mpjSize];
+		numberOfModels = arrayListModel.size();
+		
+		ParallelModelCollection pmi = new ParallelModelCollection(arrayListModel, mpjSize, comparator);
+		Request[] requests = new Request[mpjSize - 1];
+		for (int procToSend = 1; procToSend < mpjSize; procToSend++) {
+			ModelCollection[] modelsToSend = new SingleModelCollection[1];
+			modelsToSend[0] = pmi.getModelCollection(procToSend);
+			itemsPerProc[procToSend] = modelsToSend[0].size();
+			requests[procToSend - 1] = MPI.COMM_WORLD.Isend(modelsToSend, 0, 1, MPI.OBJECT, procToSend, 2);
+		}
+		modelSet = pmi.getModelCollection(mpjMe);
+		itemsPerProc[0] = modelSet.size();
+		displs[0] = 0;
+		for (int i = 1; i < mpjSize; i++)
+			displs[i] = displs[i-1] + itemsPerProc[i-1];
+
+		Request.Waitall(requests);
+		
+		startTime = System.currentTimeMillis();
+		Model[] models = compute(modelSet);
+		endTime = System.currentTimeMillis();
+		
+		return models;
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy#request()
+	 */
+	public void request() {
+		
+		startTime = System.currentTimeMillis();
+		
+		ModelCollection[] modelsToReceive = new SingleModelCollection[1];
+		Request request = MPI.COMM_WORLD.Irecv(modelsToReceive, 0, 1, MPI.OBJECT, 0, 2);
+		request.Wait();
+		modelSet = modelsToReceive[0];
+		
+		compute(modelSet);
+		
+		endTime = System.currentTimeMillis();
+	}
+	
+	/**
+	 * Computes the likelihood value of the model set.
+	 * 
+	 * @param modelSet the model set to compute
+	 * 
+	 * @return the array of models after computing likelihood
+	 */
+	private Model[] compute(ModelCollection modelSet) {
+		RunEstimator[] runenv = new RunEstimator[modelSet.size()];
+		
+		int current = 0;
+		for (Model model : modelSet) {
+
+			runenv[current] 
+		       = factory.createRunEstimator(options, model);
+			runenv[current].addObserver(this);
+			
+			if(!runenv[current].optimizeModel())
+				throw new ProtTestInternalException("Optimization error");
+
+			current++;
+		}
+
+		return gather();
+	}
+	
+	/**
+	 * 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() {
+		
+		Model[] allModels = new Model[numberOfModels];
+		
+		// gathering optimized models
+		if (mpjSize > 1)
+			MPI.COMM_WORLD.Gatherv(modelSet.toArray(new Model[0]), 0, modelSet.size(), MPI.OBJECT, 
+					allModels, 0, itemsPerProc, displs, MPI.OBJECT, 0);
+		else
+			allModels = modelSet.toArray(new Model[0]);
+		
+		return allModels;
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/strategy/package.html b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/package.html
new file mode 100755
index 0000000..dd78207
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/strategy/package.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains the different strategies for distribution and execution. The MPJ Express facade
+implements an strategy pattern for model distribution among processes. All the classes
+needed by the several strategies are below this package.
+
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/thread/ThreadPoolSynchronizer.java b/src/main/java/es/uvigo/darwin/prottest/facade/thread/ThreadPoolSynchronizer.java
new file mode 100755
index 0000000..a7fad4f
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/thread/ThreadPoolSynchronizer.java
@@ -0,0 +1,104 @@
+/*
+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.prottest.facade.thread;
+
+import java.util.Hashtable;
+
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+/**
+ * Synchronization of all threads in a thread pool. This class
+ * maps every thread to an internal unique thread identifier, which
+ * can be used to manage temporary files. This manager is a singleton
+ * class.
+ * 
+ * @author Diego Darriba
+ * 
+ * @since 3.0
+ */
+public class ThreadPoolSynchronizer {
+
+    /** Internal mapping of threads ids with sequential identifiers */
+    private Hashtable<Long, Integer> threadIds;
+    /** The value of the next thread in the pool */
+    private int nextValue;
+    /** The size of the thread pool */
+    private int poolSize;
+    /** The unique instance of the class */
+    private static ThreadPoolSynchronizer instance;
+
+    /** 
+     * Instantiates the synchronizer
+     * 
+     * @param poolSize the size of the thread pool
+     */
+    private ThreadPoolSynchronizer(int poolSize) {
+        this.poolSize = poolSize;
+        threadIds = new Hashtable<Long, Integer>(poolSize);
+        nextValue = 0;
+    }
+
+    /**
+     * Gets the internal identifier of a thread
+     * 
+     * @param thread the thread
+     * 
+     * @return the unique internal identifier
+     */
+    public synchronized int getThreadId(Thread thread) {
+        long threadNumber = thread.getId();
+        Integer value = threadIds.get(threadNumber);
+
+        if (value == null) {
+            if (nextValue >= poolSize) {
+                throw new ProtTestInternalException("Thread out of sync on ThreadPool");
+            }
+            // next value
+            value = nextValue++;
+            threadIds.put(threadNumber, value);
+        }
+
+        return value;
+    }
+
+    /** 
+     * Synchronizes a new manager. This method instantiates the unique
+     * instance of the class.
+     * 
+     * @param poolSize the size of the thread pool
+     */
+    public static void synchronize(int poolSize) {
+        instance = new ThreadPoolSynchronizer(poolSize);
+    }
+
+    /**
+     * Gets the unique instance of the class. Before the first call of
+     * this method, the class thread pool shoud be synchronized.
+     * 
+     * @return the unique instance
+     * 
+     * @throws ProtTestInternalException Signals that the thread pool is not synchronized.
+     */
+    public synchronized static ThreadPoolSynchronizer getInstance() 
+    throws ProtTestInternalException {
+        if (instance == null) {
+            throw new ProtTestInternalException("ThreadPool out of sync");
+        }
+        return instance;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/thread/package.html b/src/main/java/es/uvigo/darwin/prottest/facade/thread/package.html
new file mode 100755
index 0000000..d5f305d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/thread/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains the threaded execution utils.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/util/ProtTestParameterVO.java b/src/main/java/es/uvigo/darwin/prottest/facade/util/ProtTestParameterVO.java
new file mode 100755
index 0000000..1f1bcc4
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/util/ProtTestParameterVO.java
@@ -0,0 +1,144 @@
+/*
+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.prottest.facade.util;
+
+import java.util.Collection;
+import pal.alignment.Alignment;
+
+/**
+ * A value object containing all parameters of a ProtTest-HPC execution.
+ * 
+ * @author Diego Darriba López
+ * 
+ * @since 3.0
+ */
+public class ProtTestParameterVO {
+
+    /** The alignment */
+    private Alignment alignment;
+    /** The path of the file which contains the alignment */
+    private String alignmentFilePath;
+    /** The path of the file which contains the starting topology, if exists */
+    private String treeFilePath;
+    /** The matrices of the models to optimize. */
+    private Collection<String> matrices;
+    /** The distributions of the models to optimize. */
+    private Collection<String> distributions;
+    /** The number of transition categories. It is only useful if the distribution is gamma */
+    public int ncat;
+    /** Boolean value to consider or not the empirical amino-acid frequencies. */
+    private boolean plusF;
+    /** The starting topology strategy mode */
+    private int strategyMode;
+
+    /** 
+     * Gets the path of the alignment file.
+     * 
+     * @return the path of the alignment file
+     */
+    public String getAlignmentFilePath() {
+        return alignmentFilePath;
+    }
+
+    /**
+     * Gets the alignment.
+     * 
+     * @return the alignment
+     */
+    public Alignment getAlignment() {
+        return alignment;
+    }
+
+    /**
+     * Gets the path of the starting user topology file, if it exists.
+     *  
+     * @return the path of the starting user topology file
+     */
+    public String getTreeFilePath() {
+        return treeFilePath;
+    }
+
+    /**
+     * Gets the set of substitution matrix names.
+     * 
+     * @return a collection of the substitution matrix names
+     */
+    public Collection<String> getMatrices() {
+        return matrices;
+    }
+
+    /**
+     * Gets the set of distributions in consideration.
+     * 
+     * @return a collection of the distribution manes.
+     */
+    public Collection<String> getDistributions() {
+        return distributions;
+    }
+
+    /**
+     * Gets the number of rate categories, if the distribution +G is considered.
+     * 
+     * @return the number of rate categories
+     */
+    public int getNcat() {
+        return ncat;
+    }
+
+    /**
+     * Gets the state of the empirical frequencies consideration.
+     * 
+     * @return true, if empirical frequencies are considered
+     */
+    public boolean isPlusF() {
+        return plusF;
+    }
+
+    /**
+     * Gets the starting topology strategy mode.
+     * @return the starting topology strategy mode
+     */
+    public int getStrategyMode() {
+        return strategyMode;
+    }
+
+    /**
+     * Instantiates a new ProtTestParameterVO.
+     * 
+     * @param alignmentFilePath the path of the file which contains the alignment
+     * @param alignment the alignment
+     * @param treeFilePath the path of the file which contains the starting topology, if exists
+     * @param matrices the matrices of the models to optimize
+     * @param distributions the distributions of the models to optimize
+     * @param plusF boolean value to consider or not the empirical amino-acid frequencies
+     * @param ncat the number of transition categories. It is only useful if the distribution is gamma
+     * @param strategyMode the starting topology strategy mode
+     */
+    public ProtTestParameterVO(String alignmentFilePath, Alignment alignment, String treeFilePath,
+            Collection<String> matrices, Collection<String> distributions, boolean plusF,
+            int ncat, int strategyMode) {
+        this.alignmentFilePath = alignmentFilePath;
+        this.alignment = alignment;
+        this.treeFilePath = treeFilePath;
+        this.matrices = matrices;
+        this.distributions = distributions;
+        this.plusF = plusF;
+        this.ncat = ncat;
+        this.strategyMode = strategyMode;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/util/SelectionChunk.java b/src/main/java/es/uvigo/darwin/prottest/facade/util/SelectionChunk.java
new file mode 100755
index 0000000..a96229f
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/util/SelectionChunk.java
@@ -0,0 +1,210 @@
+/*
+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.prottest.facade.util;
+
+import java.util.Collection;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.selection.model.SelectionModel;
+
+/**
+ * A value object to calculate information criteria. It works as
+ * a wrapper for the information criteria class.
+ * 
+ * @author Diego Darriba
+ * 
+ * @since 3.0
+ */
+public class SelectionChunk {
+
+    /**
+     * Akaike Information Criteiron constant.
+     */
+    public static final int AIC = 1;
+    /**
+     * Bayesian Information Criteiron constant.
+     */
+    public static final int BIC = 2;
+    /**
+     * Corrected Akaike Information Criteiron constant.
+     */
+    public static final int AICC = 3;
+    /**
+     * Decision Theory Criteiron constant.
+     */
+    public static final int DT = 4;
+    /**
+     * log Likelihood Criterion constant.
+     */
+    public static final int LNL = 5;
+    /**
+     * The inner information criterion
+     */
+    private InformationCriterion informationCriterion;
+
+    /**
+     * Gets the inner information criterion
+     * 
+     * @return the information criterion
+     */
+    public InformationCriterion getInformationCriterion() {
+        return informationCriterion;
+    }
+
+    /**
+     * Instantiates a new Selection Chunk.
+     * 
+     * @param informationCriterion the inner information criterion
+     */
+    public SelectionChunk(InformationCriterion informationCriterion) {
+        this.informationCriterion = informationCriterion;
+    }
+
+    public boolean existGammaModels() {
+        return informationCriterion.isExistGammaModels();
+    }
+
+    public boolean existInvModels() {
+        return informationCriterion.isExistInvModels();
+    }
+
+    public boolean existGammaInvModels() {
+        return informationCriterion.isExistGammaInvModels();
+    }
+
+    public boolean existFModels() {
+        return informationCriterion.isExistFModels();
+    }
+    
+    /**
+     * Gets the criterion value of a specific substitution model.
+     * 
+     * @param model the substitution model
+     * 
+     * @return the criterion value
+     */
+    public double getValue(Model model) {
+        return informationCriterion.get(model).getValue();
+    }
+
+    /**
+     * Gets the incremental criterion value of a specific substitution model.
+     * 
+     * @param model the substitution model
+     * 
+     * @return the incremental criterion value
+     */
+    public double getDeltaValue(Model model) {
+        return informationCriterion.get(model).getDeltaValue();
+    }
+
+    /**
+     * Gets the relative weight of a specific substitution model.
+     * 
+     * @param model the substitution model
+     * 
+     * @return the relative weight
+     */
+    public double getWeightValue(Model model) {
+        return informationCriterion.get(model).getWeightValue();
+    }
+
+    /**
+     * Gets the overall importance of the alpha parameter.
+     * 
+     * @return the overall importance of the +G models.
+     */
+    public double getOverallAlpha() {
+        return informationCriterion.getOverallAlpha();
+    }
+
+    /**
+     * Gets the overall importance of the alpha parameter on +I+G models..
+     * 
+     * @return the overall importance.
+     */
+    public double getOverallAlphaInv() {
+        return informationCriterion.getOverallAlphaInv();
+    }
+
+    /**
+     * Gets the overall importance of the proportion of invariant sites
+     * parameter.
+     * 
+     * @return the overall importance of the +I models.
+     */
+    public double getOverallInv() {
+        return informationCriterion.getOverallInv();
+    }
+
+    /**
+     * Gets the overall importance of the proportion of invariant sites 
+     * parameter on +I+G models.
+     * 
+     * @return the overall importance
+     */
+    public double getOverallInvAlpha() {
+        return informationCriterion.getOverallInvAlpha();
+    }
+
+    /**
+     * Gets the relative importance of +G parameter.
+     * 
+     * @return the relative importance
+     */
+    public double getAlphaImportance() {
+        return informationCriterion.getAlphaImportance();
+    }
+
+    /**
+     * Gets the relative importance of +I parameter.
+     * 
+     * @return the relative importance
+     */
+    public double getInvImportance() {
+        return informationCriterion.getInvImportance();
+    }
+
+    /**
+     * Gets the relative importance of +I+G parameter.
+     * 
+     * @return the relative importance
+     */
+    public double getAlphaInvImportance() {
+        return informationCriterion.getAlphaInvImportance();
+    }
+
+    /**
+     * Gets the relative importance of empirical frequencies parameter.
+     * 
+     * @return the relative importance
+     */
+    public double getFImportance() {
+        return informationCriterion.getFImportance();
+    }
+
+    /**
+     * Gets the models which belong to the confidence interval.
+     * 
+     * @return the models in the confidence interval.
+     */
+    public Collection<SelectionModel> getConfidenceModels() {
+        return informationCriterion.getConfidenceModels();
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/facade/util/package.html b/src/main/java/es/uvigo/darwin/prottest/facade/util/package.html
new file mode 100755
index 0000000..2d7414e
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/facade/util/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains some utilies for the facades.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/global/AminoAcidApplicationGlobals.java b/src/main/java/es/uvigo/darwin/prottest/global/AminoAcidApplicationGlobals.java
new file mode 100755
index 0000000..c81806e
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/global/AminoAcidApplicationGlobals.java
@@ -0,0 +1,63 @@
+/*
+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.prottest.global;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * The global application settings and parameter names for
+ * amino-acid alignment sequences.
+ */
+public class AminoAcidApplicationGlobals extends ApplicationGlobals {
+
+	/** The Amino-Acid supported matrices. */
+	public static String[] ALL_MATRICES	= { 
+		 "JTT",
+		 "LG",
+		 "DCMut",
+		 "MtREV",
+		 "MtMam",
+		 "MtArt",
+		 "Dayhoff",
+		 "WAG",
+		 "RtREV",
+		 "CpREV",
+		 "Blosum62",
+		 "VT",
+		 "HIVb",
+		 "HIVw",
+                 "FLU"
+	};
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.global.ApplicationGlobals#getSupportedMatrices()
+	 */
+    @Override
+	public List<String> getSupportedMatrices() {
+		return Arrays.asList(ALL_MATRICES);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.global.ApplicationGlobals#getModelName(java.lang.String, int)
+	 */
+    @Override
+	public String getModelName(String matrix, int frequenciesDistribution) {
+		return matrix;
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/global/ApplicationGlobals.java b/src/main/java/es/uvigo/darwin/prottest/global/ApplicationGlobals.java
new file mode 100755
index 0000000..7e0d5ec
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/global/ApplicationGlobals.java
@@ -0,0 +1,70 @@
+/*
+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.prottest.global;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.Properties;
+
+import es.uvigo.darwin.prottest.ProtTest;
+
+/**
+ * The global application settings and parameter names.
+ */
+public abstract class ApplicationGlobals implements ProtTestConstants {
+
+    /** The application APPLICATION_PROPERTIES. */
+    public static final Properties APPLICATION_PROPERTIES;
+    public static final String JAR_PATH = ProtTest.class.getProtectionDomain().getCodeSource().getLocation().getFile()
+    		.replace("%20", " ");
+    public static final String PATH = JAR_PATH.replaceFirst(new File(JAR_PATH).getName(),"");
+    
+    static {
+        APPLICATION_PROPERTIES = new Properties();
+        try {
+            FileInputStream prop = new FileInputStream(PATH + "prottest.properties");
+            APPLICATION_PROPERTIES.load(prop);
+        } catch (IOException e) {
+            System.err.println("Properties file (prottest.properties) cannot be resolved");
+            System.exit(EXIT_NO_PROPERTIES);
+        }
+
+    }
+    public static final String DEFAULT_SNAPSHOT_DIR = "snapshot/";
+
+    /**
+     * Gets the supported matrices.
+     * 
+     * @return the supported matrices
+     */
+    public abstract List<String> getSupportedMatrices();
+
+    /**
+     * Gets the model name from matrix and distribution names. This
+     * method is useful specially when a custom matrix is set, so
+     * his internal name is not representative for the user.
+     * 
+     * @param matrix the matrix name
+     * @param frequenciesDistribution the frequencies distribution name
+     * 
+     * @return the model name
+     */
+    public abstract String getModelName(String matrix, int frequenciesDistribution);
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/global/ProtTestConsoleParameters.java b/src/main/java/es/uvigo/darwin/prottest/global/ProtTestConsoleParameters.java
new file mode 100755
index 0000000..16c2024
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/global/ProtTestConsoleParameters.java
@@ -0,0 +1,74 @@
+/*
+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.prottest.global;
+
+/**
+ * Console execution parameters
+ * 
+ * @author diego
+ */
+public interface ProtTestConsoleParameters {
+
+    /** Data type parameter token. */
+    public static final String PARAM_DATA_TYPE = "d";		// data type
+    /** Nucleotide data type parameter value. */
+    public static final String DATA_TYPE_NUCLEOTIDE = "nt";
+    /** Amino-acid data type parameter value. */
+    public static final String DATA_TYPE_AMINOACID = "aa";	// default
+    /** Number of threads parameter token. */
+    public static final String PARAM_NUM_THREADS = "threads";
+    /** Alignment file parameter token. */
+    public static final String PARAM_ALIGNMENT_FILE = "i";	// alignment file (required)
+    /** Output file parameter token. */
+    public static final String PARAM_OUTPUT_FILE = "o";		// output file
+    /** Tree file parameter token. */
+    public static final String PARAM_TREE_FILE = "t";		// tree file
+    /** Sort by parameter token. */
+    public static final String PARAM_DO_AIC = "AIC";            // sort models by AIC
+    public static final String PARAM_DO_BIC = "BIC";            // sort models by BIC
+    public static final String PARAM_DO_AICC = "AICC";          // sort models by AICc
+    public static final String PARAM_DO_DT = "DT";              // sort models by DT
+    /** Display all framework comparison parameter token. */
+    public static final String PARAM_ALL_FRAMEWORK_COMPARISON = "all";	// display 7-framework comparison table
+    /** Optimization strategy selection parameter token. */
+    public static final String PARAM_TREE_SEARCH_OP = "s";	// tree search operation
+    /** Optimization strategy selection parameter token. */
+    public static final String PARAM_OPTIMIZATION_STRATEGY = "S";	// optimization strategy
+    /** Display Newick tree parameter token. */
+    public static final String PARAM_DISPLAY_NEWICK_TREE = "t1";	// display newick tree
+    /** Display ASCII tree parameter token. */
+    public static final String PARAM_DISPLAY_ASCII_TREE = "t2";		// display ASCII tree
+    /** Display Consensus tree parameter token. */
+    public static final String PARAM_DISPLAY_CONSENSUS_TREE = "tc";	// display Consensus tree
+    /** Include models with observed frequencies parameter token. */
+    public static final String PARAM_PLUSF = "F";
+    /** Include models with a proportion invariable sites parameter token. */
+    public static final String PARAM_PLUSI = "I";
+    /** Include models with rate variation among sites and number of categories parameter token. */
+    public static final String PARAM_PLUSG = "G";
+    /** Include models with a proportion of invariable sites and rate variation parameter token. */
+    public static final String PARAM_PLUSIG = "IG";
+    /** User defined number of categories parameter token. */
+    public static final String PARAM_NCAT = "ncat";
+    /** Include models with all distributions (like -I -G). */
+    public static final String PARAM_ALL_DISTRIBUTIONS = "all-distributions";
+    /** Enable or Disable output logging files. */
+    public static final String PARAM_LOGGING = "log";
+    /** Verbose mode parameter token. */
+    public static final String PARAM_VERBOSE = "verbose";
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/global/ProtTestConstants.java b/src/main/java/es/uvigo/darwin/prottest/global/ProtTestConstants.java
new file mode 100755
index 0000000..f331539
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/global/ProtTestConstants.java
@@ -0,0 +1,111 @@
+/*
+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.prottest.global;
+
+/**
+ * The global constants of ProtTest-HPC
+ *
+ * @author diego
+ */
+public interface ProtTestConstants {
+
+    /** The exit status for signals caused by the non existence of properties file. */
+    static final int EXIT_NO_PROPERTIES = 101;
+    // third-party applications
+    /** The Constant ANALYZER_PHYML. It is used to check the analyzer in the properties file */
+    static final String ANALYZER_PHYML = "phyml";
+    /** The Constant ANALYZER_RAXML. It is used to check the analyzer in the properties file */
+    static final String ANALYZER_RAXML = "raxml";
+    /** The number of states for amino-acids. */
+    static final int AMINOACID_NUM_STATES = 20;
+    
+    /** The empirical frequencies parameter. */
+    static final String PARAMETER_F = "+F";
+    /** The invariant sites parameter. */
+    static final String PARAMETER_I = "+I";
+    /** The gamma distribution parameter. */
+    static final String PARAMETER_G = "+G";
+    /** The invariant sites and gamma distribution parameter. */
+    static final String PARAMETER_IG = "+I+G";
+
+    // tree search operation
+    /** NNI moves */
+    static final String TREE_SEARCH_NNI = "nni";
+    /** SPR moves */
+    static final String TREE_SEARCH_SPR = "spr";
+    /** Best of NNI and SPR moves */
+    static final String TREE_SEARCH_BEST = "best";
+
+    /** Fixed BIONJ topology for every model. */
+    static final int OPTIMIZE_FIXED_BIONJ = 0;
+    /** BIONJ topology for each model. */
+    static final int OPTIMIZE_BIONJ = 1;
+    /** Maximum likelighood topology for each model. */
+    static final int OPTIMIZE_ML = 2;
+    /** User defined topology. */
+    static final int OPTIMIZE_USER = 3;
+    /** Set of descriptions of the optimization strategies. */
+    public static final String[] OPTIMIZE_NAMES = {
+        "Fixed BIONJ JTT",
+        "BIONJ Tree",
+        "Maximum Likelihood tree",
+        "User defined topology"
+    };
+    /** Set of values of the optimization strategies. */
+    static final int[] OPTIMIZE_VALUES = {
+        OPTIMIZE_FIXED_BIONJ,
+        OPTIMIZE_BIONJ,
+        OPTIMIZE_ML,
+        OPTIMIZE_USER
+    };
+    static final String[] CRITERION_NAMES = {
+        "AKAIKE INFORMATION CRITERION",
+        "BAYESIAN INFORMATION CRITERION",
+        "CORRECTED AKAIKE INFORMATION CRITERION",
+        "DECISION THEORY CRITERION",
+        "LOG-LIKELIHOOD"
+    };
+    // default settings
+    /** The default setting of property "Display Newick tree". */
+    static final boolean DEFAULT_DISPLAY_NEWICK_TREE = false;
+    /** The default setting of property "Number of threads". */
+    static final int DEFAULT_THREADS = 1;
+    /** The default setting of property "Display ASCII tree". */
+    static final boolean DEFAULT_DISPLAY_ASCII_TREE = false;
+    /** The default setting of property "Display Consensus tree". */
+    static final boolean DEFAULT_DISPLAY_CONSENSUS_TREE = false;
+    /** The default setting of property "Debug" (Verbose mode). */
+    static final boolean DEFAULT_DEBUG = false;
+    /** The default setting of property "Display a 7-framework comparison". */
+    static final boolean DEFAULT_COMPARE_ALL = false;
+    /** The default setting of property "Compute all matrices". */
+    static final boolean DEFAULT_MATRICES = false;
+    /** The default setting of property "Compute all distributions". */
+    static final boolean DEFAULT_DISTRIBUTIONS = false;
+    /** The default setting of property "Number of categories". */
+    static final int DEFAULT_NCAT = 4;
+    /** The default setting of property "Optimization strategy mode". */
+    static final int DEFAULT_STRATEGY_MODE = OPTIMIZE_FIXED_BIONJ;
+    
+    // Tree properties
+    /** Tree property for write branch length averaging */
+    static final String PROP_BRANCH_LENGTH_AVERAGING = "branch_length_averaging";
+
+    static final int IMPORTANCE_PRECISSION = 3;
+    static final int CRITERION_PRECISSION = 5;
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/global/RaxmlAminoAcidApplicationGlobals.java b/src/main/java/es/uvigo/darwin/prottest/global/RaxmlAminoAcidApplicationGlobals.java
new file mode 100755
index 0000000..d6afe81
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/global/RaxmlAminoAcidApplicationGlobals.java
@@ -0,0 +1,52 @@
+/*
+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.prottest.global;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * The global application settings and parameter names for
+ * amino-acid alignment sequences using RAxML.
+ */
+public class RaxmlAminoAcidApplicationGlobals extends
+		AminoAcidApplicationGlobals {
+
+	/** The Amino-Acid substitution matrices supported by RAxML. */
+	public static final String[] RAXML_MATRICES	= {
+		 "JTT",
+		 "DCMut",
+		 "MtREV",
+		 "MtMam",
+		 "Dayhoff",
+		 "WAG",
+		 "RtREV",
+		 "CpREV",
+		 "Blosum62",
+		 "VT",
+                 "FLU"
+	};
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.global.ApplicationGlobals#getSupportedMatrices()
+	 */
+    @Override
+	public List<String> getSupportedMatrices() {
+		return Arrays.asList(RAXML_MATRICES);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/global/options/ApplicationOptions.java b/src/main/java/es/uvigo/darwin/prottest/global/options/ApplicationOptions.java
new file mode 100755
index 0000000..b784f76
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/global/options/ApplicationOptions.java
@@ -0,0 +1,841 @@
+/*
+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.prottest.global.options;
+
+import static es.uvigo.darwin.prottest.global.AminoAcidApplicationGlobals.*;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import pal.alignment.Alignment;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.ProtTestAlignment;
+import es.uvigo.darwin.prottest.util.argumentparser.ProtTestArgumentParser;
+import es.uvigo.darwin.prottest.util.exception.AlignmentParseException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.exception.TreeFormatException;
+import es.uvigo.darwin.prottest.util.factory.ProtTestFactory;
+import es.uvigo.darwin.prottest.util.fileio.AlignmentReader;
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.logging.Level;
+import static es.uvigo.darwin.prottest.util.logging.ProtTestLogger.*;
+
+/**
+ * The ProtTest application options models the common global options for the
+ * application execution. It is a singleton class which gathers all
+ * necessary options to run.
+ */
+public class ApplicationOptions {
+
+    /** Verbose mode on/off. */
+    protected boolean debug = DEFAULT_DEBUG;
+    /** The sample size. It is only useful if the sample size mode is custom */
+    protected double sampleSize = 0.0;
+    /** The alignment filename. */
+    protected String align_file = null;
+    /** The tree filename. */
+    protected String tree_file = null;
+    /** Logging Enabled/Disabled **/
+    protected boolean logEnabled = true;
+    /** The log filename. */
+    protected String log_file = null;
+    /** The alignment, according to the alignment input file. */
+    protected Alignment alignment;
+    /** The tree, according to the tree filename. */
+    protected Tree tree;
+    /** The number of categories. It is only useful if the distribution is gamma */
+    public int ncat = 4;
+    /** The optimization strategy mode. */
+    public int strategyMode = DEFAULT_STRATEGY_MODE;
+    /** The matrices of the models to optimize. */
+    private List<String> matrices = new ArrayList<String>();	//{"JTT", "MtREV", "Dayhoff", "WAG"};
+    /** The distributions of the models to optimize. */
+    private List<Integer> distributions = new ArrayList<Integer>();	//{0,1,2,3};
+    /** Hash table with the relationship between distribution name and distribution internal parameter. */
+    private HashMap<String, Integer> distributionsHash;
+    /** Boolean value to consider or not different kind of amino-acid frequencies. */
+    private boolean plusF = false;
+    // display options
+    /** Display Newick tree on results. */
+    private boolean displayNewickTree = DEFAULT_DISPLAY_NEWICK_TREE;
+    /** Display ASCII tree on results. */
+    private boolean displayASCIITree = DEFAULT_DISPLAY_ASCII_TREE;
+    /** Display Consensus tree on results. */
+    private boolean displayConsensusTree = DEFAULT_DISPLAY_CONSENSUS_TREE;
+    /** Consensus threshold **/
+    private double consensusThreshold;
+    /** Display a 7-framework comparison. */
+    private boolean compareAll = DEFAULT_COMPARE_ALL;
+    /** Write a log file. */
+    public boolean writeLog = true;
+    /** Criterion to sort the models. */
+    private boolean doAIC,doBIC,doAICc,doDT;
+    /** Tree search operation */
+    private String treeSearchOperation = TREE_SEARCH_NNI;
+
+    /**
+     * Sets the number of categories.
+     * 
+     * @param ncat the new number of categories
+     */
+    public void setNumberOfCategories(int ncat) {
+        this.ncat = ncat;
+    }
+
+    /**
+     * Gets the value of plusF attribute.
+     * 
+     * @return the plusF value
+     */
+    public boolean isPlusF() {
+        return plusF;
+    }
+
+    /**
+     * Sets the empirical amino-acid frequencies usage.
+     * 
+     * @param plusF the new value for consider empirical frequencies
+     */
+    public void setPlusF(boolean plusF) {
+        this.plusF = plusF;
+    }
+
+    /**
+     * Checks if is required to display newick tree.
+     * 
+     * @return true, if is required to display newick tree
+     */
+    public boolean isDisplayNewickTree() {
+        return displayNewickTree;
+    }
+
+    /**
+     * Checks if is required to display ascii tree.
+     * 
+     * @return true, if is required to display ascii tree
+     */
+    public boolean isDisplayASCIITree() {
+        return displayASCIITree;
+    }
+
+    /**
+     * Checks whether PhyML logging is enabled
+     * 
+     * @return true, if PhyML logging is enabled
+     */
+    public boolean isLogEnabled() {
+    	return logEnabled;
+    }
+    
+    /**
+     * Checks if is required to display consensus tree.
+     * 
+     * @return true, if is required to display consensus tree
+     */
+    public boolean isDisplayConsensusTree() {
+        return displayConsensusTree;
+    }
+
+    /**
+     * Gets the threshold to create consensus tree.
+     * 
+     * @return the threshold
+     */
+    public double getConsensusThreshold() {
+        return consensusThreshold;
+    }
+
+    /**
+     * Check if should compute the AIC criterion
+     * 
+     * @return true, if AIC should be computed
+     */
+    public boolean isAIC() {
+        return doAIC;
+    }
+    
+    /**
+     * Check if should compute the BIC criterion
+     * 
+     * @return true, if BIC should be computed
+     */
+    public boolean isBIC() {
+        return doBIC;
+    }
+    
+    /**
+     * Check if should compute the AICc criterion
+     * 
+     * @return true, if AICc should be computed
+     */
+    public boolean isAICc() {
+        return doAICc;
+    }
+    
+    /**
+     * Check if should compute the DT criterion
+     * 
+     * @return true, if DT should be computed
+     */
+    public boolean isDT() {
+        return doDT;
+    }
+    public String getTreeSearchOperation() {
+		return treeSearchOperation;
+	}
+
+	public void setTreeSearchOperation(String treeSearchOperation) {
+		this.treeSearchOperation = treeSearchOperation;
+	}
+
+	/**
+     * Sets the alignment filename without checking
+     * 
+     * @param alignFile the alignment filename
+     */
+    public void setAlignmentFilename(String alignFile) {
+        this.align_file = alignFile;
+    }
+
+    /**
+     * Sets the alignment file
+     * 
+     * @param alignFile the alignment filename
+     * 
+     * @return true, if successful
+     * 
+     * @throws AlignmentParseException Signals that the alignment filename is not correct.
+     * @throws IOException Signals that an I/O exception has occurred.
+     */
+    public boolean setAlignment(String alignFile)
+            throws AlignmentParseException,
+            IOException {
+
+        this.align_file = alignFile;
+
+        StringWriter sw = new StringWriter();
+        setAlignment(AlignmentReader.readAlignment(new PrintWriter(sw), alignFile, debug));
+        sw.flush();
+        println(sw.toString());
+
+        return alignFile != null;
+    }
+
+    /**
+     * Gets the alignment.
+     * 
+     * @return the alignment
+     */
+    public Alignment getAlignment() {
+        return alignment;
+    }
+
+    /**
+     * Gets the tree.
+     * 
+     * @return the tree
+     */
+    public Tree getTree() {
+        return tree;
+    }
+
+    /**
+     * Sets the alignment.
+     * 
+     * @param alignment the new alignment
+     */
+    public void setAlignment(Alignment alignment) {
+        this.alignment = alignment;
+    }
+
+    /**
+     * Sets the tree.
+     * 
+     * @param tree the new tree
+     */
+    public synchronized void setTree(Tree tree) {
+        this.tree = tree;
+    }
+
+    /**
+     * Checks if is debug (verbose mode).
+     * 
+     * @return true, if is debug
+     */
+    public boolean isDebug() {
+        return debug;
+    }
+
+    /**
+     * Sets the debug mode value.
+     * 
+     * @param debug the new debug mode value
+     */
+    public void setDebug(boolean debug) {
+        this.debug = debug;
+    }
+
+    /**
+     * Checks if a 7-framework comparison should be displayed.
+     * 
+     * @return true, if a 7-framework comparison should be displayed
+     */
+    public boolean isAll() {
+        return compareAll;
+    }
+
+    /**
+     * Sets the 7-framework comparison display value.
+     * 
+     * @param all the new 7-framework comparison display value
+     */
+    public void setAll(boolean all) {
+        this.compareAll = all;
+    }
+
+    /**
+     * Gets the tree filename.
+     * 
+     * @return the tree filename
+     */
+    public String getTreeFile() {
+        return tree_file;
+    }
+
+    /**
+     * Sets the tree filename.
+     * 
+     * @param treeFile the new tree filename
+     * 
+     * @throws TreeFormatException Signals there was an error parsing the tree file
+     */
+    public void setTreeFile(String treeFile)
+            throws TreeFormatException, FileNotFoundException, IOException {
+        if (treeFile != null) {
+            this.tree_file = treeFile;
+
+            StringWriter sw = new StringWriter();
+            setTree(AlignmentReader.readTree(new PrintWriter(sw), treeFile, debug));
+            sw.flush();
+            println(sw.toString());
+        }
+    }
+
+    /**
+     * Gets the number of model matrices.
+     * 
+     * @return the number of model matrices
+     */
+    public int getNumberOfMatrices() {
+        return matrices.size();
+    }
+
+    /**
+     * Gets the model matrices.
+     * 
+     * @return the model matrices
+     */
+    public List<String> getMatrices() {
+        List<String> matricesClone = new ArrayList<String>(matrices);
+        return matricesClone;
+    }
+
+    /**
+     * Sets the model matrices.
+     * 
+     * @param newMatrices the new model matrices
+     */
+    public void setMatrices(List<String> newMatrices) {
+        matrices = newMatrices;
+    }
+
+    /**
+     * Gets the matrix at a certain position.
+     * 
+     * @param pos the position of the matrix
+     * 
+     * @return the matrix at the required position
+     */
+    public String getMatrixAt(int pos) {
+        return matrices.get(pos);
+    }
+
+    /**
+     * Check if one matrix exists in the model matrices set of the application.
+     * 
+     * @param matrix the matrix to check out
+     * 
+     * @return true, if the set of matrices contains the model matrix
+     */
+    public boolean existsMatrix(String matrix) {
+        return matrices.contains(matrix);
+    }
+
+    /**
+     * Removes one matrix of the set.
+     * 
+     * @param matrix the matrix to remove
+     * 
+     * @return true, if the matrix was successfully removed
+     */
+    public boolean removeMatrix(String matrix) {
+        return matrices.remove(matrix);
+    }
+
+    /**
+     * Adds one matrix to the set.
+     * 
+     * @param matrix the matrix to add
+     */
+    public void addMatrix(String matrix) {
+        if (!matrices.contains(matrix)) {
+            matrices.add(matrix);
+        }
+    }
+
+    /**
+     * Gets the distributions.
+     * 
+     * @return the distributions
+     */
+    public List<Integer> getDistributions() {
+        List<Integer> distributionsClone = new ArrayList<Integer>(distributions);
+        return distributionsClone;
+    }
+
+    /**
+     * Sets the distributions.
+     * 
+     * @param newDistributions the new distributions
+     */
+    public void setDistributions(List<Integer> newDistributions) {
+        distributions = newDistributions;
+    }
+
+    /**
+     * Gets the number of distributions.
+     * 
+     * @return the number of distributions
+     */
+    public int getNumberOfDistributions() {
+        return distributions.size();
+    }
+
+    /**
+     * Gets the distribution at a certain position of the list.
+     * 
+     * @param pos the position of the distribution to get
+     * 
+     * @return the distribution at the required position
+     */
+    public int getDistributionAt(int pos) {
+        return distributions.get(pos);
+    }
+
+    /**
+     * Gets the internal value of a distribution.
+     * 
+     * @param distribution the distribution name
+     * 
+     * @return the distribution value
+     */
+    public int getDistribution(String distribution) {
+        return distributionsHash.get(distribution);
+    }
+
+    /**
+     * Check if exist one distribution in the distribution set.
+     * 
+     * @param distribution the distribution to check out
+     * 
+     * @return true, if the set of distribution contains the distribution
+     */
+    public boolean existsDistribution(String distribution) {
+        return distributionsHash.containsKey(distribution);
+    }
+
+    /**
+     * Adds one distribution to the distributions set.
+     * 
+     * @param distribution the distribution to add
+     */
+    public void addDistribution(String distribution) {
+        Integer distributionValue = distributionsHash.get(distribution);
+        if (!distributions.contains(distributionValue)) {
+            distributions.add(distributionValue);
+        }
+    }
+
+    /**
+     * Removes the distribution from the distributions set.
+     * 
+     * @param distribution the distribution to remove
+     * 
+     * @return true, if the distribution was successfully removed
+     */
+    public boolean removeDistribution(String distribution) {
+        Integer distributionValue = distributionsHash.get(distribution);
+        return distributions.remove(distributionValue);
+    }
+
+    /**
+     * Gets the sample size.
+     * 
+     * @return the sample size
+     */
+    public double getSampleSize() {
+        return alignment.getSiteCount();
+    }
+
+    /**
+     * Sets the sample size.
+     * 
+     * @param sampleSize the new sample size
+     */
+    public void setSampleSize(double sampleSize) {
+        this.sampleSize = sampleSize;
+    }
+
+    /**
+     * Sets the strategy mode.
+     * 
+     * @param strategyMode the new strategy mode
+     */
+    public void setStrategyMode(int strategyMode) {
+        if (strategyMode == OPTIMIZE_USER && getTreeFile() == null) {
+            throw new ProtTestInternalException("User defined topology must be set");
+        }
+        this.strategyMode = strategyMode;
+    }
+
+    /**
+     * Instantiates a new application options.
+     */
+    public ApplicationOptions() {
+        initLists();
+    }
+
+    /**
+     * Fill in attribute values with the arguments.
+     * 
+     * @param arguments the arguments too fill the application options instance in
+     */
+    public void fillIn(ProtTestArgumentParser arguments) {
+
+        if (arguments.exists(ProtTestArgumentParser.PARAM_ALIGNMENT_FILE)) {
+            try {
+                setAlignment(arguments.getValue(ProtTestArgumentParser.PARAM_ALIGNMENT_FILE));
+            } catch (AlignmentParseException e) {
+                throw new IllegalArgumentException(e.getMessage());
+            } catch (IOException e) {
+                throw new IllegalArgumentException(e.getMessage());
+            }
+        } else {
+            throw new IllegalArgumentException("Required input file argument -i");
+        }
+        if (arguments.exists(ProtTestArgumentParser.PARAM_TREE_FILE)) {
+            try {
+                setTreeFile(arguments.getValue(ProtTestArgumentParser.PARAM_TREE_FILE));
+            } catch (FileNotFoundException ex) {
+                throw new IllegalArgumentException(ex.getMessage());
+            } catch (IOException ex) {
+                throw new IllegalArgumentException(ex.getMessage());
+            }
+        }
+        if (arguments.exists(ProtTestArgumentParser.PARAM_OUTPUT_FILE)) {
+            //open the PrintWriter with file
+            try {
+                FileOutputStream fo = new FileOutputStream(arguments.getValue(ProtTestArgumentParser.PARAM_OUTPUT_FILE));
+                ProtTestLogger.getDefaultLogger().addHandler(fo, Level.INFO);
+            } catch (FileNotFoundException fnfe) {
+                throw new ProtTestInternalException(fnfe.getMessage());
+            }
+        }
+
+        if (arguments.exists(ProtTestArgumentParser.PARAM_LOGGING)) {
+            logEnabled = arguments.getValue(ProtTestArgumentParser.PARAM_LOGGING).equalsIgnoreCase("enabled");
+        }
+            
+        if (arguments.exists(ProtTestArgumentParser.PARAM_TREE_SEARCH_OP)) {
+            setTreeSearchOperation(arguments.getValue(ProtTestArgumentParser.PARAM_TREE_SEARCH_OP));
+        }
+        setDebug(arguments.isSet(ProtTestArgumentParser.PARAM_VERBOSE));
+        displayASCIITree = arguments.isSet(ProtTestArgumentParser.PARAM_DISPLAY_ASCII_TREE);
+        displayNewickTree = arguments.isSet(ProtTestArgumentParser.PARAM_DISPLAY_NEWICK_TREE);
+        displayConsensusTree = arguments.isSet(ProtTestArgumentParser.PARAM_DISPLAY_CONSENSUS_TREE);
+        if (arguments.exists(ProtTestArgumentParser.PARAM_DISPLAY_CONSENSUS_TREE)) {
+            displayConsensusTree = true;
+            try {
+                consensusThreshold = Double.parseDouble(arguments.getValue(ProtTestArgumentParser.PARAM_DISPLAY_CONSENSUS_TREE));
+            } catch  (NumberFormatException e) {
+                throw new IllegalArgumentException("Consensus threshold must be a number between 0.5 (majority rule) and 1 (strict). You used " + arguments.getValue(ProtTestArgumentParser.PARAM_DISPLAY_CONSENSUS_TREE));
+            }
+            if (consensusThreshold < 0.5 || consensusThreshold > 1.0) {
+                throw new IllegalArgumentException("Consensus threshold must be a number between 0.5 (majority rule) and 1 (strict). You used " + consensusThreshold);
+            }
+        }
+        setAll(arguments.isSet(ProtTestArgumentParser.PARAM_ALL_FRAMEWORK_COMPARISON));
+        if (arguments.exists(ProtTestArgumentParser.PARAM_OPTIMIZATION_STRATEGY)) {
+            if (getTreeFile() != null) {
+                strategyMode = OPTIMIZE_USER;
+            } else {
+                strategyMode = Integer.parseInt(arguments.getValue(ProtTestArgumentParser.PARAM_OPTIMIZATION_STRATEGY));
+                // Check
+                if (strategyMode == OPTIMIZE_USER &&
+                        getTreeFile() == null) {
+                    throw new IllegalArgumentException("User defined topology must be set");
+                }
+            }
+        }
+        if (arguments.exists(ProtTestArgumentParser.PARAM_DO_AIC)) {
+            doAIC = arguments.isSet(ProtTestArgumentParser.PARAM_DO_AIC);
+        }
+        if (arguments.exists(ProtTestArgumentParser.PARAM_DO_BIC)) {
+            doBIC = arguments.isSet(ProtTestArgumentParser.PARAM_DO_BIC);
+        }
+        if (arguments.exists(ProtTestArgumentParser.PARAM_DO_AICC)) {
+            doAICc = arguments.isSet(ProtTestArgumentParser.PARAM_DO_AICC);
+        }
+        if (arguments.exists(ProtTestArgumentParser.PARAM_DO_DT)) {
+            doDT = arguments.isSet(ProtTestArgumentParser.PARAM_DO_DT);
+        }
+
+        setSampleSize(ProtTestAlignment.calculateSampleSize(alignment));
+
+        boolean existsMatrix = false;
+        for (String matrix : arguments.getMatrices()) {
+            if (arguments.isSet(matrix)) {
+                addMatrix(matrix);
+                existsMatrix = true;
+            } else {
+                removeMatrix(matrix);
+            }
+        }
+        if (!existsMatrix) {
+            throw new IllegalArgumentException("You must specify at least one model matrix");
+        }
+
+        // distributions
+        addDistribution("Uniform");
+        boolean plusG = false, plusIG = false;
+        if (arguments.isSet(ProtTestArgumentParser.PARAM_PLUSI)) {
+            addDistribution("+I");
+        }
+        if (arguments.exists(ProtTestArgumentParser.PARAM_PLUSG)) {
+            addDistribution("+G");
+            plusG = true;
+        }
+        if (arguments.exists(ProtTestArgumentParser.PARAM_PLUSIG)) {
+            addDistribution("+I+G");
+            plusIG = true;
+        }
+        if (plusG || plusIG) {
+            try {
+                setNumberOfCategories(Integer.parseInt(arguments.getValue(ProtTestArgumentParser.PARAM_NCAT)));
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Invalid number of categories " + arguments.getValue(ProtTestArgumentParser.PARAM_PLUSG));
+            }
+        }
+        if (arguments.isSet(ProtTestArgumentParser.PARAM_PLUSF)) {
+            setPlusF(true);
+        }
+    }
+
+    /**
+     * Inits the Lists.
+     */
+    private void initLists() {
+//        for(int i=0; i<ALL_MATRICES.length; i++) {
+//            matrixes.addElement(ALL_MATRICES[i]);
+//        }
+        distributionsHash = new HashMap<String, Integer>();
+        distributionsHash.put("Uniform", new Integer(Model.DISTRIBUTION_UNIFORM));
+        distributionsHash.put("+I", new Integer(Model.DISTRIBUTION_INVARIABLE));
+        distributionsHash.put("+G", new Integer(Model.DISTRIBUTION_GAMMA));
+        distributionsHash.put("+I+G", new Integer(Model.DISTRIBUTION_GAMMA_INV));
+    }
+
+    /**
+     * Display the command line usage of the application.
+     */
+    public static void usage() {
+        println("-------------------------------------------------------------------------------------------------");
+        println("Basic usage: ");
+        println(" - Sequential version: ");
+        println("        java -jar prottest-2.1.jar -i alignm_file [OPTIONS]");
+        println(" - Parallel version: ");
+        println("        mpjrun.sh -wdir $PWD/ -np [NUM_PROCS] -jar ModelTest-2.1.jar -i alignm_file [OPTIONS]");
+        println("OPTIONS:");
+        println(" -i alignment_filename");
+        println("            Alignment input file (required)");
+        println(" -t tree_filename");
+        println("            Tree file       (optional) [default: NJ tree]");
+        println(" -o output_filename");
+        println("            Output file     (optional) [default: standard output]");
+        println(" -log enabled/disabled");
+        println("            Enables / Disables PhyML logging into log directory (see prottest.properties)");
+        println(" -[matrix]");
+        print(  "            Include matrix (Amino-acid) = "  );
+        int count = 0;
+        List<String> matrices = ProtTestFactory.getInstance().getApplicationGlobals().getSupportedMatrices();
+        for (String matrix : matrices) {
+            print(matrix + " ");
+            if (count == (7)) {
+                println("");
+                print("	                                  ");
+            }
+            count++;
+        }
+        println("");
+        println("                If you don't specify any matrix, all matrices displayed above will");
+        println("                be included.");
+        println(" -I");
+        println("            Include models with a proportion of invariable sites");
+        println(" -G");
+        println("            Include models with rate variation among sites and number of categories");
+        println(" -IG");
+        println("            include models with both +I and +G properties");
+        println(" -all-distributions");
+        println("            Include models with rate variation among sites, number of categories and both");
+        println(" -ncat number_of_categories");
+        println("            Define number of categories for +G and +I+G models [default: " + DEFAULT_NCAT + "]");
+        println(" -F");
+        println("            Include models with empirical frequency estimation ");
+        println(" -AIC");
+        println("            Display models sorted by Akaike Information Criterion (AIC)");
+        println(" -BIC");
+        println("            Display models sorted by Bayesian Information Criterion (BIC)");
+        println(" -AICC");
+        println("            Display models sorted by Corrected Akaike Information Criterion (AICc)");
+        println(" -DT");
+        println("            Display models sorted by Decision Theory Criterion");
+        println(" -all");
+        println("            Displays a 7-framework comparison table");
+        println(" -S optimization_strategy");
+        println("            Optimization strategy mode: [default: " + DEFAULT_STRATEGY_MODE + "]");
+        for (int i = 0; i < OPTIMIZE_NAMES.length; i++) {
+            println("             		" + i + ": " + OPTIMIZE_NAMES[i]);
+        }
+        println(" -s moves");
+        println("            Tree search operation for ML search: ");
+        println("            NNI (fastest), SPR (slowest), BEST (best of NNI and SPR) [default: NNI]");
+        println(" -t1      				");
+        println("            Display best-model's newick tree [default: " + DEFAULT_DISPLAY_NEWICK_TREE + "]");
+        println(" -t2      				");
+        println("            Display best-model's ASCII tree  [default: " + DEFAULT_DISPLAY_ASCII_TREE + "]");
+        println(" -tc consensus_threshold ");
+        println("            Display consensus tree with the specified threshold, between 0.5 and 1.0");
+        println("            [0.5 = majority rule consensus ; 1.0 = strict consensus]");
+        println(" -threads number_or_threads			");
+        println("            Number of threads requested to compute (only if MPJ is not used) [default: " +
+                DEFAULT_THREADS + "]");
+        println(" -verbose");
+        println("            Verbose mode [default: " + DEFAULT_DEBUG + "]");
+        println("-------------------------------------------------------------------------------------------------");
+        println("Example: ");
+        println("- Sequential version:");
+        println("    java -jar ModelTest-2.1.jar -i alignm_file -t tree_file -S 0 -all-distributions -F -AIC -BIC -tc 0.5 > output");
+        println("- Parallel version:");
+        println("    mpjrun.sh -wdir $PWD/ -np 2 -jar ModelTest-2.1.jar -i alignm_file -t tree_file -S 0 -all-distributions -F -AIC -BIC -tc 0.5");
+    }
+
+    public void reportModelOptimization() {
+        String tmp;
+        tmp = "BioNJ";
+        if (tree_file != null) {
+            tmp = tree_file;
+        }
+        println("");
+        println("ProtTest options");
+        println("----------------");
+        println("  Alignment file........... : " + align_file);
+        println("  Tree..................... : " + tmp);
+        println("  StrategyMode............. : " + OPTIMIZE_NAMES[strategyMode]);
+
+        println("  Candidate models......... : ");
+        print("    Matrices............... : ");
+        for (int i = 0; i < matrices.size(); i++) {
+            print(matrices.get(i) + " ");
+        }
+        println("");
+        print("    Distributions.......... : ");
+        for (String dist : distributionsHash.keySet()) {
+            Integer value = (Integer) distributionsHash.get(dist);
+            if (distributions.contains(value)) {
+                print(dist + " ");
+            }
+        }
+        println("");
+        println("    Observed frequencies... : " + plusF);
+        println("");
+    }
+
+    /**
+     * Report the current options.
+     */
+    public void reportComplete() {
+        reportModelOptimization();
+
+        println("  Statistical framework");
+        println("    Sort models according to....: ");
+        StringBuilder sb = new StringBuilder();
+        if (doAIC) {
+            sb.append(" AIC ");
+        }
+        if (doBIC) {
+            sb.append(" BIC ");
+        }
+        if (doAICc) {
+            sb.append(" AICc ");
+        }
+        if (doDT) {
+            sb.append(" DT ");
+        }
+        if (!(doAIC|doBIC|doAICc|doDT))
+            sb.append(" lnL");
+        println("      " + sb.toString());
+        println("    Sample size.................: " + sampleSize + " (not calculated yet)");
+        println("  Other options:");
+        println("    Display best tree in ASCII..: " + displayASCIITree);
+        println("    Display best tree in Newick.: " + displayNewickTree);
+        println("    Display consensus tree......: " + displayConsensusTree);
+        if (displayConsensusTree) {
+            println("    Consensus threshold.........: " + consensusThreshold);
+        }
+        println("    Verbose.....................: " + debug);
+
+        println("");
+    }
+
+    private static void print(String message) {
+        info(message, ApplicationOptions.class);
+    }
+
+    private static void println(String message) {
+        infoln(message, ApplicationOptions.class);
+    }
+}
+
diff --git a/src/main/java/es/uvigo/darwin/prottest/global/options/SerializableApplicationOptions.java b/src/main/java/es/uvigo/darwin/prottest/global/options/SerializableApplicationOptions.java
new file mode 100755
index 0000000..7bc026b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/global/options/SerializableApplicationOptions.java
@@ -0,0 +1,194 @@
+/*
+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.prottest.global.options;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * This class is a serializable version of {@link ApplicationOptions ApplicationOptions}.
+ * It has all important attributes in a concrete state of the application, and
+ * reduces alignment ant topology to a hash, making this object much lighter
+ * than the Application Options instance.
+ * 
+ * @author Diego Darriba
+ * 
+ * @since 3.0
+ */
+public class SerializableApplicationOptions implements Serializable {
+
+    private static final long serialVersionUID = 7758895101915536602L;
+    /** The alignment, according to the alignment input file. */
+    protected int alignment;
+    /** The tree, according to the tree filename. */
+    protected int tree;
+    /** The number of categories. It is only useful if the distribution is gamma */
+    public int numberOfCategories;
+    /** The optimization strategy mode. */
+    public int strategyMode;
+    /** The matrices of the models to optimize. */
+    private List<String> matrices;
+    /** The distributions of the models to optimize. */
+    private List<Integer> distributions;
+    /** Boolean value to consider or not different kind of amino-acid frequencies. */
+    private boolean plusF;
+
+    /**
+     * Gets the alignment hash.
+     * 
+     * @return the alignment hash
+     */
+    public int getAlignment() {
+        return alignment;
+    }
+
+    /**
+     * Gets the phylogenetic tree hash.
+     * 
+     * @return the tree hash
+     */
+    public int getTree() {
+        return tree;
+    }
+
+    /**
+     * Gets the number of rate categories.
+     * 
+     * @return the number of rate categories
+     */
+    public int getNumberOfCategories() {
+        return numberOfCategories;
+    }
+
+    /**
+     * Gets the starting topology strategy mode.
+     * 
+     * @return the starting topology strategy mode
+     */
+    public int getStrategyMode() {
+        return strategyMode;
+    }
+
+    /**
+     * Gets the collection of matrix names.
+     * 
+     * @return the collection of matrix names
+     */
+    public List<String> getMatrices() {
+        return matrices;
+    }
+
+    /**
+     * Gets the collection of distribution identifiers.
+     * 
+     * @return the collection of distribution identifiers
+     */
+    public List<Integer> getDistributions() {
+        return distributions;
+    }
+
+    /**
+     * Gets the state of empirical frequencies consideration.
+     * 
+     * @return true, if empirical frequencies are considered
+     */
+    public boolean isPlusF() {
+        return plusF;
+    }
+
+    /**
+     * Instantiates a new serializable application options.
+     * 
+     * @param options the actual application options instance
+     */
+    public SerializableApplicationOptions(ApplicationOptions options) {
+        this.alignment = options.getAlignment().toString().hashCode();
+        if (options.getTree() != null) {
+            this.tree = options.getTree().toString().hashCode();
+        }
+        this.numberOfCategories = options.ncat;
+        this.strategyMode = options.strategyMode;
+        this.matrices = options.getMatrices();
+        this.distributions = options.getDistributions();
+        this.plusF = options.isPlusF();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + alignment;
+        result = prime * result + ((distributions == null) ? 0 : distributions.hashCode());
+        result = prime * result + ((matrices == null) ? 0 : matrices.hashCode());
+        result = prime * result + numberOfCategories;
+        result = prime * result + (plusF ? 1231 : 1237);
+        result = prime * result + strategyMode;
+        result = prime * result + tree;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        SerializableApplicationOptions other = (SerializableApplicationOptions) obj;
+        if (alignment != other.alignment) {
+            return false;
+        }
+        if (distributions == null) {
+            if (other.distributions != null) {
+                return false;
+            }
+        } else if (!distributions.equals(other.distributions)) {
+            return false;
+        }
+        if (matrices == null) {
+            if (other.matrices != null) {
+                return false;
+            }
+        } else if (!matrices.equals(other.matrices)) {
+            return false;
+        }
+        if (numberOfCategories != other.numberOfCategories) {
+            return false;
+        }
+        if (plusF != other.plusF) {
+            return false;
+        }
+        if (strategyMode != other.strategyMode) {
+            return false;
+        }
+        if (tree != other.tree) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "SerializableApplicationOptions [alignment=" + alignment + ", distributions=" + distributions + ", matrices=" + matrices + ", numberOfCategories=" + numberOfCategories + ", plusF=" + plusF + ", strategyMode=" + strategyMode + ", tree=" + tree + "]";
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/global/options/package.html b/src/main/java/es/uvigo/darwin/prottest/global/options/package.html
new file mode 100755
index 0000000..df6c79d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/global/options/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains the configuration classes for a single execution.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/global/package.html b/src/main/java/es/uvigo/darwin/prottest/global/package.html
new file mode 100755
index 0000000..d78288e
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/global/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains global classes and interfaces which can be used from everywhere in the model.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/model/AminoAcidModel.java b/src/main/java/es/uvigo/darwin/prottest/model/AminoAcidModel.java
new file mode 100755
index 0000000..3bf15bb
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/model/AminoAcidModel.java
@@ -0,0 +1,88 @@
+/*
+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.prottest.model;
+
+import pal.alignment.Alignment;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.util.factory.ProtTestFactory;
+
+/**
+ * Substitution model form amino-acid sequences
+ * 
+ * @author Diego Darriba
+ * 
+ * @since 3.0
+ */
+public class AminoAcidModel extends Model {
+
+	/** The serialVersionUID. */
+	private static final long serialVersionUID = -8634618735564880783L;
+	
+	/**
+	 * Instantiates a new amino acid substitution model.
+	 * 
+	 * @param matrix the matrix name
+	 * @param distribution the distribution value
+	 * @param plusF consider observed frequencies
+	 */
+	public AminoAcidModel(String matrix, int distribution, boolean plusF, 
+			Alignment alignment, Tree tree, int ncat) {
+		super(matrix, distribution, plusF, alignment, tree, ncat);
+		
+		if (isPlusF())
+	    	frequenciesDistribution = FREQ_DISTRIBUTION_EMPIRICAL;
+	    else
+	    	frequenciesDistribution = FREQ_DISTRIBUTION_OTHER;
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.model.Model#getNumberOfModelParameters()
+	 */
+	public int getNumberOfModelParameters() {
+		int numModelParameters;
+		numModelParameters = getNumBranches() + getDistributionParameters();
+		if(isPlusF()) 
+			numModelParameters = numModelParameters + 19;
+		return numModelParameters;
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.model.Model#getModelName()
+	 */
+	@Override
+	public String getModelName()  {
+		
+		String matrixName = 
+			ProtTestFactory.getInstance().
+				getApplicationGlobals().
+				getModelName(getMatrix(), frequenciesDistribution);
+		StringBuffer modelName = new StringBuffer(matrixName);
+		if(getDistribution() == Model.DISTRIBUTION_INVARIABLE)
+			modelName.append("+I");
+		else if(getDistribution() == Model.DISTRIBUTION_GAMMA) 
+			modelName.append("+G");
+		else if(getDistribution() == Model.DISTRIBUTION_GAMMA_INV)
+			modelName.append("+I+G");
+
+		if(isPlusF())
+			modelName.append("+F");
+
+		return modelName.toString();
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/model/Model.java b/src/main/java/es/uvigo/darwin/prottest/model/Model.java
new file mode 100755
index 0000000..f7158f1
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/model/Model.java
@@ -0,0 +1,479 @@
+/*
+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.prottest.model;
+
+import java.io.PrintWriter;
+import java.io.Serializable;
+
+import pal.alignment.Alignment;
+import pal.tree.Tree;
+import pal.tree.TreeUtils;
+import es.uvigo.darwin.prottest.model.state.ModelEmptyLkState;
+import es.uvigo.darwin.prottest.model.state.ModelFilledLkState;
+import es.uvigo.darwin.prottest.model.state.ModelLkState;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.printer.ProtTestFormattedOutput;
+
+import static es.uvigo.darwin.prottest.util.logging.ProtTestLogger.*;
+
+import java.io.StringWriter;
+
+/**
+ * Substitution model.
+ */
+public abstract class Model implements Serializable {
+
+    /** The serialVersionUID. */
+    private static final long serialVersionUID = 20090804L;
+
+    // distributions
+    /** Useful constant for uniform distribution. */
+    public static final int DISTRIBUTION_UNIFORM = 0;
+    /** Useful constant for distribution with a proportion of invariable sites. */
+    public static final int DISTRIBUTION_INVARIABLE = 1;
+    /** Useful constant for gamma distribution. */
+    public static final int DISTRIBUTION_GAMMA = 2;
+    /** Useful constant for gamma distribution with a proportion of invariable sites. */
+    public static final int DISTRIBUTION_GAMMA_INV = 3;
+    
+    // frequencies distribution
+    /** The value of Uniform Frequencies Distribution. */
+    static final int FREQ_DISTRIBUTION_UNIFORM = 1;
+    /** The value of Empirical Frequencies Distribution. */
+    static final int FREQ_DISTRIBUTION_EMPIRICAL = 2;
+    /** The value of Maximum Likelihood Frequencies Distribution. */
+    static final int FREQ_DISTRIBUTION_MAXIMUM_LIKELIHOOD = 3;
+    /** The value of any other frequencies distribution. */
+    static final int FREQ_DISTRIBUTION_OTHER = 4;
+    
+    /** Useful constant for consider observed frequencies. */
+    public static final String PROP_PLUS_F = "plusF";
+    /** The matrix name. */
+    private String matrix;
+    /** The distribution. */
+    private int distribution;
+    /** Consider observed frequencies. */
+    private boolean plusF;
+    /** The frequencies distribution. */
+    protected int frequenciesDistribution;
+    /** The alignment hashcode. */
+    private int alignment;
+    /** The number of sequences. */
+    private int numberOfSequences;
+    /** The tree. */
+    private Tree tree;
+    /** The number of model parameters. */
+//	private  int numModelParameters;
+    /** The number of transition categories. */
+    private int numOfTransCategories;
+    /** The likelihood calculation state. */
+    private ModelLkState lkState;
+    /** The external executor command line. */
+    private String[] commandLine;
+
+    /**
+     * Gets the likelihood estimated value.
+     * 
+     * @return the likelihood estimated value
+     */
+    public double getLk() {
+        return lkState.getLk();
+    }
+
+    /**
+     * Checks if is computed.
+     * 
+     * @return true, if is computed
+     */
+    public boolean isComputed() {
+        return (lkState instanceof ModelFilledLkState);
+    }
+
+    /**
+     * Sets the likelihood estimated value.
+     * 
+     * @param lk the new likelihood estimated value
+     */
+    public void setLk(double lk) {
+        lkState = lkState.setLk(lk);
+    }
+
+    /**
+     * Gets the alpha estimated value.
+     * 
+     * @return the alpha estimated value
+     */
+    public double getAlpha() {
+        return lkState.getAlpha();
+    }
+
+    /**
+     * Sets the alpha estimated value.
+     * 
+     * @param alpha the new alpha estimated value
+     */
+    public void setAlpha(double alpha) {
+        lkState = lkState.setAlpha(alpha);
+    }
+
+    /**
+     * Gets the proportion of invariant sites.
+     * 
+     * @return the proportion of invariant sites
+     */
+    public double getInv() {
+        return lkState.getInv();
+    }
+
+    /**
+     * Sets the proportion of invariant sites.
+     * 
+     * @param inv the new proportion of invariant sites
+     */
+    public void setInv(double inv) {
+        lkState = lkState.setInv(inv);
+    }
+
+    /**
+     * Gets the alignment hashcode.
+     * 
+     * @return the alignment hashcode
+     */
+    public int getAlignment() {
+        return alignment;
+    }
+
+    /**
+     * Sets the alignment only if there wasn't set or it is a different instance of the same object.
+     * 
+     * @param alignment the new alignment
+     */
+    public void setAlignment(Alignment alignment) {
+        if (this.alignment != 0 && this.alignment != alignment.toString().hashCode()) {
+            throw new ProtTestInternalException("cannot set a different alignment");
+        }
+        this.alignment = alignment.toString().hashCode();
+        this.numberOfSequences = alignment.getSequenceCount();
+    }
+
+    /**
+     * Checks if an alignment matches the internal model alignment
+     * 
+     * @return alignment equality
+     */
+    public boolean checkAlignment(Alignment alignment) {
+        if (alignment == null) {
+            return false;
+        }
+        return (this.alignment == alignment.toString().hashCode() &&
+                this.numberOfSequences == alignment.getSequenceCount());
+    }
+
+    /**
+     * Gets the tree.
+     * 
+     * @return the tree
+     */
+    public Tree getTree() {
+        return tree;
+    }
+
+    /**
+     * Sets the tree.
+     * 
+     * @param tree the new tree
+     */
+    public void setTree(Tree tree) {
+        this.tree = tree;
+    }
+
+    /**
+     * Gets the command line.
+     * 
+     * @return the command line
+     */
+    public String[] getCommandLine() {
+        return commandLine;
+    }
+
+    /**
+     * Sets the command line.
+     * 
+     * @param commandLine the new command line
+     */
+    public void setCommandLine(String[] commandLine) {
+        this.commandLine = commandLine;
+    }
+
+    /**
+     * Gets the number of transition categories.
+     * 
+     * @return the number of transition categories
+     */
+    public int getNumberOfTransitionCategories() {
+        return numOfTransCategories;
+    }
+
+    /**
+     * Instantiates a new substitution model.
+     * 
+     * @param matrix the matrix name
+     * @param distribution the distribution value
+     * @param plusF consider observed frequencies
+     * @param alignment the alignment
+     * @param tree the tree
+     * @param ncat the ncat
+     */
+    public Model(String matrix, int distribution, boolean plusF, Alignment alignment, Tree tree, int ncat) {
+
+        if (distribution < 0 || distribution > 3) {
+            throw new ProtTestInternalException("Distribution not supported " + distribution);
+        }
+
+        if (alignment == null) {
+            throw new ProtTestInternalException("Null alignment");
+        }
+
+        this.matrix = matrix;
+        this.distribution = distribution;
+        this.plusF = plusF;
+        this.alignment = alignment.toString().hashCode();
+        this.numberOfSequences = alignment.getSequenceCount();
+        this.tree = tree;
+        this.lkState = new ModelEmptyLkState();
+
+//		numBranches = 2*alignment.getSequenceCount() - 3;
+        switch (distribution) {
+            case DISTRIBUTION_UNIFORM:
+                numOfTransCategories = 1;
+                break;
+            case DISTRIBUTION_INVARIABLE:
+                numOfTransCategories = 2;
+                break;
+            case DISTRIBUTION_GAMMA:
+                numOfTransCategories = ncat;
+                break;
+            case DISTRIBUTION_GAMMA_INV:
+                numOfTransCategories = ncat;
+                break;
+            }
+
+    }
+
+    /**
+     * Gets the number of parameters according with the distribution.
+     * 
+     * @return the distribution parameters according with the distribution
+     */
+    public int getDistributionParameters() {
+        int value = -1;
+        switch (distribution) {
+            case DISTRIBUTION_UNIFORM:
+                value = 0;
+                break;
+            case DISTRIBUTION_INVARIABLE:
+                value = 1;
+                break;
+            case DISTRIBUTION_GAMMA:
+                value = 1;
+                break;
+            case DISTRIBUTION_GAMMA_INV:
+                value = 2;
+                break;
+            }
+        return value;
+    }
+
+    /**
+     * Gets the number of model parameters.
+     * 
+     * @return the number of model parameters
+     */
+    public abstract int getNumberOfModelParameters();
+
+    /**
+     * Gets the matrix name.
+     * 
+     * @return the matrix name
+     */
+    public String getMatrix() {
+        return matrix;
+    }
+
+    /**
+     * Gets the distribution.
+     * 
+     * @return the distribution
+     */
+    public int getDistribution() {
+        return distribution;
+    }
+
+    /**
+     * Checks if observed frequencies are considered.
+     * 
+     * @return true, if the model considers observed frequencies
+     */
+    public boolean isPlusF() {
+        return plusF;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + distribution;
+        result = prime * result + ((matrix == null) ? 0 : matrix.hashCode());
+        result = prime * result + (isPlusF() ? 1231 : 1237);
+        return result;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @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 (distribution != other.distribution) {
+            return false;
+        }
+        if (matrix == null) {
+            if (other.matrix != null) {
+                return false;
+            }
+        } else if (!matrix.equals(other.matrix)) {
+            return false;
+        }
+        if (isPlusF() != other.isPlusF()) {
+            return false;
+        }
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "Model [distribution=" + distribution + ", matrix=" + matrix + ", plusF=" + isPlusF();
+//		+ ", weight=" + weight + "]";
+    }
+
+    /**
+     * Gets the complete model name.
+     * 
+     * @return the model name
+     */
+    public abstract String getModelName();
+
+    /**
+     * Gets the number of branches.
+     * 
+     * @return the number of branches
+     */
+    public int getNumBranches() {
+        return 2 * numberOfSequences - 3;
+    }
+
+    /**
+     * Checks if distribution is gamma.
+     * 
+     * @return true, if is gamma
+     */
+    public boolean isGamma() {
+        return (distribution == DISTRIBUTION_GAMMA ||
+                distribution == DISTRIBUTION_GAMMA_INV);
+    }
+
+    /**
+     * Checks if a proportion of invariant sites are considered.
+     * 
+     * @return true, if considers a proportion of invariant sites
+     */
+    public boolean isInv() {
+        return (distribution == DISTRIBUTION_INVARIABLE ||
+                distribution == DISTRIBUTION_GAMMA_INV);
+    }
+
+    /**
+     * Prints the model status report.
+     */
+    public void printReport() {
+
+        println("Model................................ : " + getModelName());
+        print("  Number of parameters............... : " + getNumberOfModelParameters());
+        println(" (" + (getNumberOfModelParameters() - getNumBranches()) + " + " +
+                getNumBranches() + " branch length estimates)");
+
+        if (isComputed()) {
+            if (isGamma()) {
+                println("    gamma shape (" + getNumberOfTransitionCategories() + " rate categories).. = " + getAlpha());
+            }
+            if (isInv()) {
+                println("    proportion of invariable sites... = " + getInv());
+            }
+            if (isPlusF()) {
+                println("    aminoacid frequencies............ = observed (see above)");
+            }
+            print(" -lnL................................ = " + ProtTestFormattedOutput.getDecimalString((-1 * getLk()), 2));
+            println("");
+
+            verboseln("The tree:");
+            verboseln("---------");
+            StringWriter ascciiSw = new StringWriter();
+            TreeUtils.report(getTree(), new PrintWriter(ascciiSw));
+            ascciiSw.flush();
+            verboseln(ascciiSw.toString());
+            StringWriter newickSw = new StringWriter();
+            verboseln("---------");
+            TreeUtils.printNH(getTree(), new PrintWriter(newickSw));
+            newickSw.flush();
+            verboseln(newickSw.toString());
+            verboseln("");
+        }
+        flush(Model.class);
+    }
+
+    private void print(String message) {
+        info(message, Model.class);
+    }
+
+    private void println(String message) {
+        infoln(message, Model.class);
+    }
+
+    private void verbose(String message) {
+        finer(message, Model.class);
+    }
+
+    private void verboseln(String message) {
+        finerln(message, Model.class);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/model/package.html b/src/main/java/es/uvigo/darwin/prottest/model/package.html
new file mode 100755
index 0000000..71513cb
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/model/package.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains the information about the selection models. This hierarchy not only supports amino-acid
+substitution models, but also a future implementation of nucleotide models can be implemented.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/model/state/ModelEmptyLkState.java b/src/main/java/es/uvigo/darwin/prottest/model/state/ModelEmptyLkState.java
new file mode 100755
index 0000000..7664711
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/model/state/ModelEmptyLkState.java
@@ -0,0 +1,89 @@
+/*
+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.prottest.model.state;
+
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+/**
+ * The Class ModelEmptyLkState defines the behavior of the model while the
+ * likelihood is not yet calculated.
+ */
+public class ModelEmptyLkState extends ModelLkState {
+
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = -6972504372160405275L;
+
+    /**
+     * Throws an internal exception.
+     * 
+     * @see es.uvigo.darwin.prottest.model.state.ModelLkState#getLk()
+     */
+    @Override
+    public double getLk() {
+        throw new ProtTestInternalException("Lk not initialized");
+    }
+
+    /**
+     * 
+     * Sets the log Likelihood and changes the state to {@link ModelFilledLkState}.
+     * 
+     * @see es.uvigo.darwin.prottest.model.state.ModelLkState#setLk(double)
+     * 
+     * @return the new state
+     */
+    @Override
+    public ModelLkState setLk(double lk) {
+        return new ModelFilledLkState(lk);
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.model.state.ModelLkState#getAlpha()
+     */
+    @Override
+    public double getAlpha() {
+        throw new ProtTestInternalException("This model is still unoptimized");
+    }
+
+    /* (non-Javadoc)
+     * @see es.uvigo.darwin.prottest.model.state.ModelLkState#getInv()
+     */
+    @Override
+    public double getInv() {
+        throw new ProtTestInternalException("This model is still unoptimized");
+    }
+
+    /**
+     * Throws an internal exception.
+     * 
+     * @see es.uvigo.darwin.prottest.model.state.ModelLkState#setAlpha(double)
+     */
+    @Override
+    public ModelLkState setAlpha(double alpha) {
+        throw new ProtTestInternalException("This model is still unoptimized");
+    }
+
+    /**
+     * Throws an internal exception.
+     * 
+     * @see es.uvigo.darwin.prottest.model.state.ModelLkState#setInv(double)
+     */
+    @Override
+    public ModelLkState setInv(double inv) {
+        throw new ProtTestInternalException("This model is still unoptimized");
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/model/state/ModelFilledLkState.java b/src/main/java/es/uvigo/darwin/prottest/model/state/ModelFilledLkState.java
new file mode 100755
index 0000000..0356b72
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/model/state/ModelFilledLkState.java
@@ -0,0 +1,100 @@
+/*
+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.prottest.model.state;
+
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+/**
+ * The Class ModelFilledLkState defines the behavior of the model when the
+ * likelihood is already calculated.
+ */
+public class ModelFilledLkState extends ModelLkState {
+
+	/** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 8247641688056141331L;
+
+	/** The likelihood logarithm value. */
+	private double lk;
+	
+	/** The calculated alpha value. */
+	private double alpha;
+	
+	/** The calculated proportion of invariant sites. */
+	private double inv;
+	
+	/**
+	 * Instantiates a new model filled lk state.
+	 * 
+	 * @param lk the lk
+	 */
+	public ModelFilledLkState(double lk) {
+		this.lk = lk;
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.model.state.ModelLkState#getLk()
+	 */
+	@Override
+	public double getLk() {
+		return lk;
+	}
+
+	/**
+         * Throws an internal exception.
+         * 
+	 * @see es.uvigo.darwin.prottest.model.state.ModelLkState#setLk(double)
+	 */
+	@Override
+	public ModelLkState setLk(double lk) {
+		throw new ProtTestInternalException("Trying to modify lnl value");
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.model.state.ModelLkState#getAlpha()
+	 */
+	@Override
+	public double getAlpha() {
+		return alpha;
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.model.state.ModelLkState#setAlpha(double)
+	 */
+	@Override
+	public ModelLkState setAlpha(double alpha) {
+		this.alpha = alpha;
+		return this;
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.model.state.ModelLkState#getInv()
+	 */
+	@Override
+	public double getInv() {
+		return inv;
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.model.state.ModelLkState#setInv(double)
+	 */
+	@Override
+	public ModelLkState setInv(double inv) {
+		this.inv = inv;
+		return this;
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/model/state/ModelLkState.java b/src/main/java/es/uvigo/darwin/prottest/model/state/ModelLkState.java
new file mode 100755
index 0000000..de34348
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/model/state/ModelLkState.java
@@ -0,0 +1,78 @@
+/*
+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.prottest.model.state;
+
+import java.io.Serializable;
+
+/**
+ * The Class ModelLkState defines the behavior of the model in relation to the
+ * likelihood value.
+ */
+public abstract class ModelLkState implements Serializable {
+
+	/** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 2199513513876803640L;
+
+	/**
+	 * Gets the likelihood of the model.
+	 * 
+	 * @return the likelihood logarithm value.
+	 */
+	public abstract double getLk();
+	
+	/**
+	 * Sets the likelihood of the model.
+	 * 
+	 * @param lk the likelihood logarithm value.
+	 * 
+	 * @return the new state of the model.
+	 */
+	public abstract ModelLkState setLk(double lk);
+	
+	/**
+	 * Gets the alpha estimated value.
+	 * 
+	 * @return the alpha estimated value
+	 */
+	public abstract double getAlpha();
+
+	/**
+	 * Sets the alpha estimated value.
+	 * 
+	 * @param alpha the new alpha estimated value
+         *
+         * @return the new state
+	 */
+	public abstract ModelLkState setAlpha(double alpha);
+
+	/**
+	 * Gets the proportion of invariant sites.
+	 * 
+	 * @return the proportion of invariant sites
+	 */
+	public abstract double getInv();
+
+	/**
+	 * Sets the proportion of invariant sites.
+	 * 
+	 * @param inv the new proportion of invariant sites
+         * 
+         * @return the new state
+	 */
+	public abstract ModelLkState setInv(double inv);
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/model/state/package.html b/src/main/java/es/uvigo/darwin/prottest/model/state/package.html
new file mode 100755
index 0000000..87f7e1b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/model/state/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+This state pattern allows to manage the optimization state of the models.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/observer/ModelUpdaterObserver.java b/src/main/java/es/uvigo/darwin/prottest/observer/ModelUpdaterObserver.java
new file mode 100755
index 0000000..5463523
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/observer/ModelUpdaterObserver.java
@@ -0,0 +1,40 @@
+/*
+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.prottest.observer;
+
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+
+/**
+ * The observer interface for model update.
+ * 
+ * @author Diego Darriba López
+ * 
+ * @since 3.0
+ */
+public interface ModelUpdaterObserver {
+
+    /**
+     * Updates the observers.
+     * 
+     * @param o the observable object
+     * @param model the updated model
+     * @param options the application options
+     */
+	public void update(ObservableModelUpdater o, Model model, ApplicationOptions options);
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/observer/ObservableModelUpdater.java b/src/main/java/es/uvigo/darwin/prottest/observer/ObservableModelUpdater.java
new file mode 100755
index 0000000..d82a20e
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/observer/ObservableModelUpdater.java
@@ -0,0 +1,83 @@
+/*
+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.prottest.observer;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+
+/**
+ * The observable class for model update.
+ * 
+ * @author Diego Darriba López
+ * 
+ * @since 3.0
+ */
+public abstract class ObservableModelUpdater {
+
+    /** Collection of observers */
+    private Collection<ModelUpdaterObserver> modelUpdaterObservers;
+
+    /**
+     * Constructor for observable objects.
+     */
+    public ObservableModelUpdater() {
+        modelUpdaterObservers = new ArrayList<ModelUpdaterObserver>();
+    }
+
+    /**
+     * Adds a new observer.
+     * 
+     * @param o the observer
+     */
+    public void addObserver(ModelUpdaterObserver o) {
+        modelUpdaterObservers.add(o);
+    }
+
+    /**
+     * Removes an observer.
+     * 
+     * @param o the observer
+     */
+    public void removeObserver(ModelUpdaterObserver o) {
+        modelUpdaterObservers.remove(o);
+    }
+
+    /**
+     * Notifies all observers.
+     */
+    public void notifyObservers() {
+        for (ModelUpdaterObserver o : modelUpdaterObservers) {
+            o.update(this, null, null);
+        }
+    }
+
+    /**
+     * Notifies all observers with a model an options
+     * 
+     * @param model the substitution models
+     * @param options the application options
+     */
+    public void notifyObservers(Model model, ApplicationOptions options) {
+        for (ModelUpdaterObserver o : modelUpdaterObservers) {
+            o.update(this, model, options);
+        }
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/observer/package.html b/src/main/java/es/uvigo/darwin/prottest/observer/package.html
new file mode 100755
index 0000000..7400fc2
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/observer/package.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains a custom implementation of the <code>Observer</code> pattern for
+ProtTest-HPC.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/package.html b/src/main/java/es/uvigo/darwin/prottest/package.html
new file mode 100755
index 0000000..951bb31
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/package.html
@@ -0,0 +1,22 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains the main class of ProtTest-HPC console version. This is the main package and contains only
+the main class of ProtTest-HPC. Packages below this one contains all the model classes and the
+facades, and provides the whole functionality of the application.
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/AIC.java b/src/main/java/es/uvigo/darwin/prottest/selection/AIC.java
new file mode 100755
index 0000000..b4c976b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/AIC.java
@@ -0,0 +1,89 @@
+/*
+Copyright (C) 2009  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 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.prottest.selection;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.model.AICSelectionModel;
+import es.uvigo.darwin.prottest.selection.model.SelectionModel;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+
+/**
+ * The Akaike Information Criterion
+ *
+ * Description:		AIC computation
+ * @author			David Posada, University of Vigo, Spain
+ *					dposada at uvigo.es | darwin.uvigo.es
+ */
+public class AIC extends InformationCriterion
+{
+	
+//	/**
+//	 * Instantiates a new Akaike Information Criterion.
+//	 * 
+//	 * @param models the models
+//	 * @param confidenceInterval the confidence interval
+//	 */
+//	public AIC (ModelCollection models, double confidenceInterval) 
+//		{
+//		super(models, confidenceInterval);
+//		
+//		Collections.sort(selectionModels);
+//		}
+	
+	/**
+	 * Instantiates a new Akaike Information Criterion.
+	 * 
+	 * @param models the models
+	 * @param confidenceInterval the confidence interval
+	 * @param sampleSize the sample size if different of the default
+	 */
+	public AIC (ModelCollection models, double confidenceInterval, double sampleSize) 
+		{
+		super(models, confidenceInterval, sampleSize);
+		
+		Collections.sort(selectionModels);
+		}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.InformationCriterion#getSelectionModels(es.uvigo.darwin.prottest.util.collection.ModelIterator)
+	 */
+	protected List<SelectionModel> getSelectionModels(List<Model> models) {
+		List<SelectionModel> list = new ArrayList<SelectionModel>();
+		for (Model model : models) {
+			SelectionModel toAdd = new AICSelectionModel(
+					model, 
+					sampleSize); 
+			list.add( toAdd );
+			hashModels.put(model, toAdd);
+		}
+		return list;
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.InformationCriterion#getCriterionName()
+	 */
+	public String getCriterionName() {
+		return "AIC";
+	}
+}
+
+
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/AICc.java b/src/main/java/es/uvigo/darwin/prottest/selection/AICc.java
new file mode 100755
index 0000000..4bde77f
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/AICc.java
@@ -0,0 +1,74 @@
+/*
+Copyright (C) 2009  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 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.prottest.selection;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.model.AICcSelectionModel;
+import es.uvigo.darwin.prottest.selection.model.SelectionModel;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+
+/**
+ * The Corrected Akaike Information Criterion.
+ * @author			David Posada, University of Vigo, Spain
+ *					dposada at uvigo.es | darwin.uvigo.es
+ */
+public class AICc extends InformationCriterion
+{
+	
+	/**
+	 * Instantiates a new Corrected Akaike Information Criterion.
+	 * 
+	 * @param models the models
+	 * @param confidenceInterval the confidence interval
+	 * @param sampleSize the sample size if different of the default
+	 */
+	public AICc (ModelCollection models, double confidenceInterval, double sampleSize) 
+		{
+		super(models, confidenceInterval, sampleSize);
+		
+		Collections.sort(selectionModels);
+		}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.InformationCriterion#getSelectionModels(es.uvigo.darwin.prottest.util.collection.ModelIterator)
+	 */
+	protected List<SelectionModel> getSelectionModels(List<Model> models) {
+		List<SelectionModel> list = new ArrayList<SelectionModel>();
+		for (Model model : models) {
+			SelectionModel toAdd = new AICcSelectionModel(
+					model, 
+					sampleSize); 
+			list.add( toAdd );
+			hashModels.put(model, toAdd);
+		}
+		return list;
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.InformationCriterion#getCriterionName()
+	 */
+	public String getCriterionName() {
+		return "AICc";
+	}
+}
+
+
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/BIC.java b/src/main/java/es/uvigo/darwin/prottest/selection/BIC.java
new file mode 100755
index 0000000..87f043d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/BIC.java
@@ -0,0 +1,87 @@
+/*
+Copyright (C) 2009  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 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.prottest.selection;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.model.BICSelectionModel;
+import es.uvigo.darwin.prottest.selection.model.SelectionModel;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+
+/**
+ * The Bayesian Information Criterion.
+ * @author			David Posada, University of Vigo, Spain
+ *					dposada at uvigo.es | darwin.uvigo.es
+ */
+public class BIC extends InformationCriterion
+{
+	
+//	/**
+//	 * Instantiates a new Bayesian Information Criterion.
+//	 * 
+//	 * @param models the models
+//	 * @param confidenceInterval the confidence interval
+//	 */
+//	public BIC (ModelCollection models, double confidenceInterval) 
+//		{
+//		super(models, confidenceInterval);
+//		
+//		Collections.sort(selectionModels);
+//		}
+	
+	/**
+	 * Instantiates a new Bayesian Information Criterion.
+	 * 
+	 * @param models the models
+	 * @param confidenceInterval the confidence interval
+	 * @param sampleSize the sample size if different of the default
+	 */
+	public BIC (ModelCollection models, double confidenceInterval, double sampleSize) 
+		{
+		super(models, confidenceInterval, sampleSize);
+		
+		Collections.sort(selectionModels);
+		}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.InformationCriterion#getSelectionModels(es.uvigo.darwin.prottest.util.collection.ModelIterator)
+	 */
+	protected List<SelectionModel> getSelectionModels(List<Model> models) {
+		List<SelectionModel> list = new ArrayList<SelectionModel>();
+		for (Model model : models) {
+			SelectionModel toAdd = new BICSelectionModel(
+					model, 
+					sampleSize); 
+			list.add( toAdd );
+			hashModels.put(model, toAdd);
+		}
+		return list;
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.InformationCriterion#getCriterionName()
+	 */
+	public String getCriterionName() {
+		return "BIC";
+	}
+}
+
+
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/DT.java b/src/main/java/es/uvigo/darwin/prottest/selection/DT.java
new file mode 100755
index 0000000..f24ddeb
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/DT.java
@@ -0,0 +1,87 @@
+/*
+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.prottest.selection;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.model.DTSelectionModel;
+import es.uvigo.darwin.prottest.selection.model.SelectionModel;
+import es.uvigo.darwin.prottest.tree.TreeDistancesCache;
+import es.uvigo.darwin.prottest.tree.TreeEuclideanDistancesCache;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+
+/**
+ * The Decision Theory Information Criterion.
+ *
+ * @author Diego Darriba
+ */
+public class DT extends InformationCriterion
+{
+	
+	private BIC bic;
+	private TreeDistancesCache distancesCache;
+	
+	/**
+	 * Instantiates a new Decision Theory Information Criterion.
+	 * 
+	 * @param models the models
+	 * @param confidenceInterval the confidence interval
+	 * @param sampleSize the sample size if different of the default
+	 */
+	public DT (ModelCollection models, double confidenceInterval, double sampleSize) 
+		{
+		super(models, confidenceInterval, sampleSize);
+		Collections.sort(selectionModels);
+		}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.InformationCriterion#getSelectionModels(es.uvigo.darwin.prottest.util.collection.ModelIterator)
+	 */
+	protected List<SelectionModel> getSelectionModels(List<Model> models) {
+		ModelCollection modelCollection = new SingleModelCollection(
+                        models.toArray(new Model[0]),
+                        alignment);
+		bic = new BIC(modelCollection, confidenceInterval, sampleSize);
+		distancesCache = TreeEuclideanDistancesCache.getInstance();
+		
+		List<SelectionModel> list = new ArrayList<SelectionModel>();
+		for (Model model : models) {
+			SelectionModel toAdd = new DTSelectionModel(
+					model, 
+					sampleSize,
+					bic,
+					distancesCache); 
+			list.add( toAdd );
+			hashModels.put(model, toAdd);
+		}
+		return list;
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.InformationCriterion#getCriterionName()
+	 */
+	public String getCriterionName() {
+		return "DT";
+	}
+}
+
+
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/InformationCriterion.java b/src/main/java/es/uvigo/darwin/prottest/selection/InformationCriterion.java
new file mode 100755
index 0000000..6867ed6
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/InformationCriterion.java
@@ -0,0 +1,423 @@
+/*
+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.prottest.selection;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.model.SelectionModel;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import java.util.ArrayList;
+import pal.alignment.Alignment;
+
+/**
+ * Generic implementation of an information criterion for model selection.
+ * Model selection is used to model-averaging and estimate parameter importance
+ * in an evolutionary context after computing likelihood values for every model.
+ */
+public abstract class InformationCriterion {
+
+    /** The best model according the concrete criterion. */
+    protected SelectionModel bestModel;
+    /** The models including some information about the criterion. */
+    protected List<SelectionModel> selectionModels;
+    /** HashMap to quick find the selection models. */
+    protected HashMap<Model, SelectionModel> hashModels;
+    /** The confidence interval. */
+    protected double confidenceInterval;
+    /** The set of models that fall into the confidence interval. */
+    protected List<SelectionModel> confidenceModels;
+    /** The cumulative weight of the parameter. */
+    protected double cumWeight;
+    /** The overall alpha value. */
+    protected double overallAlpha = 0.0;
+    /** The overall invariant value. */
+    protected double overallInv = 0.0;
+    /** The overall alpha + invariant value. */
+    protected double overallAlphaInv = 0.0;
+    /** The overall invariant + alpha value. */
+    protected double overallInvAlpha = 0.0;
+    /** The alpha parameter importance. */
+    protected double alphaImportance = 0.0;
+    /** The invariant parameter importance. */
+    protected double invImportance = 0.0;
+    /** The alpha + invariant parameter importance. */
+    protected double alphaInvImportance = 0.0;
+    /** The +F parameter importance. */
+    protected double fImportance = 0.0;
+    /** The sample size. */
+    protected double sampleSize;
+    /** The alignment */
+    protected Alignment alignment;
+
+    private boolean existInvModels = false,
+            existGammaModels = false,
+            existGammaInvModels = false,
+            existFModels = false;
+
+    public boolean isExistFModels() {
+        return existFModels;
+    }
+
+    public boolean isExistGammaInvModels() {
+        return existGammaInvModels;
+    }
+
+    public boolean isExistGammaModels() {
+        return existGammaModels;
+    }
+
+    public boolean isExistInvModels() {
+        return existInvModels;
+    }
+
+    /**
+     * Gets the overall alpha value.
+     * 
+     * @return the overall alpha value
+     */
+    public double getOverallAlpha() {
+        return overallAlpha;
+    }
+
+    /**
+     * Gets the overall invariant value.
+     * 
+     * @return the overall invariant value
+     */
+    public double getOverallInv() {
+        return overallInv;
+    }
+
+    /**
+     * Gets the overall alpha + invariant value.
+     * 
+     * @return the overall alpha + invariant value
+     */
+    public double getOverallAlphaInv() {
+        return overallAlphaInv;
+    }
+
+    /**
+     * Gets the overall invariant + alpha value.
+     * 
+     * @return the overall invariant + alpha value
+     */
+    public double getOverallInvAlpha() {
+        return overallInvAlpha;
+    }
+
+    /**
+     * Gets the alpha parameter importance.
+     * 
+     * @return the alpha parameter importance
+     */
+    public double getAlphaImportance() {
+        return alphaImportance;
+    }
+
+    /**
+     * Gets the invariant parameter importance.
+     * 
+     * @return the invariant parameter importance
+     */
+    public double getInvImportance() {
+        return invImportance;
+    }
+
+    /**
+     * Gets the alpha + invariant parameter importance.
+     * 
+     * @return the alpha + invariant parameter importance
+     */
+    public double getAlphaInvImportance() {
+        return alphaInvImportance;
+    }
+
+    /**
+     * Gets the +F parameter importance.
+     * 
+     * @return the +F parameter importance
+     */
+    public double getFImportance() {
+        return fImportance;
+    }
+
+    /**
+     * Gets the sample size.
+     * 
+     * @return the sample size
+     */
+    public double getSampleSize() {
+        return sampleSize;
+    }
+
+    /**
+     * Gets the confidence interval value
+     * 
+     * @return the confidence interval
+     */
+    public double getConfidenceInterval() {
+        return confidenceInterval;
+    }
+
+    /**
+     * Gets the list of selection models.
+     * 
+     * @return the list of selection models
+     */
+    public List<SelectionModel> getSelectionModels() {
+        return selectionModels;
+    }
+
+    /**
+     * Instantiates a new model selection criterion.
+     * 
+     * @param models the models to compute
+     * @param confidenceInterval the confidence interval
+     * @param sampleSize the sample size if different of the default
+     */
+    public InformationCriterion(ModelCollection models,
+            double confidenceInterval, double sampleSize) {
+        this.alignment = models.getAlignment();
+        this.sampleSize = sampleSize;
+        int numberOfModels = models.size();
+        this.confidenceInterval = confidenceInterval;
+        this.hashModels = new HashMap<Model, SelectionModel>(numberOfModels);
+        this.confidenceModels = new ArrayList<SelectionModel>();
+        this.selectionModels = getSelectionModels(models);
+        Collections.sort(selectionModels);
+        for (Model model : models) {
+            if (!existInvModels && model.isInv() && !model.isGamma()) {
+                existInvModels = true;
+            } else if (!existGammaModels && !model.isInv() && model.isGamma()) {
+                existGammaModels = true;
+            } else if (!existGammaInvModels && model.isInv() && model.isGamma()) {
+                existGammaInvModels = true;
+            } else if (!existFModels && model.isPlusF()) {
+                existFModels = true;
+            }
+        }
+        compute();
+    }
+
+    /**
+     * Gets the list of selection models.
+     * 
+     * @param models the models to calculate the information criterion
+     * 
+     * @return the list of models having the information about the concrete criterion
+     */
+    protected abstract List<SelectionModel> getSelectionModels(List<Model> models);
+
+    /**
+     * Computes the delta criterion, the weight and the cumulative weight of the criterion
+     * over the model collection.
+     */
+    private void compute() {
+        double minValue, sumExp, cum;
+
+        bestModel = selectionModels.get(0);
+        minValue = bestModel.getValue();
+
+        // Calculate differences
+        sumExp = 0;
+        for (SelectionModel model : selectionModels) {
+            model.setDeltaValue(
+                    model.getValue() - minValue);
+            sumExp += Math.exp(-0.5 * model.getDeltaValue());
+        }
+
+        // Calculate weights
+        for (SelectionModel model : selectionModels) {
+            if (model.getDeltaValue() > 1000) {
+                model.setWeightValue(0.0);
+            } else {
+                model.setWeightValue(
+                        Math.exp(-0.5 * model.getDeltaValue()) / sumExp);
+            }
+        }
+
+        // Calculate cumulative weights, overalls and parameters importance
+        cum = 0.0;
+        alphaImportance = 0.0;
+        invImportance = 0.0;
+        alphaInvImportance = 0.0;
+        fImportance = 0.0;
+        overallAlpha = 0.0;
+        overallInv = 0.0;
+        overallAlphaInv = 0.0;
+        overallInvAlpha = 0.0;
+        for (SelectionModel model : selectionModels) {
+            cum += model.getWeightValue();
+            model.setCumulativeWeightValue(cum);
+
+            if (model.getModel().isGamma() && model.getModel().isInv()) {
+                alphaInvImportance += model.getWeightValue();
+                overallAlphaInv += model.getWeightValue() * model.getModel().getAlpha();
+                overallInvAlpha += model.getWeightValue() * model.getModel().getInv();
+            } else if (model.getModel().isGamma()) {
+                alphaImportance += model.getWeightValue();
+                overallAlpha += model.getWeightValue() * model.getModel().getAlpha();
+            } else if (model.getModel().isInv()) {
+                invImportance += model.getWeightValue();
+                overallInv += model.getWeightValue() * model.getModel().getInv();
+            }
+            if (model.getModel().isPlusF()) {
+                fImportance += model.getWeightValue();
+            }
+        }
+
+        overallAlpha /= alphaImportance;
+        overallInv /= invImportance;
+        overallInvAlpha /= alphaInvImportance;
+        overallAlphaInv /= alphaInvImportance;
+
+        // confidence interval
+        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).
+     */
+    public void buildConfidenceInterval() {
+        confidenceModels = new ArrayList<SelectionModel>();
+
+        // first construct the confidence interval for models
+        if (confidenceInterval >= 1.0) {
+
+            for (SelectionModel model : selectionModels) {
+                model.setInConfidenceInterval(true);
+                confidenceModels.add(model);
+            }
+            cumWeight = 1.0;
+
+        } else {
+            cumWeight = 0.0;
+            SelectionModel lastModel = null;
+            for (SelectionModel model : selectionModels) {
+                if (model.getCumulativeWeightValue() <= confidenceInterval) {
+                    confidenceModels.add(model);
+                    cumWeight += model.getWeightValue();
+                } else {
+                    lastModel = model;
+                    break;
+                }
+            }
+
+            // lets decide whether the model that just passed the confidence
+            // interval should be included (suggested by John Huelsenbeck)
+            double probOut = (lastModel.getCumulativeWeightValue() - confidenceInterval) / lastModel.getWeightValue();
+            double probIn = 1.0 - probOut;
+            Random generator = new Random();
+            double randomNumber = generator.nextDouble();
+            if (randomNumber <= probIn) {
+                lastModel.setInConfidenceInterval(true);
+                confidenceModels.add(lastModel);
+                cumWeight += lastModel.getWeightValue();
+            } else {
+                lastModel.setInConfidenceInterval(false);
+            }
+        }
+    }
+
+    /**
+     * All iterator.
+     * 
+     * @return the iterator< selection model>
+     */
+    public Iterator<SelectionModel> allIterator() {
+        return selectionModels.iterator();
+    }
+
+    /**
+     * Confidence collection.
+     * 
+     * @return the collection of confidence selection models
+     */
+    public Collection<SelectionModel> getConfidenceModels() {
+        return confidenceModels;
+    }
+
+    /**
+     * Gets the model collection.
+     * 
+     * @return the model collection
+     */
+    public ModelCollection getModelCollection() {
+        ModelCollection models = new SingleModelCollection(alignment);
+        for (SelectionModel model : confidenceModels) {
+            models.add(model.getModel());
+        }
+        return models;
+    }
+
+    /**
+     * Gets the SelectionModel in an specific position of the
+     * collection, sorted by this criterion value.
+     * 
+     * @param index the index
+     * 
+     * @return the SelectionModel 
+     */
+    public SelectionModel get(int index) {
+        return selectionModels.get(index);
+    }
+
+    /**
+     * Gets the SelectionModel filled with this criterion data that
+     * wraps the specified model.
+     * @see SelectionModel
+     * 
+     * @param model the model contained in the SelectionModel
+     * 
+     * @return the SelectionModel that wraps the model
+     * 
+     */
+    public SelectionModel get(Model model) {
+        return hashModels.get(model);
+    }
+
+    /**
+     * Gets the best model according with the concrete criterion.
+     * (i.e. the model with the lowest criterion value)
+     * @see SelectionModel#getValue()
+     * 
+     * @return the best model
+     */
+    public Model getBestModel() {
+        return bestModel.getModel();
+    }
+
+    /**
+     * Gets the criterion name.
+     * 
+     * @return the criterion name
+     */
+    public abstract String getCriterionName();
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/LNL.java b/src/main/java/es/uvigo/darwin/prottest/selection/LNL.java
new file mode 100755
index 0000000..d039356
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/LNL.java
@@ -0,0 +1,71 @@
+/*
+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.prottest.selection;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.model.LNLSelectionModel;
+import es.uvigo.darwin.prottest.selection.model.SelectionModel;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+
+/**
+ * The Maximum Likelihood Information Criterion.
+ */
+public class LNL extends InformationCriterion
+{
+	
+	/**
+	 * Instantiates a new Maximum Likelihood Information Criterion.
+	 * 
+	 * @param models the models
+	 * @param confidenceInterval the confidence interval
+	 * @param sampleSize the sample size if different of the default
+	 */
+	public LNL (ModelCollection models, double confidenceInterval, double sampleSize) 
+		{
+		super(models, confidenceInterval, sampleSize);
+		
+		Collections.sort(selectionModels);
+		}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.InformationCriterion#getSelectionModels(es.uvigo.darwin.prottest.util.collection.ModelIterator)
+	 */
+	protected List<SelectionModel> getSelectionModels(List<Model> models) {
+		List<SelectionModel> list = new ArrayList<SelectionModel>();
+		for (Model model : models) {
+			SelectionModel toAdd = new LNLSelectionModel(
+					model); 
+			list.add( toAdd );
+			hashModels.put(model, toAdd);
+		}
+		return list;
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.InformationCriterion#getCriterionName()
+	 */
+	public String getCriterionName() {
+		return "LnL";
+	}
+}
+
+
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/model/AICSelectionModel.java b/src/main/java/es/uvigo/darwin/prottest/selection/model/AICSelectionModel.java
new file mode 100755
index 0000000..1aba79e
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/model/AICSelectionModel.java
@@ -0,0 +1,37 @@
+/*
+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.prottest.selection.model;
+
+import es.uvigo.darwin.prottest.model.Model;
+
+/**
+ * Model wrapper including information about Akaike Information Criterion
+ */
+public class AICSelectionModel extends SelectionModel {
+
+	/**
+	 * Instantiates a new AIC selection model.
+	 * 
+	 * @param model the underlying model
+	 * @param sampleSize the sample size
+	 */
+	public AICSelectionModel(Model model, double sampleSize) {
+		super(model, sampleSize);
+		this.value = -2 * model.getLk() + 2*model.getNumberOfModelParameters(); 
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/model/AICcSelectionModel.java b/src/main/java/es/uvigo/darwin/prottest/selection/model/AICcSelectionModel.java
new file mode 100755
index 0000000..efd3395
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/model/AICcSelectionModel.java
@@ -0,0 +1,39 @@
+/*
+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.prottest.selection.model;
+
+import es.uvigo.darwin.prottest.model.Model;
+
+/**
+ * Model wrapper including information about corrected Akaike Information Criterion
+ */
+public class AICcSelectionModel extends SelectionModel {
+
+	/**
+	 * Instantiates a new AICc selection model.
+	 * 
+	 * @param model the underlying model
+	 * @param sampleSize the sample size
+	 */
+	public AICcSelectionModel(Model model, double sampleSize) {
+		super(model, sampleSize);
+		double k	= model.getNumberOfModelParameters();
+		double n	= sampleSize;
+		this.value = (-2 * model.getLk() + 2*k + 2*k*(k+1)/(n-k-1));
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/model/BICSelectionModel.java b/src/main/java/es/uvigo/darwin/prottest/selection/model/BICSelectionModel.java
new file mode 100755
index 0000000..830465c
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/model/BICSelectionModel.java
@@ -0,0 +1,37 @@
+/*
+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.prottest.selection.model;
+
+import es.uvigo.darwin.prottest.model.Model;
+
+/**
+ * Model wrapper including information about Bayesian Information Criterion
+ */
+public class BICSelectionModel extends SelectionModel {
+
+	/**
+	 * Instantiates a new BIC selection model.
+	 * 
+	 * @param model the underlying model
+	 * @param sampleSize the sample size
+	 */
+	public BICSelectionModel(Model model, double sampleSize) {
+		super(model, sampleSize);
+		this.value = -2 * model.getLk() + model.getNumberOfModelParameters() * Math.log (sampleSize);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/model/DTSelectionModel.java b/src/main/java/es/uvigo/darwin/prottest/selection/model/DTSelectionModel.java
new file mode 100755
index 0000000..d8ddf17
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/model/DTSelectionModel.java
@@ -0,0 +1,54 @@
+/*
+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.prottest.selection.model;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.BIC;
+import es.uvigo.darwin.prottest.tree.TreeDistancesCache;
+
+/**
+ * Model wrapper including information about Decision Theory Information Criterion
+ */
+public class DTSelectionModel extends SelectionModel {
+
+	/**
+	 * Instantiates a new Decision Theory selection model.
+	 * 
+	 * @param model the underlying model
+	 * @param sampleSize the sample size
+	 */
+	public DTSelectionModel(Model model, double sampleSize, BIC bic, 
+			TreeDistancesCache distancesCache) {
+		super(model, sampleSize);
+
+		double minBIC = bic.get(bic.getBestModel()).getValue();
+		double sum = 0.0;
+		for (SelectionModel selectionModel : bic.getSelectionModels()) {
+			double distance = distancesCache.getDistance(model.getTree(), selectionModel.getModel().getTree());
+			if (distance > 0) {
+				double power = Math.log(distance) - selectionModel.getValue() + minBIC;
+				if (power > -30) {
+					sum += Math.exp(power);
+				}
+			}
+		}
+
+		this.value = sum;
+	}
+	
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/model/LNLSelectionModel.java b/src/main/java/es/uvigo/darwin/prottest/selection/model/LNLSelectionModel.java
new file mode 100755
index 0000000..7975235
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/model/LNLSelectionModel.java
@@ -0,0 +1,37 @@
+/*
+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.prottest.selection.model;
+
+import es.uvigo.darwin.prottest.model.Model;
+
+/**
+ * Model wrapper including information about 
+ * Likelihood Score Selection
+ */
+public class LNLSelectionModel extends SelectionModel {
+
+	/**
+	 * Instantiates a new LnL selection model.
+	 * 
+	 * @param model the underlying model
+	 */
+	public LNLSelectionModel(Model model) {
+		super(model, 0.0);
+		this.value = -model.getLk(); 
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/model/SelectionModel.java b/src/main/java/es/uvigo/darwin/prottest/selection/model/SelectionModel.java
new file mode 100755
index 0000000..7476cc8
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/model/SelectionModel.java
@@ -0,0 +1,165 @@
+/*
+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.prottest.selection.model;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+
+/**
+ * This class provides a Model wrapper including information about a concrete
+ * model selection criterion, like AIC, BIC or corrected AIC.
+ * 
+ * @see Model
+ * @see InformationCriterion
+ */
+public abstract class SelectionModel implements Comparable<SelectionModel> {
+
+	/** The contained model. */
+	private Model model;
+	
+	/** The sample size. */
+	protected double sampleSize;
+	
+	/** The model selection absolute value. */
+	protected double value;
+	
+	/** The model selection relative weight value. */
+	private double weightValue;
+	
+	/** The model selection delta value. */
+	private double deltaValue;
+	
+	/** The cumulative weight value, in relationship to
+	 * the order of the models sorted by the model selection
+	 * criterion. */
+	private double cumulativeWeightValue;
+	
+	/** Model lays into the confidence interval */
+	private boolean inConfidenceInterval;
+	
+	/**
+	 * Gets the underlying model.
+	 * 
+	 * @return the underlyingmodel
+	 */
+	public Model getModel() { return model; }
+
+	/**
+	 * Gets the model selection criterion value.
+	 * 
+	 * @return the model selection criterion value
+	 */
+	public double getValue() {
+		return value;
+	}
+
+	/**
+	 * Gets the model selection relative weight value.
+	 * 
+	 * @return the weight value
+	 */
+	public double getWeightValue() {
+		return weightValue;
+	}
+
+	/**
+	 * Sets the model selection relative weight value.
+	 * 
+	 * @param weightValue the new weight value
+	 */
+	public void setWeightValue(double weightValue) {
+		this.weightValue = weightValue;
+	}
+
+	/**
+	 * Gets the model selection criterion delta value.
+	 * 
+	 * @return the delta value
+	 */
+	public double getDeltaValue() {
+		return deltaValue;
+	}
+
+	/**
+	 * Sets the model selection criterion delta value.
+	 * 
+	 * @param deltaValue the new delta value
+	 */
+	public void setDeltaValue(double deltaValue) {
+		this.deltaValue = deltaValue;
+	}
+
+	/**
+	 * Gets the cumulative weight value.
+	 * 
+	 * @return the cumulative weight value
+	 */
+	public double getCumulativeWeightValue() {
+		return cumulativeWeightValue;
+	}
+
+	/**
+	 * Sets the cumulative weight value.
+	 * 
+	 * @param cumulateWeightValue the new cumulative weight value
+	 */
+	public void setCumulativeWeightValue(double cumulateWeightValue) {
+		this.cumulativeWeightValue = cumulateWeightValue;
+	}
+	
+	/**
+	 * Checks if model lays into the confidence interval.
+	 * 
+	 * @return true, if is in confidence interval
+	 */
+	public boolean isInConfidenceInterval() {
+		return inConfidenceInterval;
+	}
+
+	/**
+	 * Sets the in confidence interval.
+	 * 
+	 * @param inConfidenceInterval the new in confidence interval
+	 */
+	public void setInConfidenceInterval(boolean inConfidenceInterval) {
+		this.inConfidenceInterval = inConfidenceInterval;
+	}
+
+	/**
+	 * Instantiates a new selection model.
+	 * 
+	 * @param model the underlying model
+	 * @param sampleSize the sample size
+	 */
+	public SelectionModel(Model model, double sampleSize) {
+		this.model = model;
+		this.sampleSize = sampleSize;
+	}
+	
+	/* (non-Javadoc)
+	 * @see java.lang.Comparable#compareTo(java.lang.Object)
+	 */
+	public int compareTo(SelectionModel other) {
+		if (this.value > other.value)
+			return 1;
+		else if (this.value < other.value)
+			return -1;
+		else
+			return 0;
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/model/package.html b/src/main/java/es/uvigo/darwin/prottest/selection/model/package.html
new file mode 100755
index 0000000..1354326
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/model/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains the wrapper classes for model selection.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/package.html b/src/main/java/es/uvigo/darwin/prottest/selection/package.html
new file mode 100755
index 0000000..6c73bec
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/package.html
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+This package contains all the information criteria. Every information
+criterion is implemented in two parts. At a lower level, a wrapper class
+contain the concrete substitution models plus the criterion information.
+At a higher level, classes like <code>AIC</code> or <code>BIC</code> manages
+the criterion calculation over a set of wrappers.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/printer/AminoAcidPrintFramework.java b/src/main/java/es/uvigo/darwin/prottest/selection/printer/AminoAcidPrintFramework.java
new file mode 100755
index 0000000..d6a9784
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/printer/AminoAcidPrintFramework.java
@@ -0,0 +1,68 @@
+/*
+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.prottest.selection.printer;
+
+import static es.uvigo.darwin.prottest.global.ApplicationGlobals.*;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.util.printer.ProtTestFormattedOutput;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class AminoAcidPrintFramework.
+ */
+public class AminoAcidPrintFramework extends PrintFramework {
+
+	/**
+	 * Instantiates a new amino acid print framework.
+	 */
+	public AminoAcidPrintFramework() {
+		super();
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.printer.PrintFramework#printRelativeImportance(java.io.PrintWriter)
+	 */
+	@Override
+	void printRelativeImportance(InformationCriterion ic) {
+		
+		println("***********************************************");
+		println("Relative importance of parameters");
+		println("***********************************************");
+		println("  alpha       (+G):  " + ProtTestFormattedOutput.space(3, ' ') + getDisplayValue(ic.getAlphaImportance(), PARAMETER_G, ic.isExistGammaModels()));
+		println("  p-inv       (+I):  " + ProtTestFormattedOutput.space(3, ' ') + getDisplayValue(ic.getInvImportance(), PARAMETER_I, ic.isExistInvModels()));
+		println("  alpha+p-inv (+I+G):" + ProtTestFormattedOutput.space(3, ' ') + getDisplayValue(ic.getAlphaInvImportance(), PARAMETER_IG, ic.isExistGammaInvModels()));
+		println("  freqs       (+F):  " + ProtTestFormattedOutput.space(3, ' ') + getDisplayValue(ic.getFImportance(), PARAMETER_F, ic.isExistFModels()));
+		println("");
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.selection.printer.PrintFramework#printModelAveragedEstimation(java.io.PrintWriter)
+	 */
+	@Override
+	void printModelAveragedEstimation(InformationCriterion ic) {
+		
+		println("***********************************************");
+		println("Model-averaged estimate of parameters");
+		println("***********************************************");
+		println("  alpha (+G):        " + ProtTestFormattedOutput.space(3,  ' ') + getDisplayValue(ic.getOverallAlpha(), PARAMETER_G, ic.isExistGammaModels()));
+		println("  p-inv (+I):        " + ProtTestFormattedOutput.space(3,  ' ') + getDisplayValue(ic.getOverallInv(), PARAMETER_I, ic.isExistInvModels()));
+		println("  alpha (+I+G):      " + ProtTestFormattedOutput.space(3,  ' ') + getDisplayValue(ic.getOverallAlphaInv(), PARAMETER_IG, ic.isExistGammaInvModels()));
+		println("  p-inv (+I+G):      " + ProtTestFormattedOutput.space(3,  ' ') + getDisplayValue(ic.getOverallInvAlpha(), PARAMETER_IG, ic.isExistGammaInvModels()));
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/printer/PrintFramework.java b/src/main/java/es/uvigo/darwin/prottest/selection/printer/PrintFramework.java
new file mode 100755
index 0000000..6153c08
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/printer/PrintFramework.java
@@ -0,0 +1,407 @@
+/*
+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.prottest.selection.printer;
+
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.IMPORTANCE_PRECISSION;
+
+import java.util.Collections;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.AIC;
+import es.uvigo.darwin.prottest.selection.AICc;
+import es.uvigo.darwin.prottest.selection.BIC;
+import es.uvigo.darwin.prottest.selection.DT;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.util.StatFramework;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.comparator.LKComparator;
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import es.uvigo.darwin.prottest.util.printer.ProtTestFormattedOutput;
+
+/**
+ * Utility to print application data into loggers.
+ */
+public abstract class PrintFramework {
+
+	/**
+	 * Prints the models sorted by a concrete information criterion.
+	 */
+	public final void printModelsSorted(
+			InformationCriterion informationCriterion) {
+
+		int fieldLength = 15;
+		int numberOfFields = 5;
+		int lineLength = fieldLength * numberOfFields;
+
+		Model bestModel = informationCriterion.getBestModel();
+		ModelCollection models = informationCriterion.getModelCollection();
+
+		String columns[] = new String[5];
+		columns[0] = "Model";
+		columns[1] = "delta" + informationCriterion.getCriterionName();
+		columns[2] = informationCriterion.getCriterionName();
+		columns[3] = informationCriterion.getCriterionName() + "w";
+		columns[4] = "-lnL";
+
+		println("");
+		println(ProtTestFormattedOutput.space(lineLength, '*'));
+		println("Best model according to "
+				+ informationCriterion.getCriterionName() + ": "
+				+ bestModel.getModelName());
+		double confPercent = informationCriterion.getConfidenceInterval() * 100;
+		println("Confidence Interval: " + confPercent);
+		println(ProtTestFormattedOutput.space(lineLength, '*'));
+		for (int i = 0; i < numberOfFields; i++) {
+			print(columns[i]);
+			print(ProtTestFormattedOutput.space(
+					fieldLength - columns[i].length(), ' '));
+		}
+		println("");
+		println(ProtTestFormattedOutput.space(lineLength, '-'));
+		for (Model model : models) {
+			print(model.getModelName());
+			print(ProtTestFormattedOutput.space(fieldLength
+					- model.getModelName().length(), ' '));
+
+			String decimal;
+
+			decimal = ProtTestFormattedOutput.getDecimalString(
+					informationCriterion.get(model).getDeltaValue(), 2);
+			print(decimal);
+			print(ProtTestFormattedOutput.space(fieldLength - decimal.length(),
+					' '));
+			decimal = ProtTestFormattedOutput.getDecimalString(
+					informationCriterion.get(model).getValue(), 2);
+			print(decimal);
+			print(ProtTestFormattedOutput.space(fieldLength - decimal.length(),
+					' '));
+			decimal = ProtTestFormattedOutput.getDecimalString(
+					informationCriterion.get(model).getWeightValue(), 2);
+			print(decimal);
+			print(ProtTestFormattedOutput.space(fieldLength - decimal.length(),
+					' '));
+			decimal = ProtTestFormattedOutput.getDecimalString(
+					-1 * model.getLk(), 2);
+			print(decimal);
+			print(ProtTestFormattedOutput.space(fieldLength - decimal.length(),
+					' '));
+
+			println("");
+		}
+
+		println(ProtTestFormattedOutput.space(lineLength, '-'));
+
+		println(ProtTestFormattedOutput.space(lineLength, '-'));
+
+		printRelativeImportance(informationCriterion);
+
+		printModelAveragedEstimation(informationCriterion);
+
+	}
+
+	protected static void print(String text) {
+		ProtTestLogger.getDefaultLogger().info(text);
+	}
+
+	protected static void println(String text) {
+		ProtTestLogger.getDefaultLogger().infoln(text);
+	}
+
+	/**
+	 * Prints the comparison over the 7 frameworks.
+	 */
+	public static void printFrameworksComparison(ModelCollection models) {
+
+		boolean includeI, includeG, includeIG, includeF;
+		includeI = includeG = includeIG = includeF = false;
+
+		double[] aic = new double[models.size()];
+		double[] aicc = new double[models.size()];
+		double[] bic = new double[models.size()];
+		double[] dt = new double[models.size()];
+
+		String[] modelNames = new String[models.size()];
+
+		InformationCriterion aicS = new AIC(models, 1.0, 0);
+		InformationCriterion aiccS = new AICc(models, 1.0, models.getAlignment().getSiteCount());
+		InformationCriterion bicS = new BIC(models, 1.0, models.getAlignment().getSiteCount());
+		InformationCriterion dtS = new DT(models, 1.0, models.getAlignment().getSiteCount());
+
+		Collections.sort(models, new LKComparator());
+		for (int i = 0; i < models.size(); i++) {
+			Model model = models.get(i);
+
+			includeI |= model.isInv();
+			includeG |= model.isGamma();
+			includeIG |= model.isInv() && model.isGamma();
+			includeF |= model.isPlusF();
+
+			modelNames[i] = model.getModelName();
+
+			aicc[i] = aiccS.get(model).getValue();
+			dt[i] = dtS.get(model).getValue();
+			bic[i] = bicS.get(model).getValue();
+			aic[i] = aicS.get(model).getValue();
+
+		}
+
+		StatFramework aicF, aiccF, bicF, dtF;
+		aicF = new StatFramework(aicS, "AIC", "AIC");
+		aiccF = new StatFramework(aiccS, "AICc",
+				"second-order AIC");
+		bicF = new StatFramework(bicS, "BIC", "BIC");
+		dtF = new StatFramework(dtS, "DT", "DT");
+		
+
+		// Hala, ahora a imprimir:
+		println(ProtTestFormattedOutput.space(100, '-'));
+		println("Table: Weights(Ranking) of the candidate models under the different frameworks");
+		println(ProtTestFormattedOutput.space(100, '-'));
+		println("model          AIC         AICc        BIC         DT");
+		String model__, tmp;
+		for (int i = 0; i < models.size(); i++) {
+			model__ = aicF.getModelName(i);
+			print(model__
+					+ ProtTestFormattedOutput.space(15 - model__.length(), ' '));
+			tmp = ProtTestFormattedOutput.getDecimalString(
+					aicF.getWeight(model__), 2)
+					+ "(" + aicF.getRanking(model__) + ")";
+			print(ProtTestFormattedOutput.space(0 - tmp.length(), ' ') + tmp
+					+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+			tmp = ProtTestFormattedOutput.getDecimalString(
+					aiccF.getWeight(model__), 2)
+					+ "(" + aiccF.getRanking(model__) + ")";
+			print(ProtTestFormattedOutput.space(0 - tmp.length(), ' ') + tmp
+					+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+			tmp = ProtTestFormattedOutput.getDecimalString(
+					bicF.getWeight(model__), 2)
+					+ "(" + bicF.getRanking(model__) + ")";
+			print(ProtTestFormattedOutput.space(0 - tmp.length(), ' ') + tmp
+					+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+			tmp = ProtTestFormattedOutput.getDecimalString(
+					dtF.getWeight(model__), 2)
+					+ "(" + dtF.getRanking(model__) + ")";
+			print(ProtTestFormattedOutput.space(0 - tmp.length(), ' ') + tmp
+					+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+			println("");
+		}
+		if (includeG | includeI | includeIG | includeF) {
+			println(ProtTestFormattedOutput.space(100, '-'));
+			println("Relative importance of");
+			println("parameters     AIC         AICc        BICc       DT");
+			if (includeG) {
+				print("+G" + ProtTestFormattedOutput.space(13, ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aicF.getAlphaImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aiccF.getAlphaImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						bicF.getAlphaImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						dtF.getAlphaImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				println("");
+			}
+			if (includeI) {
+				print("+I" + ProtTestFormattedOutput.space(13, ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aicF.getInvImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aiccF.getInvImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						bicF.getInvImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						dtF.getInvImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				println("");
+			}
+			if (includeIG) {
+				print("+I+G" + ProtTestFormattedOutput.space(11, ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(aicF.getGIImp(),
+						2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aiccF.getGIImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						bicF.getGIImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						dtF.getGIImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				println("");
+			}
+			if (includeF) {
+				print("+F" + ProtTestFormattedOutput.space(13, ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(aicF.getFImp(),
+						2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aiccF.getFImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						bicF.getFImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						dtF.getFImp(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				println("");
+			}
+		}
+		if (includeG | includeI | includeIG) {
+			println(ProtTestFormattedOutput.space(100, '-'));
+			println("Model-averaged estimate of");
+			println("parameters     AIC         AICc        BIC         DT");
+			if (includeG) {
+				print("alpha (+G)" + ProtTestFormattedOutput.space(5, ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aicF.getOverallAlpha(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aiccF.getOverallAlpha(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						bicF.getOverallAlpha(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						dtF.getOverallAlpha(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				println("");
+			}
+			if (includeI) {
+				print("p-inv (+I)" + ProtTestFormattedOutput.space(5, ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aicF.getOverallInv(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aiccF.getOverallInv(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						bicF.getOverallInv(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						dtF.getOverallInv(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				println("");
+			}
+			if (includeIG) {
+				print("alpha (+I+G)" + ProtTestFormattedOutput.space(3, ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aicF.getOverallAlphaGI(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aiccF.getOverallAlphaGI(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						bicF.getOverallAlphaGI(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						dtF.getOverallAlphaGI(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				println("");
+				print("p-inv (+I+G)" + ProtTestFormattedOutput.space(3, ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aicF.getOverallInvGI(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						aiccF.getOverallInvGI(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						bicF.getOverallInvGI(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				tmp = ProtTestFormattedOutput.getDecimalString(
+						dtF.getOverallInvGI(), 2);
+				print(tmp
+						+ ProtTestFormattedOutput.space(12 - tmp.length(), ' '));
+				println("");
+			}
+		}
+		println(ProtTestFormattedOutput.space(100, '-'));
+		println("AIC   : Akaike Information Criterion framework.");
+		println("AICc  : Second-Order Akaike framework.");
+		println("BIC   : Bayesian Information Criterion framework.");
+		println("DT    : Decision Theory Criterion framework.");
+		println(ProtTestFormattedOutput.space(100, '-'));
+		println("");
+	}
+
+	public static String getDisplayValue(double value, String parameter,
+			boolean existModels) {
+		String toDisplay;
+		if (existModels) {
+			toDisplay = ProtTestFormattedOutput.getDecimalString(value,
+					IMPORTANCE_PRECISSION);
+		} else {
+			toDisplay = "No " + parameter + " models";
+		}
+		return toDisplay;
+	}
+
+	/**
+	 * Prints the relative importance.
+	 * 
+	 * @param ic
+	 *            the information criterion
+	 */
+	abstract void printRelativeImportance(InformationCriterion ic);
+
+	/**
+	 * Prints the model averaged estimation.
+	 * 
+	 * @param ic
+	 *            the information criterion
+	 */
+	abstract void printModelAveragedEstimation(InformationCriterion ic);
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/selection/printer/package.html b/src/main/java/es/uvigo/darwin/prottest/selection/printer/package.html
new file mode 100755
index 0000000..95661a2
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/selection/printer/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains classes which can display selection information.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/taxa/Taxon.java b/src/main/java/es/uvigo/darwin/prottest/taxa/Taxon.java
new file mode 100755
index 0000000..ab7d3b0
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/taxa/Taxon.java
@@ -0,0 +1,164 @@
+package es.uvigo.darwin.prottest.taxa;
+
+import es.uvigo.darwin.prottest.util.attributable.AttributableHelper;
+import es.uvigo.darwin.prottest.util.attributable.Attributable;
+import es.uvigo.darwin.prottest.util.fileio.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Andrew Rambaut
+ * @author Alexei Drummond
+ *
+ * @version $Id: Taxon.java 569 2006-12-12 18:48:36Z twobeers $
+ */
+public final class Taxon implements Attributable, Comparable {
+
+    /**
+     * A private constructor. Taxon objects can only be created by the static Taxon.getTaxon()
+     * factory method.
+     * @param name the name of the taxon
+     */
+    private Taxon(String name) {
+        this(name, null);
+    }
+
+    /**
+     * A private constructor. Taxon objects can only be created by the static Taxon.getTaxon()
+     * factory method.
+     * @param name the name of the taxon
+     */
+    private Taxon(String name, TaxonomicLevel taxonomicLevel) {
+        this.name = name;
+        this.taxonomicLevel = taxonomicLevel;
+    }
+
+    /**
+     * get the name of the taxon
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * get the taxonomic level of the taxon
+     * @return the taxonomic level
+     */
+    public TaxonomicLevel getTaxonomicLevel() {
+        return taxonomicLevel;
+    }
+
+	// Attributable IMPLEMENTATION
+
+	public void setAttribute(String name, Object value) {
+		if (helper == null) {
+			helper = new AttributableHelper();
+		}
+		helper.setAttribute(name, value);
+	}
+
+	public Object getAttribute(String name) {
+		if (helper == null) {
+			return null;
+		}
+		return helper.getAttribute(name);
+	}
+
+    public void removeAttribute(String name) {
+        if( helper != null ) {
+            helper.removeAttribute(name);
+        }
+    }
+
+    public Set<String> getAttributeNames() {
+        if (helper == null) {
+            return Collections.emptySet();
+        }
+        return helper.getAttributeNames();
+    }
+
+	public Map<String, Object> getAttributeMap() {
+		if (helper == null) {
+			return Collections.emptyMap();
+		}
+		return helper.getAttributeMap();
+	}
+
+	private AttributableHelper helper = null;
+
+    // Static factory methods
+
+    /**
+     * @return a Set containing all the currently created Taxon objects.
+     */
+    public static Set<Taxon> getAllTaxa() {
+        return Collections.unmodifiableSet(new HashSet<Taxon>(taxa.values()));
+    }
+
+    /**
+     * A static method that returns a Taxon object with the given name. If this has
+     * already been created then the same instance will be returned.
+     *
+     * Due to problems with the singleton model of taxa, this factory method now
+     * creates a new instance.
+     *
+     * @param name
+     * @return the taxon
+     */
+    public static Taxon getTaxon(String name) {
+        if (name == null) {
+            throw new IllegalArgumentException("Illegal null string for taxon name");
+        }
+        if (name.length() == 0) {
+            throw new IllegalArgumentException("Illegal empty string for taxon name");
+        }
+
+        Taxon taxon = taxa.get(name);
+
+        if (taxon == null) {
+            taxon = new Taxon(name);
+            taxa.put(name, taxon);
+        }
+
+        return taxon;
+    }
+
+	// private members
+
+
+    /**
+     * The name of this taxon.
+     */
+    private final String name;
+
+    /**
+     * A hash map containing taxon name, object pairs.
+     */
+    private static Map<String, Taxon> taxa = new HashMap<String, Taxon>();
+
+    /**
+     * the taxonomic level of this taxon.
+     */
+    private final TaxonomicLevel taxonomicLevel;
+
+    public String toString() {
+        return name;
+    }
+
+	public int compareTo(Object o) {
+		return name.compareTo(((Taxon)o).getName());
+	}
+
+
+    public boolean equals(Taxon t) {
+	    return name.equals(t.getName());
+    }
+
+    public int hashCode() {
+        return name.hashCode();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/prottest/taxa/TaxonomicLevel.java b/src/main/java/es/uvigo/darwin/prottest/taxa/TaxonomicLevel.java
new file mode 100755
index 0000000..7b52ecb
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/taxa/TaxonomicLevel.java
@@ -0,0 +1,69 @@
+package es.uvigo.darwin.prottest.taxa;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author Andrew Rambaut
+ * @author Alexei Drummond
+ *
+ * @version $Id: TaxonomicLevel.java 185 2006-01-23 23:03:18Z rambaut $
+ */
+public class TaxonomicLevel {
+
+    /**
+     * A private constructor. TaxonomicLevel objects can only be created by the static TaxonomicLevel.getTaxonomicLevel()
+     * factory method.
+     * @param name the name of the taxonomic level
+     */
+    private TaxonomicLevel(String name) {
+        this.name = name;
+    }
+
+    /**
+     * get the name of the taxonomic level
+     * @return the name
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * The name of this taxonomic level
+     */
+    private final String name;
+
+    // Static factory methods
+
+    /**
+     * A static method that returns a TaxonomicLevel object with the given name. If this has
+     * already been created then the same instance will be returned.
+     * @param name the name of the taxonomic level
+     * @return the taxonomic level object
+     */
+    public static TaxonomicLevel getTaxonomicLevel(String name) {
+        TaxonomicLevel taxonomicLevel = (TaxonomicLevel)taxonomicLevels.get(name);
+
+        if (taxonomicLevel == null) {
+            taxonomicLevel = new TaxonomicLevel(name);
+            taxonomicLevels.put(name, taxonomicLevel);
+        }
+
+        return taxonomicLevel;
+    }
+
+    /**
+     * Returns a Set containing all the currently created taxonomic levels.
+     * @return the set of taxonomic levels
+     */
+    public static Set getTaxonomicLevels() {
+        return Collections.unmodifiableSet(taxonomicLevels.entrySet());
+    }
+
+    /**
+     * A hash map containing name, object pairs.
+     */
+    private static Map<String, TaxonomicLevel> taxonomicLevels = new HashMap<String, TaxonomicLevel>();
+}
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/prottest/taxa/package.html b/src/main/java/es/uvigo/darwin/prottest/taxa/package.html
new file mode 100755
index 0000000..59c5870
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/taxa/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains classes related to taxa.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/tree/TreeDistancesCache.java b/src/main/java/es/uvigo/darwin/prottest/tree/TreeDistancesCache.java
new file mode 100755
index 0000000..6b3d88d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/tree/TreeDistancesCache.java
@@ -0,0 +1,157 @@
+/*
+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.prottest.tree;
+
+import java.util.Hashtable;
+
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+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) {
+            throw new ProtTestInternalException("Unsupported distance type");
+        }
+        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 = TreeUtils.euclideanTreeDistance(t1, t2);
+                    break;
+                case ROBINSON_FOULDS:
+                    distance = TreeUtils.robinsonFouldsTreeDistance(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;
+            }
+            if (t1 == null) {
+                if (other.t1 != null) {
+                    return false;
+                }
+            } else if (!t1.equals(other.t1)) {
+                return false;
+            }
+            if (t2 == null) {
+                if (other.t2 != null) {
+                    return false;
+                }
+            } else if (!t2.equals(other.t2)) {
+                return false;
+            }
+            return true;
+        }
+
+        private TreeDistancesCache getOuterType() {
+            return TreeDistancesCache.this;
+        }
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/tree/TreeEuclideanDistancesCache.java b/src/main/java/es/uvigo/darwin/prottest/tree/TreeEuclideanDistancesCache.java
new file mode 100755
index 0000000..469c49b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/tree/TreeEuclideanDistancesCache.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.prottest.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/prottest/tree/TreeUtils.java b/src/main/java/es/uvigo/darwin/prottest/tree/TreeUtils.java
new file mode 100755
index 0000000..e87ba6b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/tree/TreeUtils.java
@@ -0,0 +1,516 @@
+/*
+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.prottest.tree;
+
+import pal.tree.Node;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.printer.ProtTestFormattedOutput;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import pal.io.FormattedOutput;
+import pal.misc.IdGroup;
+import pal.misc.Identifier;
+import pal.misc.SimpleIdGroup;
+import pal.tree.NodeUtils;
+
+/**
+ * Some utils to phylogenetic tree analysis.
+ * Based on PAL library.
+ */
+public abstract class TreeUtils {
+
+    public static final int DEFAULT_COLUMN_WIDTH = 70;
+    public static final String TREE_WEIGHT_ATTRIBUTE = "weight";
+    public static final String TREE_CLADE_SUPPORT_ATTRIBUTE = "support";
+    public static final String TREE_NAME_ATTRIBUTE = "treeName";
+
+    /**
+     * Calculates the euclidean tree distance between two trees.
+     * 
+     * @param t1 the first tree
+     * @param t2 the second tree
+     * 
+     * @return the double
+     */
+    public static double euclideanTreeDistance(Tree t1, Tree t2) {
+        double sum = 0.0;
+        int numberOfInternalNodes = t1.getInternalNodeCount();
+        if (numberOfInternalNodes != t2.getInternalNodeCount()) {
+            throw new ProtTestInternalException("Different number of internal nodes: " +
+                    t1.getInternalNodeCount() + " vs " + t2.getInternalNodeCount());
+        }
+        int numberOfExternalNodes = t1.getExternalNodeCount();
+        if (numberOfExternalNodes != t2.getExternalNodeCount()) {
+            throw new ProtTestInternalException("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);
+    }
+
+    /**
+     * Calculates the Robinson-Foulds tree distance between two trees.
+     * 
+     * @param t1 the first tree
+     * @param t2 the second tree
+     * 
+     * @return the double
+     */
+    public static double robinsonFouldsTreeDistance(Tree t1, Tree t2) {
+        return pal.tree.TreeUtils.getRobinsonFouldsDistance(t1, t2);
+    }
+
+    // 
+    /**
+     * Calculates the number of branches from node to most remote tip.
+     * 
+     * @param node the starting node
+     * 
+     * @return the node distance
+     */
+    public static int nodeDistance(final Node node) {
+        if (node.isLeaf()) {
+            return 0;
+        }
+
+        int d = 0;
+        for (int i = 0; i < node.getChildCount(); i++) {
+            Node n = node.getChild(i);
+            d = Math.max(d, nodeDistance(n));
+        }
+        return d + 1;
+    }
+
+    /**
+     * Calculates the safe node height.
+     * 
+     * @param tree the tree
+     * @param node the node
+     * 
+     * @return the height of the node
+     */
+    public static double safeNodeHeight(final Tree tree, final Node node) {
+        if (node.getNodeHeight() > 0.0) {
+            return node.getNodeHeight();
+        }
+        return TreeUtils.nodeDistance(node);
+    }
+
+    /**
+     * Make sure subtree below node has consistent heights, i.e. node height is higher than it's descendants
+     * 
+     * @param tree the tree
+     * @param node the node
+     * 
+     * @return height of node
+     */
+    public static double insureConsistency(Tree tree, Node node) {
+        double height = TreeUtils.safeNodeHeight(tree, node);
+        if (node.isLeaf()) {
+            return height;
+        } else {
+            for (int i = 0; i < node.getChildCount(); i++) {
+                Node n = node.getChild(i);
+                final double childHeight = insureConsistency(tree, n);
+                height = Math.max(height, childHeight);
+            }
+        }
+
+        node.setNodeHeight(height);
+        return height;
+    }
+
+    @Deprecated
+    public static int printNH(PrintWriter out, Tree tree,
+            boolean printLengths, boolean printInternalLabels,
+            boolean printCladeSupport) {
+        return printNH(out, tree, tree.getRoot(),
+                printLengths, printInternalLabels,
+                printCladeSupport,
+                0, true, DEFAULT_COLUMN_WIDTH);
+    }
+
+    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,
+                0, false, -1);
+
+        sw.append(';');
+        return sw.toString();
+
+    }
+
+    @Deprecated
+    public static int printNH(PrintWriter out, Tree tree, Node node,
+            boolean printLengths, boolean printInternalLabels,
+            boolean printCladeSupport,
+            int column, boolean breakLines, int colWidth) {
+
+        if (breakLines) {
+            column = breakLine(out, column, colWidth);
+        }
+
+        if (!node.isLeaf()) {
+            out.print("(");
+            column++;
+
+            for (int i = 0; i < node.getChildCount(); i++) {
+                if (i != 0) {
+                    out.print(",");
+                    column++;
+                }
+
+                column = printNH(out, tree, node.getChild(i),
+                        printLengths, printInternalLabels,
+                        printCladeSupport,
+                        column, breakLines, colWidth);
+            }
+
+            out.print(")");
+            column++;
+        }
+
+        if (!node.isRoot()) {
+            if (node.isLeaf() || printInternalLabels) {
+                if (breakLines) {
+                    column = breakLine(out, column, colWidth);
+                }
+
+                String id = node.getIdentifier().toString();
+                out.print(id);
+                column += id.length();
+            }
+
+            if (printCladeSupport) {
+                if (tree.getAttribute(node, TREE_CLADE_SUPPORT_ATTRIBUTE) != null) {
+                    double support = (Double) tree.getAttribute(node, TREE_CLADE_SUPPORT_ATTRIBUTE);
+                    column += ProtTestFormattedOutput.displayDecimal(out, support, 2);
+                }
+            }
+
+            if (printLengths) {
+                out.print(":");
+                column++;
+
+                if (breakLines) {
+                    column = breakLine(out, column, colWidth);
+                }
+
+                column += ProtTestFormattedOutput.displayDecimal(out, node.getBranchLength(), 6);
+            }
+        }
+
+        return column;
+    }
+
+    /**
+     * get list of the identifiers of the external nodes
+     *
+     * @return leaf identifier group
+     */
+    public static final IdGroup getLeafIdGroup(Tree tree) {
+        tree.createNodeList();
+
+        IdGroup labelList =
+                new SimpleIdGroup(tree.getExternalNodeCount());
+
+        for (int i = 0; i < tree.getExternalNodeCount(); i++) {
+            labelList.setIdentifier(i, tree.getExternalNode(i).getIdentifier());
+        }
+
+        return labelList;
+    }
+
+    private static int breakLine(PrintWriter out, int column, int colWidth) {
+        if (column > colWidth) {
+            out.println();
+            column = 0;
+        }
+
+        return column;
+    }
+
+    // Print picture of current tree in ASCII
+    public static void printASCII(Tree tree, PrintWriter out) {
+        FormattedOutput format = FormattedOutput.getInstance();
+
+        tree.createNodeList();
+
+        int numExternalNodes = tree.getExternalNodeCount();
+        int numInternalNodes = tree.getInternalNodeCount();
+        int numBranches = numInternalNodes + numExternalNodes - 1;
+
+        boolean[] umbrella = new boolean[numExternalNodes];
+        int[] position = new int[numExternalNodes];
+
+        int minLength = (Integer.toString(numBranches)).length() + 1;
+
+        int MAXCOLUMN = 40;
+        Node root = tree.getRoot();
+        if (root.getNodeHeight() == 0.0) {
+            NodeUtils.lengths2Heights(root);
+        }
+        double proportion = (double) MAXCOLUMN / root.getNodeHeight();
+
+        for (int n = 0; n < numExternalNodes; n++) {
+            umbrella[n] = false;
+        }
+
+        position[0] = 1;
+        for (int i = root.getChildCount() - 1; i > -1; i--) {
+            printNodeInASCII(out, root.getChild(i), 1, i, root.getChildCount(),
+                    numExternalNodes, umbrella, position, proportion, minLength);
+            if (i != 0) {
+                putCharAtLevel(out, 0, '|', position);
+                out.println();
+            }
+        }
+    }
+
+    private static void printNodeInASCII(PrintWriter out, Node node, int level, int m, int maxm,
+            int numExternalNodes, boolean[] umbrella, int[] position, double proportion, int minLength) {
+        position[level] = (int) (node.getBranchLength() * proportion);
+
+        if (position[level] < minLength) {
+            position[level] = minLength;
+        }
+
+        if (node.isLeaf()) // external branch
+        {
+            if (m == maxm - 1) {
+                umbrella[level - 1] = true;
+            }
+
+            printlnNodeWithNumberAndLabel(out, node, level, numExternalNodes, umbrella, position);
+
+            if (m == 0) {
+                umbrella[level - 1] = false;
+            }
+        } else // internal branch
+        {
+            for (int n = node.getChildCount() - 1; n > -1; n--) {
+                printNodeInASCII(out, node.getChild(n), level + 1, n, node.getChildCount(),
+                        numExternalNodes, umbrella, position, proportion, minLength);
+
+                if (m == maxm - 1 && n == node.getChildCount() / 2) {
+                    umbrella[level - 1] = true;
+                }
+
+                if (n != 0) {
+                    if (n == node.getChildCount() / 2) {
+                        printlnNodeWithNumberAndLabel(out, node, level, numExternalNodes, umbrella, position);
+                    } else {
+                        for (int i = 0; i < level + 1; i++) {
+                            if (umbrella[i]) {
+                                putCharAtLevel(out, i, '|', position);
+                            } else {
+                                putCharAtLevel(out, i, ' ', position);
+                            }
+                        }
+                        out.println();
+                    }
+                }
+
+                if (m == 0 && n == node.getChildCount() / 2) {
+                    umbrella[level - 1] = false;
+                }
+            }
+        }
+    }
+
+    private static void printlnNodeWithNumberAndLabel(PrintWriter out, Node node, int level,
+            int numExternalNodes, boolean[] umbrella, int[] position) {
+        for (int i = 0; i < level - 1; i++) {
+            if (umbrella[i]) {
+                putCharAtLevel(out, i, '|', position);
+            } else {
+                putCharAtLevel(out, i, ' ', position);
+            }
+        }
+
+        putCharAtLevel(out, level - 1, '+', position);
+
+        int branchNumber;
+        if (node.isLeaf()) {
+            branchNumber = node.getNumber() + 1;
+        } else {
+            branchNumber = node.getNumber() + 1 + numExternalNodes;
+        }
+
+        String numberAsString = Integer.toString(branchNumber);
+
+        int numDashs = position[level] - numberAsString.length();
+
+//        String cladeSupport = "";
+//        if (node instanceof AttributeNode && ((AttributeNode)node).getAttribute(TreeUtils.TREE_CLADE_SUPPORT_ATTRIBUTE) != null) {
+//            double cladeSupportValue = (Double) ((AttributeNode)node).getAttribute(TreeUtils.TREE_CLADE_SUPPORT_ATTRIBUTE);
+//            cladeSupport = ProtTestFormattedOutput.getDecimalString(cladeSupportValue, 1);
+//        }
+//
+//        numDashs -= cladeSupport.length();
+        
+        for (int i = 0; i < numDashs ; i++) {
+            out.print('-');
+        }
+        out.print(numberAsString);
+
+        if (node.isLeaf()) {
+            out.println(" " + node.getIdentifier());
+        } else {
+            if (!node.getIdentifier().equals(Identifier.ANONYMOUS)) {
+                out.print("(" + node.getIdentifier() + ")");
+            }
+            out.println();
+        }
+    }
+
+    private static void putCharAtLevel(PrintWriter out, int level, char c,
+            int[] position) {
+        int n = position[level] - 1;
+        for (int i = 0; i < n; i++) {
+            out.print(' ');
+        }
+        out.print(c);
+    }
+
+    public static void printBranchInfo(Tree tree, PrintWriter out) {
+
+        //
+        // CALL PRINTASCII FIRST !!!
+        //
+
+        // check if some SE values differ from the default zero
+
+        int numExternalNodes = tree.getExternalNodeCount();
+        int numInternalNodes = tree.getInternalNodeCount();
+        int numBranches = numBranches = numInternalNodes + numExternalNodes - 1;
+
+        boolean showSE = false;
+        for (int i = 0; i < numExternalNodes && showSE == false; i++) {
+            if (tree.getExternalNode(i).getBranchLengthSE() != 0.0) {
+                showSE = true;
+            }
+            if (i < numInternalNodes - 1) {
+                if (tree.getInternalNode(i).getBranchLengthSE() != 0.0) {
+                    showSE = true;
+                }
+            }
+        }
+
+        ProtTestFormattedOutput.displayIntegerWhite(out, numExternalNodes);
+        out.print("   Length    ");
+        if (showSE) {
+            out.print("S.E.      ");
+        }
+        out.print("Label     ");
+        if (numInternalNodes > 1) {
+            ProtTestFormattedOutput.displayIntegerWhite(out, numBranches);
+            out.print("        Length    ");
+            if (showSE) {
+                out.print("S.E.      ");
+            }
+            out.print("Label");
+        }
+        out.println();
+
+        for (int i = 0; i < numExternalNodes; i++) {
+            ProtTestFormattedOutput.displayInteger(out, i + 1, numExternalNodes);
+            out.print("   ");
+            ProtTestFormattedOutput.displayDecimal(out, tree.getExternalNode(i).getBranchLength(), 5);
+            out.print("   ");
+            if (showSE) {
+                ProtTestFormattedOutput.displayDecimal(out, tree.getExternalNode(i).getBranchLengthSE(), 5);
+                out.print("   ");
+            }
+            ProtTestFormattedOutput.displayLabel(out, tree.getExternalNode(i).getIdentifier().getName(), 10);
+
+            if (i < numInternalNodes - 1) {
+                ProtTestFormattedOutput.multiplePrint(out, ' ', 5);
+                ProtTestFormattedOutput.displayInteger(out, i + 1 + numExternalNodes, numBranches);
+                out.print("   ");
+                ProtTestFormattedOutput.displayDecimal(out, tree.getInternalNode(i).getBranchLength(), 5);
+                out.print("   ");
+                if (showSE) {
+                    ProtTestFormattedOutput.displayDecimal(out, tree.getInternalNode(i).getBranchLengthSE(), 5);
+                    out.print("   ");
+                }
+                ProtTestFormattedOutput.displayLabel(out, tree.getInternalNode(i).getIdentifier().getName(), 10);
+            }
+
+            out.println();
+        }
+    }
+
+    // Print height information
+    public static void heightInfo(Tree tree, PrintWriter out) {
+
+        int numExternalNodes = tree.getExternalNodeCount();
+        int numInternalNodes = tree.getInternalNodeCount();
+        int numBranches = numExternalNodes + numInternalNodes - 1;
+
+        if (tree.getRoot().getNodeHeight() == 0.0) {
+            NodeUtils.lengths2Heights(tree.getRoot());
+        }
+
+        ProtTestFormattedOutput.displayIntegerWhite(out, numExternalNodes);
+        out.print("   Height    ");
+        ProtTestFormattedOutput.displayIntegerWhite(out, numBranches);
+        out.print("        Height    ");
+
+        out.println();
+
+        for (int i = 0; i < numExternalNodes; i++) {
+            ProtTestFormattedOutput.displayInteger(out, i + 1, numExternalNodes);
+            out.print("   ");
+            ProtTestFormattedOutput.displayDecimal(out, tree.getExternalNode(i).getNodeHeight(), 7);
+            out.print("   ");
+
+            if (i < numInternalNodes) {
+                ProtTestFormattedOutput.multiplePrint(out, ' ', 5);
+
+                if (i == numInternalNodes - 1) {
+                    out.print("R");
+                    ProtTestFormattedOutput.multiplePrint(out, ' ', Integer.toString(numBranches).length() - 1);
+                } else {
+                    ProtTestFormattedOutput.displayInteger(out, i + 1 + numExternalNodes, numBranches);
+                }
+
+                out.print("   ");
+                ProtTestFormattedOutput.displayDecimal(out, tree.getInternalNode(i).getNodeHeight(), 7);
+                out.print("   ");
+            }
+
+            out.println();
+        }
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/tree/WeightedTree.java b/src/main/java/es/uvigo/darwin/prottest/tree/WeightedTree.java
new file mode 100755
index 0000000..f0c2fa2
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/tree/WeightedTree.java
@@ -0,0 +1,60 @@
+/*
+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.prottest.tree;
+
+import pal.tree.Tree;
+
+/**
+ *  This class represents a weighted PAL Tree
+ * 
+ * @author diego
+ */
+public class WeightedTree {
+
+    /** The tree. */
+    private Tree tree;
+    /** The weight. */
+    private double weight;
+
+    public Tree getTree() {
+        return tree;
+    }
+
+    public void setTree(Tree tree) {
+        this.tree = tree;
+    }
+
+    public double getWeight() {
+        return weight;
+    }
+
+    public void setWeight(double weight) {
+        this.weight = weight;
+    }
+
+    /**
+     * Instantiates a new weighted tree.
+     *
+     * @param tree the tree
+     * @param weight the weight
+     */
+    public WeightedTree(Tree tree, double weight) {
+        this.tree = tree;
+        this.weight = weight;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/tree/package.html b/src/main/java/es/uvigo/darwin/prottest/tree/package.html
new file mode 100755
index 0000000..b611f0d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/tree/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains utilites to manage phylogenetic trees.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/FixedBitSet.java b/src/main/java/es/uvigo/darwin/prottest/util/FixedBitSet.java
new file mode 100755
index 0000000..d2c8c67
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/FixedBitSet.java
@@ -0,0 +1,268 @@
+package es.uvigo.darwin.prottest.util;
+
+import java.util.Arrays;
+
+/**
+ * A bit-set of fixed size. Size is determined on creation.
+ *
+ * @author Joseph Heled
+ * @version $Id: FixedBitSet.java 591 2006-12-21 02:39:18Z pepster $
+ */
+public class FixedBitSet implements Comparable<FixedBitSet> {
+    int[] bits;
+    int size;
+    //private int intSize = Integer.SIZE;
+
+    private final static int ADDRESS_BITS_PER_UNIT = 5;
+    private final static int BITS_PER_UNIT = 1 << ADDRESS_BITS_PER_UNIT;
+    private final static int BIT_INDEX_MASK = BITS_PER_UNIT - 1;
+
+
+    private static int unitIndex(int bitIndex) {
+        return bitIndex >> ADDRESS_BITS_PER_UNIT;
+    }
+
+    private int countBits(int b) {
+        int sum = 0;
+
+        while (b != 0) {
+            // remove most significant bit
+            b = b & (b - 1);
+            ++sum;
+        }
+        return sum;
+    }
+
+    /**
+     * Given a bit index, return a unit that masks that bit in its unit.
+     * @return the mask
+     */
+    private static int bit(int bitIndex) {
+        return 1 << (bitIndex & BIT_INDEX_MASK);
+    }
+
+    public FixedBitSet(int size) {
+        this.size = size;
+        bits = new int[(unitIndex(size - 1) + 1)];
+    }
+
+    public FixedBitSet(FixedBitSet bs) {
+        bits = bs.bits.clone();
+        size = bs.size;
+    }
+
+
+    public void set(int position) {
+        int unitIndex = unitIndex(position);
+        bits[unitIndex] |= bit(position);
+    }
+
+    public void clear(int position) {
+        int unitIndex = unitIndex(position);
+        bits[unitIndex] &= ~bit(position);
+    }
+
+    /**
+     * @param bitset
+     * @return true if bitset contains this set (this <= bitset)
+     */
+    public boolean setInclusion(final FixedBitSet bitset) {
+        for (int k = 0; k < bits.length; ++k) {
+            if (bits[k] != (bits[k] & bitset.bits[k])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void union(FixedBitSet b) {
+        for (int k = 0; k < Math.min(bits.length, b.bits.length); ++k) {
+            bits[k] |= b.bits[k];
+        }
+    }
+
+    public void intersect(FixedBitSet b) {
+        for (int k = 0; k < Math.min(bits.length, b.bits.length); ++k) {
+            bits[k] &= b.bits[k];
+        }
+    }
+
+    public void setMinus(FixedBitSet b) {
+        for (int k = 0; k < Math.min(bits.length, b.bits.length); ++k) {
+            bits[k] &= ~b.bits[k];
+        }
+    }
+
+    public int intersectCardinality(FixedBitSet b) {
+        int c = 0;
+        for (int k = 0; k < Math.min(bits.length, b.bits.length); ++k) {
+            c += countBits(bits[k] & b.bits[k]);
+        }
+        return c;
+    }
+
+    public static FixedBitSet complement(FixedBitSet b) {
+        FixedBitSet t = new FixedBitSet(b);
+        t.complement();
+        return t;
+    }
+
+    public void complement() {
+        int k;
+        for (k = 0; k < bits.length - 1; ++k) {
+            bits[k] = ~ bits[k];
+        }
+
+        bits[k] = ~bits[k];
+        // reset all higher order bits
+        final int mask = bit(size) - 1;
+        if( mask != 0 ) {
+            bits[k] &= mask;
+        }
+    }
+
+    private final static byte firstBitLocation[] = {
+            -1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
+            4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
+
+    private int firstOnBit(int i) {
+        for (int k = 0; k < 4; ++k) {
+            char b = (char) (i & 0xff);
+            if (b != 0) {
+                return 8 * k + firstBitLocation[b];
+            }
+            i = i >> 8;
+        }
+        return -1;
+    }
+
+    /**
+     * Iteration helper. A typical iteration on set bits might be
+     * FixedBitSet b;
+     * for(int i = b.nextOnBit(0); i >= 0; i = b.nextOnBit(i+1)) ...
+     *
+     * @param fromIndex
+     * @return Next set member whose index is >= fromIndex. -1 if none.
+     */
+    public int nextOnBit(int fromIndex) {
+        int u = unitIndex(fromIndex);
+        int testIndex = (fromIndex & BIT_INDEX_MASK);
+        int unit = bits[u] >> testIndex;
+
+        if (unit == 0) {
+            testIndex = 0;
+
+            while ((unit == 0) && (u < bits.length - 1))
+                unit = bits[++u];
+        }
+
+        if (unit == 0)
+            return -1;
+
+        testIndex += firstOnBit(unit);
+        return ((u * BITS_PER_UNIT) + testIndex);
+    }
+
+    public int cardinality() {
+        int sum = 0;
+        for (int b : bits) {
+            sum += countBits(b);
+        }
+        return sum;
+    }
+
+    public boolean contains(final int i) {
+        final int unitIndex = unitIndex(i);
+        return (bits[unitIndex] & bit(i)) != 0;
+    }
+
+    @Override
+    public int hashCode() {
+        int code = 0;
+
+        for (int bit : bits) {
+            code = code ^ bit;
+        }
+        return code;
+    }
+
+    @Override
+    public boolean equals(Object x) {
+        if (x instanceof FixedBitSet) {
+            final FixedBitSet b = (FixedBitSet) x;
+
+            return b.size == size && Arrays.equals(bits, b.bits);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder rep = new StringBuilder();
+        rep.append("{");
+        for (int b = 0; b < size; ++b) {
+            if (contains(b)) {
+                if (rep.length() > 0) {
+                    rep.append("," + b);
+                } else {
+                    rep.append("" + b);
+                }
+            }
+        }
+        rep.append("}");
+        return rep.toString();
+    }
+    
+    public String splitRepresentation() {
+        StringBuilder rep = new StringBuilder();
+        for (int b = 0; b < size; ++b) {
+            if (contains(b)) {
+                rep.append("*");
+            }
+            else {
+                rep.append("-");
+            }
+        }
+        return rep.toString();
+    }
+
+    public int compareTo(FixedBitSet fbs) {
+        int minSize;
+        int defaultValue;
+        if (size < fbs.size) {
+            minSize = size;
+            defaultValue = -1;
+        } else {
+            minSize = fbs.size;
+            if (size == fbs.size)
+                defaultValue = 0;
+            else
+                defaultValue = 1;
+        }
+        
+        for (int i = 0; i < minSize; i++) {
+            if (this.contains(i) && !fbs.contains(i)) {
+                return -1;
+            }
+            if (!this.contains(i) && fbs.contains(i)) {
+                return 1;
+            }
+        }
+        return defaultValue;
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/ProtTestAlignment.java b/src/main/java/es/uvigo/darwin/prottest/util/ProtTestAlignment.java
new file mode 100755
index 0000000..5f176e3
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/ProtTestAlignment.java
@@ -0,0 +1,177 @@
+/*
+Copyright (C) 2009  Diego Darriba, Federico Abascal
+
+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.prottest.util;
+
+import static es.uvigo.darwin.prottest.global.ApplicationGlobals.*;
+
+import java.io.PrintWriter;
+
+import pal.alignment.Alignment;
+import es.uvigo.darwin.prottest.util.printer.ProtTestFormattedOutput;
+
+/**
+ * The Class ProtTestAlignment provides some operations about Alignment, as
+ * could be the empirical frequencies or the sample size calculation.
+ * 
+ * @author Federico Abascal
+ * @author Diego Darriba
+ * @since 3.0
+ */
+public abstract class ProtTestAlignment {
+
+	/**
+	 * Calculate sample size.
+	 * 
+	 * @param alignment
+	 *            the alignment to calculate sample size
+	 * @return the sample size
+	 */
+	public static double calculateSampleSize(Alignment alignment) {
+		// For AICc and BIC frameworks
+		return alignment.getSiteCount();
+	}
+
+	/**
+	 * Calculate invariable sites.
+	 * 
+	 * @param alignment
+	 *            the alignment
+	 * @param verbose
+	 *            the verbose
+	 * 
+	 * @return the int
+	 */
+	public static int calculateInvariableSites(Alignment alignment,
+			boolean verbose) {
+		// 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++;
+		}
+		if (verbose)
+			System.out.println("Observed number of invariant sites: " + inv);
+		return inv;
+	}
+
+	/**
+	 * Gets the frequencies.
+	 * 
+	 * @param alignment
+	 *            the alignment
+	 * 
+	 * @return the frequencies
+	 */
+	public static double[] getFrequencies(Alignment alignment) {
+		int numSites = alignment.getSiteCount();
+		int numSeqs = alignment.getSequenceCount();
+		double freqs[] = new double[AMINOACID_NUM_STATES];
+		int aas[] = new int[AMINOACID_NUM_STATES];
+		int total_aas = 0;
+		for (int i = 0; i < AMINOACID_NUM_STATES; i++)
+			aas[i] = 0;
+
+		for (int i = 0; i < numSites; i++)
+			for (int j = 0; j < numSeqs; j++) {
+				int index = indexOfChar(alignment.getData(j, i));
+				if (index >= 0) {
+					aas[index]++;
+					total_aas++;
+				}
+			}
+
+		for (int i = 0; i < AMINOACID_NUM_STATES; i++)
+			freqs[i] = (double) aas[i] / (double) total_aas;
+
+		return freqs;
+	}
+
+	/**
+	 * Prints the frequencies.
+	 * 
+	 * @param freqs
+	 *            the freqs
+	 * @param out
+	 *            the out
+	 */
+	public static void printFrequencies(double[] freqs, PrintWriter out) {
+
+		out.println("Observed aminoacid frequencies:");
+		for (int i = 0; i < AMINOACID_NUM_STATES; i++) {
+			char aa = charOfIndex(i);
+			out.print(" " + aa + ": "
+					+ ProtTestFormattedOutput.getDecimalString(freqs[i], 3)
+					+ "   ");
+			if ((i + 1) % 5 == 0)
+				out.println("");
+		}
+	}
+
+	/**
+	 * Char of index.
+	 * 
+	 * @param c
+	 *            the c
+	 * 
+	 * @return the char
+	 */
+	public static char charOfIndex(int c) {
+		char[] charSet = { 'A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L',
+				'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'Y' };
+		if (c >= 0 && c <= charSet.length)
+			return charSet[c];
+		else {
+			return '?';
+		}
+	}
+
+	/**
+	 * Index of char.
+	 * 
+	 * @param c
+	 *            the c
+	 * 
+	 * @return the int
+	 */
+	private static int indexOfChar(char c) {
+		char[] charSet = { 'A', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L',
+				'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'Y' };
+		for (int charIndex = 0; charIndex < charSet.length; charIndex++)
+			if (charSet[charIndex] == c)
+				return charIndex;
+
+		return -1;
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/StatFramework.java b/src/main/java/es/uvigo/darwin/prottest/util/StatFramework.java
new file mode 100755
index 0000000..e6527cd
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/StatFramework.java
@@ -0,0 +1,141 @@
+/*
+Copyright (C) 2004  Federico Abascal
+
+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.prottest.util;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.selection.model.SelectionModel;
+
+public class StatFramework {
+        //recibe los delta.
+        //ordena los datos y calcula los pesos
+        //guarda las cosas en un hash
+        //implementa métodos para dar el ranking y el peso a partir del String modelName
+        //implementa métodos para dar el modelName y el peso a partir del ranking
+    
+    private HashMap<String, Integer> hashSorted;          //clave: nombre modelo, valor: ranking
+    private HashMap<Integer, String> hashSortedReverse;   //clave: raking,        valor: nombre
+    private HashMap<String, Double> hashWeights;          //clave: nombre modelo, valor: peso
+    private HashMap<String, Double> hashDeltas;           //clave: nombre modelo, valor delta
+    private String    framework;
+    private String    description;
+    private double    alphaImp       = 0.0;
+    private double    invImp         = 0.0;
+    private double    GIImp          = 0.0;
+    private double    FImp           = 0.0;
+    private double    overallAlpha   = 0.0;
+    private double    overallInv     = 0.0;
+    private double    overallAlphaGI = 0.0;
+    private double    overallInvGI   = 0.0;
+    private String[]  names;
+    
+    public StatFramework (InformationCriterion ic, String framework, String description) {
+        this.framework     = framework;
+        this.description   = description;
+        alphaImp           = ic.getAlphaImportance();//calculateAlphaImp    (ic, false);
+        invImp             = ic.getInvImportance(); //calculateInvImp      (ic, false);
+        GIImp              = ic.getAlphaInvImportance();//calculateAlphaImp    (ic, true );
+        FImp               = ic.getFImportance();//calculateFImp        (ic);
+        overallAlpha       = ic.getOverallAlpha();//calculateOverallAlpha(ic, false);
+        overallInv         = ic.getOverallInv();//calculateOverallInv  (ic, false);
+        overallAlphaGI     = ic.getOverallAlphaInv();//calculateOverallAlpha(ic, true );
+        overallInvGI       = ic.getOverallInvAlpha();//calculateOverallInv  (ic, true );
+        initHashes         (ic, names);
+    }
+    
+    private void initHashes (InformationCriterion ic, String[] names) {
+        hashSorted        = new HashMap<String, Integer>(); //clave: nombre modelo, valor ranking
+        hashSortedReverse = new HashMap<Integer, String>(); //clave: raking, valor: nombre
+        hashWeights       = new HashMap<String, Double>(); //clave: nombre modelo, valor peso
+        hashDeltas        = new HashMap<String, Double>(); //clave: nombre modelo, valor delta
+        Iterator<SelectionModel> selectionModels = ic.allIterator();
+        int position = 0;
+        while (selectionModels.hasNext()) {
+        	SelectionModel model = selectionModels.next();
+        	hashSorted.put       (model.getModel().getModelName(),  new Integer(position));
+            hashSortedReverse.put(new Integer(position),model.getModel().getModelName());
+            hashWeights.put      (model.getModel().getModelName(),  new Double(model.getWeightValue()));
+            hashDeltas.put       (model.getModel().getModelName(),  new Double(model.getDeltaValue()));
+            position++;
+        }
+    }
+    
+    public int getRanking (String modelName) {
+        return hashSorted.get(modelName).intValue()+1;
+    }
+    
+    public double getWeight (String modelName) {
+        return hashWeights.get(modelName).doubleValue();
+    }
+    
+    public double getDelta (String modelName) {
+        return hashDeltas.get(modelName).doubleValue();
+    }
+    
+    public String getModelName (int ranking) {
+        return hashSortedReverse.get(new Integer(ranking));
+    }
+    
+    public String getFramework () {
+        return framework;
+    } 
+
+    public String getDescription () {
+        return description;
+    }
+
+	public double getAlphaImp() {
+		return alphaImp;
+	}
+
+	public double getInvImp() {
+		return invImp;
+	}
+
+	public double getGIImp() {
+		return GIImp;
+	}
+
+	public double getFImp() {
+		return FImp;
+	}
+
+	public double getOverallAlpha() {
+		return overallAlpha;
+	}
+
+	public double getOverallInv() {
+		return overallInv;
+	}
+
+	public double getOverallAlphaGI() {
+		return overallAlphaGI;
+	}
+
+	/**
+	 * Gets the overall inv gi.
+	 * 
+	 * @return the overall inv gi
+	 */
+	public double getOverallInvGI() {
+		return overallInvGI;
+	}
+    
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/Utilities.java b/src/main/java/es/uvigo/darwin/prottest/util/Utilities.java
new file mode 100755
index 0000000..d2a7a71
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/Utilities.java
@@ -0,0 +1,299 @@
+/*
+Copyright (C) 2004  Federico Abascal
+
+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.prottest.util;
+
+import java.net.URL;
+import java.util.StringTokenizer;
+
+/**
+ * The Class Utilities.
+ */
+public class Utilities {
+	
+    /**
+     * Instantiates a new utilities.
+     */
+    public Utilities() {    }
+    
+    /**
+     * Last token.
+     * 
+     * @param str the str
+     * 
+     * @return the string
+     */
+    public static String lastToken (String str) {
+        StringTokenizer st = new StringTokenizer(str);
+        String token = "";
+        while (st.hasMoreTokens()) {
+            token = st.nextToken();
+        }
+        return token;    
+    }
+
+    /**
+     * Next token.
+     *
+     * @param str the string
+     * @param previousToken the previous token
+     *
+     * @return the next token
+     */
+    public static String nextToken (String str, String previousToken) {
+        StringTokenizer st = new StringTokenizer(str);
+        String token = "";
+        while (st.hasMoreTokens()) {
+            token = st.nextToken();
+            if (token.equals(previousToken))
+                return st.nextToken();
+        }
+        return null;
+    }
+    
+    /**
+     * Checks if is windows.
+     * 
+     * @return true, if is windows
+     */
+    public static boolean isWindows () {
+        if(System.getProperty("os.name").startsWith("Window"))
+            return true;
+        return false;
+    }
+    
+    /**
+     * Gets the average.
+     * 
+     * @param meassures the meassures
+     * 
+     * @return the average
+     */
+    public static long getAverage(long[] meassures) {
+    	double avg = 0;
+    	for (long value : meassures)
+    		avg += value;
+    	avg /= meassures.length;
+    	return Math.round(avg);
+    }
+    
+    /**
+     * Gets the max.
+     * 
+     * @param meassures the meassures
+     * 
+     * @return the max
+     */
+    public static long getMax(long[] meassures) {
+    	long max = Long.MIN_VALUE;
+    	for (long value : meassures) {
+    		if (value > max)
+    			max = value;
+    	}
+    	return max;	
+    }
+    
+    /**
+     * Gets the min.
+     * 
+     * @param meassures the meassures
+     * 
+     * @return the min
+     */
+    public static long getMin(long[] meassures) {
+    	long min = Long.MAX_VALUE;
+    	for (long value : meassures) {
+    		if (value < min)
+    			min = value;
+    	}
+    	return min;	
+    }
+    
+    /**
+     * Arrange runtime.
+     * 
+     * @param runTime the run time
+     * 
+     * @return the string
+     */
+    public static String arrangeRuntime(long runTime) {
+		long seconds = (long) Math.round(runTime/1000.0);
+		int  hours   = (int ) (seconds/(60.0*60.0));
+		int  rest1   = (int ) (seconds%(60.0*60.0));
+		int  minutes = (int ) (rest1/60.0);
+		seconds      = (int ) (seconds - (hours*60*60 + 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 + "";
+    }
+    
+    /**
+     * Calculate runtime.
+     * 
+     * @param startTime the start time
+     * @param endTime the end time
+     * 
+     * @return the string
+     */
+    public static String calculateRuntime(long startTime, long endTime) {
+        return arrangeRuntime(endTime - startTime);
+    }
+
+    /**
+     * Gets the path.
+     * 
+     * @return the path
+     */
+    public static String getPath () {
+        return (new Utilities()).internalGetPath(false);
+    }
+    
+    /**
+     * Gets the uRL path.
+     * 
+     * @return the uRL path
+     */
+    public static String getURLPath () {
+        return (new Utilities()).internalGetPath(true);
+    }
+    
+    /**
+     * Internal get path.
+     * 
+     * @param withFile the with file
+     * 
+     * @return the string
+     */
+    private String internalGetPath (boolean withFile) {
+        //ClassLoader loader = this.getClass().getClassLoader();
+        //URL tmp = loader.getResource("./");
+        String j   = null;
+        URL    tmp = null;
+        try {
+            //tmp = XProtTest.class.getResource("");
+            tmp = getClass().getResource("");
+        } catch (Exception e) {
+            System.err.println(e);
+            e.printStackTrace();
+            return null;
+        }
+        if(tmp == null) {
+            System.err.println("***************************************************************");
+            System.err.println("** ERROR: Cannot find ProtTest's path, unable to run phyml!! **");
+            System.err.println("***************************************************************");
+            //prottest.setValue(-1);
+            return null;
+        } else {
+            j = tmp.getPath();
+            j = replace(j, "%20", " ");
+            //j = tmp.getPath().replaceAll("%20", " ");
+			//System.err.println("j: " + j);
+            if(!withFile) {
+                if(isWindows())
+                    j = replace(j, "file:/", "");
+                else
+                    j = replace(j, "file:" , "");
+            }
+            //j = Pattern.compile("file:").matcher(j).replaceFirst("");
+			//j = j.replaceFirst("file:", "");
+			//System.err.println("after replaceFirst:  " + j);
+            //j = Pattern.compile("!.*$").matcher(j).replaceFirst("");
+            int last2 = j.lastIndexOf("!");
+            j = j.substring(0, last2);
+			//j = j.replaceFirst("!.*$", "");
+			//System.err.println("after replaceFirst2: " + j);
+			int last =  j.lastIndexOf("/");
+			//j = j.replaceFirst("/.*?.jar$", "");
+			j = j.substring(0, last);
+			//System.err.println("after replaceFirst3: " + j);
+        }
+        return j;
+    }
+    
+    /**
+     * Quote it.
+     * 
+     * @param orig the orig
+     * 
+     * @return the string
+     */
+    public static String quoteIt (String orig) {
+        //quote spaces (or other characters) of filenames:
+        String result = replace(orig, " "  , "\\ ");
+        //orig = replace(orig, "\\\\ ", "\\ ");
+        return result;
+    }
+
+    //I took this method from SkeetUtil ( http://www.yoda.arachsys.com/java/skeetutil/ )
+    /**
+     * Replace.
+     * 
+     * @param orig the orig
+     * @param from the from
+     * @param to the to
+     * 
+     * @return the string
+     */
+    public static String replace (String orig, String from, String to) {
+        int fromLength = from.length();
+        
+        if (fromLength==0)
+            throw new IllegalArgumentException 
+            ("String to be replaced must not be empty");
+        
+        int start = orig.indexOf (from);
+        if (start==-1)
+            return orig;
+        
+        boolean greaterLength = (to.length() >= fromLength);
+        
+        StringBuffer buffer;
+        // If the "to" parameter is longer than (or
+        // as long as) "from", the final length will
+        // be at least as large
+        if (greaterLength) {
+            if (from.equals (to))
+                return orig;
+            buffer = new StringBuffer(orig.length());
+        }
+        else {
+            buffer = new StringBuffer();
+        }
+        
+        char [] origChars = orig.toCharArray();
+        
+        int copyFrom=0;
+        while (start != -1) {
+            buffer.append (origChars, copyFrom, start-copyFrom);
+            buffer.append (to);
+            copyFrom=start+fromLength;
+            start = orig.indexOf (from, copyFrom);
+        }
+        buffer.append (origChars, copyFrom, origChars.length-copyFrom);
+        
+        return buffer.toString();
+    }
+    
+    public static double round(double value, int decimals) {
+        return (Math.round(value * Math.pow(10, decimals)))/Math.pow(10, decimals);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/WriterOutputStream.java b/src/main/java/es/uvigo/darwin/prottest/util/WriterOutputStream.java
new file mode 100755
index 0000000..4e1e4e9
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/WriterOutputStream.java
@@ -0,0 +1,87 @@
+// ========================================================================
+// Copyright (c) 1999 Mort Bay Consulting (Australia) Pty. Ltd.
+// $Id: WriterOutputStream.java,v 1.1 2003/02/13 22:39:19 mpowers Exp $
+// ========================================================================
+
+package es.uvigo.darwin.prottest.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+
+/* ------------------------------------------------------------ */
+/** Wrap a Writer as an OutputStream.
+ * When all you have is a Writer and only an OutputStream will do.
+ * Try not to use this as it indicates that your design is a dogs
+ * breakfast (JSP made me write it).
+ * @version 1.0 Tue Feb 12 2002
+ * @author Greg Wilkins (gregw)
+ */
+public class WriterOutputStream extends OutputStream
+{
+    protected Writer _writer;
+    protected String _encoding;
+    private byte[] _buf=new byte[1];
+    
+    /* ------------------------------------------------------------ */
+    public WriterOutputStream(Writer writer, String encoding)
+    {
+        _writer=writer;
+        _encoding=encoding;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public WriterOutputStream(Writer writer)
+    {
+        _writer=writer;
+    }
+
+    /* ------------------------------------------------------------ */
+    @Override
+    public void close()
+        throws IOException
+    {
+        _writer.close();
+        _writer=null;
+        _encoding=null;
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public void flush()
+        throws IOException
+    {
+        _writer.flush();
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public void write(byte[] b) 
+        throws IOException
+    {
+        if (_encoding==null)
+            _writer.write(new String(b));
+        else
+            _writer.write(new String(b,_encoding));
+    }
+    
+    /* ------------------------------------------------------------ */
+    @Override
+    public void write(byte[] b, int off, int len)
+        throws IOException
+    {
+        if (_encoding==null)
+            _writer.write(new String(b,off,len));
+        else
+            _writer.write(new String(b,off,len,_encoding));
+    }
+    
+    /* ------------------------------------------------------------ */
+    public synchronized void write(int b)
+        throws IOException
+    {
+        _buf[0]=(byte)b;
+        write(_buf);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/argumentparser/AminoAcidArgumentParser.java b/src/main/java/es/uvigo/darwin/prottest/util/argumentparser/AminoAcidArgumentParser.java
new file mode 100755
index 0000000..5413a2e
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/argumentparser/AminoAcidArgumentParser.java
@@ -0,0 +1,98 @@
+/*
+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.prottest.util.argumentparser;
+
+import es.uvigo.darwin.prottest.global.ApplicationGlobals;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.util.factory.ProtTestFactory;
+import java.util.Properties;
+
+/**
+ * The Class AminoAcidArgumentParser.
+ */
+public class AminoAcidArgumentParser extends ProtTestArgumentParser {
+
+	/** Amino-Acid model matrices to include in the analysis. */
+	public static final List<String> PARAM_MATRICES;
+
+	/** Include models with all matrices (like -JTT -LG -etc,). */
+	public static final String PARAM_ALL_MATRICES = "all-matrices";
+	
+	static {
+		ApplicationGlobals apGlobals = ProtTestFactory.getInstance().getApplicationGlobals();
+		PARAM_MATRICES = apGlobals.getSupportedMatrices();
+		Map<String, String> allMatrices = new HashMap<String, String>(PARAM_MATRICES.size());
+		for (String matrix : PARAM_MATRICES) {
+			valuesRequired.put(matrix, false);
+			allMatrices.put(matrix, "T");
+		}
+		valuesRequired.put(PARAM_ALL_MATRICES, false);
+		specialArguments.put(PARAM_ALL_MATRICES, allMatrices);
+	}
+	
+	/**
+	 * Instantiates a new amino-acid argument parser.
+	 * 
+	 * @param args the command line arguments
+	 * @param options the application options
+	 * 
+	 * @throws IllegalArgumentException when exists some error in the command line argument
+	 */
+	public AminoAcidArgumentParser(String[] args, ApplicationOptions options)
+			throws IllegalArgumentException {
+		super(args, options);
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.argumentparser.ProtTestArgumentParser#getMatrices()
+	 */
+	public List<String> getMatrices() {
+		return PARAM_MATRICES;
+	}
+        
+        /* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.argumentparser.ProtTestArgumentParser#getMatrices()
+	 */
+        protected Properties checkArgs(String[] args)
+            throws IllegalArgumentException {
+            
+            // set all-matrices as default
+            boolean existMatrix = false;
+            int index = 0;
+            String modArgs[] = new String[args.length + 1];
+            for (String arg : args) {
+                if (PARAM_MATRICES.contains(arg.substring(1))) {
+                    existMatrix = true;
+                }
+                modArgs[index] = arg;
+                index++;
+            }
+            if (!existMatrix) {
+                modArgs[index] = "-" + PARAM_ALL_MATRICES;
+            } else {
+                modArgs = args;
+            }
+            
+            return super.checkArgs(modArgs);
+        }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/argumentparser/ProtTestArgumentParser.java b/src/main/java/es/uvigo/darwin/prottest/util/argumentparser/ProtTestArgumentParser.java
new file mode 100755
index 0000000..8da7836
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/argumentparser/ProtTestArgumentParser.java
@@ -0,0 +1,293 @@
+/*
+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.prottest.util.argumentparser;
+
+import static es.uvigo.darwin.prottest.global.ApplicationGlobals.*;
+
+import es.uvigo.darwin.prottest.global.ProtTestConsoleParameters;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+
+/**
+ * The Class ModelTestArgumentParser.
+ */
+public abstract class ProtTestArgumentParser 
+        implements ProtTestConsoleParameters {
+
+    
+    /** Hashtable to associate parameter tokens within parameter localArguments requirements. */
+    protected static final HashMap<String, Boolean> valuesRequired;
+    /** Hashtable to associate parameter tokens within parameter localArguments range. */
+    protected static final HashMap<String, String[]> argumentValues;
+    /** Hashtable to handle special localArguments like "all-distributions". */
+    protected static final HashMap<String, Map<String, String>> specialArguments;
+    /** The default APPLICATION_PROPERTIES. */
+    private static final Properties defaultProperties;
+    /** The argument  prefix. */
+    public static final String ARG_TOKEN = "-";
+    /** The command line localArguments. */
+    private Properties arguments;
+    
+    static {
+
+        valuesRequired = new HashMap<String, Boolean>();
+        argumentValues = new HashMap<String, String[]>();
+        specialArguments = new HashMap<String, Map<String, String>>();
+        valuesRequired.put(PARAM_ALIGNMENT_FILE, true);
+        valuesRequired.put(PARAM_OUTPUT_FILE, true);
+        valuesRequired.put(PARAM_TREE_FILE, true);
+        String[] optimizationStrategies = new String[OPTIMIZE_VALUES.length];
+        for (int index = 0; index < OPTIMIZE_VALUES.length; index++) {
+            optimizationStrategies[index] = String.valueOf(OPTIMIZE_VALUES[index]);
+        }
+        valuesRequired.put(PARAM_OPTIMIZATION_STRATEGY, true);
+        argumentValues.put(PARAM_OPTIMIZATION_STRATEGY, optimizationStrategies);
+        
+        String[] treeSearchOps = {
+        		TREE_SEARCH_NNI,
+        		TREE_SEARCH_SPR,
+        		TREE_SEARCH_BEST
+        };
+        String[] enabling = {
+        		"enabled",
+        		"disabled"
+        };
+        
+        valuesRequired.put(PARAM_TREE_SEARCH_OP, true);
+        argumentValues.put(PARAM_TREE_SEARCH_OP, treeSearchOps);
+        
+        valuesRequired.put(PARAM_NUM_THREADS, true);
+        valuesRequired.put(PARAM_ALL_FRAMEWORK_COMPARISON, false);
+        valuesRequired.put(PARAM_DISPLAY_NEWICK_TREE, false);
+        valuesRequired.put(PARAM_DISPLAY_ASCII_TREE, false);
+        valuesRequired.put(PARAM_DISPLAY_CONSENSUS_TREE, true);
+        valuesRequired.put(PARAM_PLUSF, false);
+        valuesRequired.put(PARAM_PLUSI, false);
+        valuesRequired.put(PARAM_PLUSG, false);
+        valuesRequired.put(PARAM_PLUSIG, false);
+        valuesRequired.put(PARAM_NCAT, true);
+        valuesRequired.put(PARAM_ALL_DISTRIBUTIONS, false);
+        valuesRequired.put(PARAM_VERBOSE, false);
+        valuesRequired.put(PARAM_DO_AIC, false);
+        valuesRequired.put(PARAM_DO_BIC, false);
+        valuesRequired.put(PARAM_DO_AICC, false);
+        valuesRequired.put(PARAM_DO_DT, false);
+        valuesRequired.put(PARAM_LOGGING, true);
+        argumentValues.put(PARAM_LOGGING, enabling);
+        Map<String, String> distributionsMap = new HashMap<String, String>(3);
+        distributionsMap.put(PARAM_PLUSG, "T");
+        distributionsMap.put(PARAM_PLUSI, "T");
+        distributionsMap.put(PARAM_PLUSIG, "T");
+        specialArguments.put(PARAM_ALL_DISTRIBUTIONS, distributionsMap);
+
+        defaultProperties = new Properties();
+
+        defaultProperties.setProperty(PARAM_NUM_THREADS, String.valueOf(DEFAULT_THREADS));
+        defaultProperties.setProperty(PARAM_NCAT, String.valueOf(DEFAULT_NCAT));
+        defaultProperties.setProperty(PARAM_OPTIMIZATION_STRATEGY, String.valueOf(DEFAULT_STRATEGY_MODE));
+        defaultProperties.setProperty(PARAM_DATA_TYPE, DATA_TYPE_AMINOACID);
+    }
+
+    /**
+     * Instantiates a new model test argument parser.
+     * 
+     * @param args the command line localArguments
+     * @param options the application options
+     * 
+     * @throws IllegalArgumentException when exists some error in the command line argument
+     */
+    public ProtTestArgumentParser(String[] args, ApplicationOptions options)
+            throws IllegalArgumentException {
+
+        arguments = checkArgs(args);
+        
+        if (!(exists(PARAM_DO_BIC) || exists(PARAM_DO_AIC)
+        		|| exists(PARAM_DO_AICC) || exists(PARAM_DO_DT))) {
+        	putArgument(PARAM_DO_BIC, "T", arguments);
+        }
+        
+        options.fillIn(this);
+    }
+
+    /**
+     * Check localArguments are grammatically correct and parse them into
+     * the instance.
+     * 
+     * @param args the command line localArguments
+     * 
+     * @return the argument APPLICATION_PROPERTIES
+     * 
+     * @throws IllegalArgumentException when exists some error in the command line argument
+     */
+    protected Properties checkArgs(String[] args)
+            throws IllegalArgumentException {
+
+        Properties localArguments = new Properties(defaultProperties);
+        int i = 0;
+        while (i < args.length) {
+
+            String arg = args[i];
+            if (!arg.startsWith(ARG_TOKEN)) {
+                System.err.print("Command line: ");
+                for (String simpleArg : args) {
+                    System.err.print(simpleArg + " ");
+                }
+                System.err.println(" ");
+                throw new IllegalArgumentException("Arguments must start with \"-\". The ofending argument was: " + arg);
+            }
+
+            arg = arg.substring(ARG_TOKEN.length());
+            if (valuesRequired.containsKey(arg)) {
+                if (valuesRequired.get(arg)) {
+                    if (i + 1 < args.length) {
+                        i++;
+                        String value = args[i];
+                        if (argumentValues.containsKey(arg)) {
+                            String[] values = argumentValues.get(arg);
+                            if (!Arrays.asList(values).contains(value.toLowerCase())) {
+                                throw new IllegalArgumentException("Invalid argument value " + value + " for parameter " + arg);
+                            }
+                        }
+
+                        // special cases
+                        if (specialArguments.containsKey(arg)) {
+                            Map<String, String> mapValues = specialArguments.get(arg);
+                            for (String key : mapValues.keySet()) {
+                                if (mapValues.get(key).equals("?")) {
+                                    mapValues.put(key, value);
+                                }
+                            }
+                            putArgument(mapValues, localArguments);
+                        } else {
+                            putArgument(arg, value, localArguments);
+                        }
+                    } else {
+                        IllegalArgumentException e = new IllegalArgumentException("Parameter " + arg + " requires a value");
+                        throw e;
+                    }
+                } else {
+                    if (specialArguments.containsKey(arg)) {
+                        Map<String, String> mapValues = specialArguments.get(arg);
+                        putArgument(mapValues, localArguments);
+                    } else {
+                        putArgument(arg, "T", localArguments);
+                    }
+                }
+            } else {
+                // Obsolete arguments checking...
+                if (arg.equals("-sort")) {
+                    System.err.println(" WARNING! \"sort\" argument is obsolete since 3.2 version. You should use one or more of the following instead: -AIC -AICC -BIC -DT");
+                }
+                throw new IllegalArgumentException("Invalid argument " + arg);
+            }
+            i++;
+        }
+        
+        return localArguments;
+
+    }
+
+    /**
+     * Checks if a concrete argument exists in the application.
+     * 
+     * @param arg the argument to check
+     * 
+     * @return true, if the argument has a value
+     */
+    public boolean exists(String arg) {
+        return arguments.containsKey(arg);
+    }
+
+    /**
+     * Checks if a boolean argument is set in the application.
+     * The method will return false if the boolean argument
+     * is set to 'false', the argument is not boolean or the
+     * argument does not exist in the argument list.
+     * 
+     * @param arg the argument to check
+     * 
+     * @return true, if the boolean argument is set to 'true'
+     */
+    public boolean isSet(String arg) {
+        boolean isSet;
+        try {
+            isSet = arguments.get(arg).equals("T");
+        } catch (NullPointerException npe) {
+            isSet = false;
+        }
+        return isSet;
+    }
+
+    /**
+     * Gets the value of an argument. If the argument key is not found,
+     * the default localArguments will be checked. If the argument key does
+     * not exist, the method will return null.
+     * 
+     * @param arg the argument to check
+     * 
+     * @return the argument value
+     */
+    public String getValue(String arg) {
+        return arguments.getProperty(arg);
+    }
+
+    /**
+     * Puts an argument into the argument list, with specified key and value.
+     * If the argument was already set to a certain value, the argument will
+     * take the new value, and a warning message will be printed into
+     * standard error output.
+     * 
+     * @param key the argument key
+     * @param value the argument value
+     * @param localArguments the argument list
+     */
+    private void putArgument(String key, String value, Properties arguments) {
+        if (arguments.containsKey(key)) {
+            System.err.println("WARNING! Repeated argument \"" + key + "\". New value is " + value);
+        }
+        arguments.setProperty(key, value);
+    }
+
+    /**
+     * Puts a set of couples argument-value into the argument list.
+     * For each argument that was already set to a certain value, the 
+     * argument will take the new value, and a warning message will be 
+     * printed into standard error output.
+     * 
+     * @param items the new localArguments to put
+     * @param localArguments the argument list
+     */
+    private void putArgument(Map<String, String> items, Properties arguments) {
+        // localArguments.putAll(items);
+        for (String key : items.keySet()) {
+            putArgument(key, items.get(key), arguments);
+        }
+    }
+
+    /**
+     * Gets the matrix name list of all supported matrices.
+     * 
+     * @return the matrix name list
+     */
+    public abstract List<String> getMatrices();
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/argumentparser/package.html b/src/main/java/es/uvigo/darwin/prottest/util/argumentparser/package.html
new file mode 100755
index 0000000..1649080
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/argumentparser/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+This classes allow to manage application arguments from command console.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/attributable/Attributable.java b/src/main/java/es/uvigo/darwin/prottest/util/attributable/Attributable.java
new file mode 100755
index 0000000..c8ae584
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/attributable/Attributable.java
@@ -0,0 +1,57 @@
+package es.uvigo.darwin.prottest.util.attributable;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * Interface for associating attributeNames with an object.
+ *
+ * @version $Id: Attributable.java 575 2006-12-14 15:49:14Z twobeers $
+ *
+ * @author Andrew Rambaut
+ */
+public interface Attributable {
+
+    /**
+     * Sets an named attribute for this object.
+     * @param name the name of the attribute.
+     * @param value the new value of the attribute.
+     */
+    void setAttribute(String name, Object value);
+
+    /**
+     * @return an object representing the named attributed for this object.
+     * @param name the name of the attribute of interest, or null if the attribute doesn't exist.
+     */
+    Object getAttribute(String name);
+
+    /**
+     * @param name name of attribute to remove
+     */
+    void removeAttribute(String name);
+
+    /**
+     * @return an array of the attributeNames that this object has.
+     */
+    Set<String> getAttributeNames();
+
+    /**
+     * Gets the entire attribute map.
+     * @return an unmodifiable map
+     */
+    Map<String, Object> getAttributeMap();
+
+    public static class Utils {
+        Set<String> getAttributeNames(Collection<Attributable> attributables) {
+            Set<String> names = new HashSet<String>();
+
+            for (Attributable attributable : attributables) {
+                names.addAll(attributable.getAttributeNames());
+            }
+
+            return names;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/attributable/AttributableHelper.java b/src/main/java/es/uvigo/darwin/prottest/util/attributable/AttributableHelper.java
new file mode 100755
index 0000000..62e8594
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/attributable/AttributableHelper.java
@@ -0,0 +1,41 @@
+package es.uvigo.darwin.prottest.util.attributable;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author rambaut
+ *         Date: Nov 27, 2005
+ *         Time: 1:31:50 PM
+ */
+public class AttributableHelper implements Attributable {
+
+    @Override
+	public void setAttribute(String name, Object value) {
+		attributeMap.put(name, value);
+	}
+
+    @Override
+	public Object getAttribute(String name) {
+		return attributeMap.get(name);
+	}
+
+    @Override
+    public void removeAttribute(String name) {
+		attributeMap.remove(name);
+	}
+
+    @Override
+    public Set<String> getAttributeNames() {
+		return attributeMap.keySet();
+	}
+
+    @Override
+	public Map<String, Object> getAttributeMap() {
+		return Collections.unmodifiableMap(attributeMap);
+	}
+
+	Map<String, Object> attributeMap = new HashMap<String, Object>();
+}
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/attributable/package.html b/src/main/java/es/uvigo/darwin/prottest/util/attributable/package.html
new file mode 100755
index 0000000..6709700
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/attributable/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+This hierarchy allows a single class to support attributes.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/CheckPointManager.java b/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/CheckPointManager.java
new file mode 100755
index 0000000..97ec8e3
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/CheckPointManager.java
@@ -0,0 +1,185 @@
+/*
+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.prottest.util.checkpoint;
+
+import static es.uvigo.darwin.prottest.global.ApplicationGlobals.*;
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import es.uvigo.darwin.prottest.util.checkpoint.status.ApplicationStatus;
+
+public class CheckPointManager {
+
+    private ApplicationStatus lastCheckpoint;
+    private File snapshotDir;
+    private File snapshotFile;
+    private boolean cpEnabled;
+    private final String SNAPSHOT_PREFIX = "SNAPSHOT";
+    private final String SNAPSHOT_SUFFIX = "snp";
+
+    public ApplicationStatus getLastCheckpoint() {
+        return lastCheckpoint;
+    }
+
+    public CheckPointManager() {
+        String snapshotDirName = APPLICATION_PROPERTIES.getProperty("snapshot_dir");
+        cpEnabled = snapshotDirName != null;
+        if (cpEnabled) {
+            snapshotDir = new File(snapshotDirName);
+            if (!snapshotDir.exists()) {
+                snapshotDir.mkdirs();
+            }
+        }
+    }
+
+    public synchronized boolean setStatus(ApplicationStatus newCheckpoint) {
+        if (cpEnabled) {
+            // check integrity
+            boolean validStatus = (lastCheckpoint == null || lastCheckpoint.isCompatible(newCheckpoint));
+
+            if (validStatus) {
+                lastCheckpoint = newCheckpoint;
+                saveStatus(lastCheckpoint);
+            } else {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private synchronized void saveStatus(ApplicationStatus checkpoint) {
+
+        if (cpEnabled) {
+            try {
+                if (snapshotFile == null) {
+                    // create new Snapshot file
+                    snapshotFile = File.createTempFile(
+                            SNAPSHOT_PREFIX, SNAPSHOT_SUFFIX, snapshotDir);
+                }
+
+                if (snapshotFile.exists()) {
+                    snapshotFile.delete();
+                }
+                snapshotFile.createNewFile();
+
+                FileOutputStream fos = new FileOutputStream(snapshotFile);
+                ObjectOutputStream out = new ObjectOutputStream(fos);
+                out.writeObject(checkpoint);
+                out.close();
+                fos.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+    @SuppressWarnings("unchecked")
+    public boolean loadStatus(ApplicationStatus initialStatus) {
+
+        boolean loaded = false;
+        if (cpEnabled) {
+            if (snapshotDir != null && snapshotDir.exists() && snapshotDir.canRead()) {
+                FilenameFilter filter = new FilenameFilter() {
+
+                    @Override
+                    public boolean accept(File dir, String name) {
+
+                        return name.startsWith(SNAPSHOT_PREFIX) && name.endsWith(SNAPSHOT_SUFFIX);
+                    }
+                };
+                File[] snapshotFiles = snapshotDir.listFiles(filter);
+                Arrays.sort(snapshotFiles, new Comparator() {
+
+                    public int compare(Object o1, Object o2) {
+
+                        if (((File) o1).lastModified() > ((File) o2).lastModified()) {
+                            return -1;
+                        } else if (((File) o1).lastModified() < ((File) o2).lastModified()) {
+                            return +1;
+                        } else {
+                            return 0;
+                        }
+                    }
+                });
+
+                ObjectInputStream in = null;
+                for (File statusFile : snapshotFiles) {
+                    try {
+                        //Construct the ObjectInputStream object
+                        in = new ObjectInputStream(new FileInputStream(statusFile));
+
+                        Object obj = null;
+
+                        obj = in.readObject();
+
+                        if (obj instanceof ApplicationStatus) {
+                            if (initialStatus.isCompatible((ApplicationStatus) obj)) {
+                                this.snapshotFile = statusFile;
+                                this.lastCheckpoint = (ApplicationStatus) obj;
+                                loaded = true;
+                                break;
+                            }
+                        }
+
+                    } catch (EOFException ex) {
+                        // This exception will be caught when EOF is reached
+                        // There is no data in the status file
+                        statusFile.delete();
+                    } catch (ClassNotFoundException ex) {
+                        // This exception will be caught when there is no 
+                        // serialized data in the status file
+                        statusFile.delete();
+                    } catch (FileNotFoundException ex) {
+
+                    } catch (IOException ex) {
+
+                    } finally {
+                        //Close the ObjectInputStream
+                        try {
+                            if (in != null) {
+                                in.close();
+                            }
+                        } catch (IOException ex) {
+                            ex.printStackTrace();
+                        }
+                    }
+                }
+            }
+        }
+        return loaded;
+
+    }
+
+    public void done() {
+        if (snapshotFile != null) {
+            snapshotFile.delete();
+        }
+        lastCheckpoint = null;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/package.html b/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/package.html
new file mode 100755
index 0000000..e094aa0
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains classes which add fault tolerance support using a distributed checkpointing system.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/status/ApplicationStatus.java b/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/status/ApplicationStatus.java
new file mode 100755
index 0000000..19d1fc9
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/status/ApplicationStatus.java
@@ -0,0 +1,47 @@
+/*
+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.prottest.util.checkpoint.status;
+
+import java.io.Serializable;
+import java.util.Calendar;
+
+public abstract class ApplicationStatus implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	private Calendar creationDate;
+	
+	public Calendar getCreationDate() {
+		return creationDate;
+	}
+	
+	public ApplicationStatus() {
+		creationDate = Calendar.getInstance();
+	}
+	
+	/**
+	 * Compare the current application status with another one
+	 * in order to check if both application status are
+	 * consistent.
+	 * 
+	 * @param other the other aplication status
+	 * 
+	 * @return true, if both are consistents
+	 */
+	public abstract boolean isCompatible(ApplicationStatus other);
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/status/ProtTestStatus.java b/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/status/ProtTestStatus.java
new file mode 100755
index 0000000..86cee3a
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/status/ProtTestStatus.java
@@ -0,0 +1,80 @@
+/*
+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.prottest.util.checkpoint.status;
+
+import java.util.Collection;
+
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.global.options.SerializableApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+public class ProtTestStatus extends ApplicationStatus {
+
+	private static final long serialVersionUID = 1L;
+	
+	private SerializableApplicationOptions applicationOptions;
+	private Model[] models;
+	
+	public Model[] getModels() {
+		return models;
+	}
+	
+	public SerializableApplicationOptions getApplicationOptions() {
+		return applicationOptions;
+	}
+	
+	public ProtTestStatus(Model[] models, ApplicationOptions applicationOptions) {
+		if (applicationOptions == null)
+			throw new ProtTestInternalException("Wrong status format");
+		if (models != null 
+				&& models.length > 0)
+				checkIntegrity(models, applicationOptions);
+			
+		this.models = models;
+		this.applicationOptions = new SerializableApplicationOptions(applicationOptions);
+	}
+
+	private boolean checkIntegrity(Model[] models, ApplicationOptions options) {
+		Collection<String> matrices = options.getMatrices(); 
+		Collection<Integer> distributions = options.getDistributions();
+		boolean plusF = options.isPlusF();
+		for (Model model : models) {
+			if (!(matrices.contains(model.getMatrix())
+					&& distributions.contains(model.getDistribution()))
+					&& (!model.isPlusF() || plusF)
+					&& (model.checkAlignment(options.getAlignment())))
+				return false;
+			if (!model.checkAlignment(options.getAlignment())) {
+				// sets up the same alignment instance, once equality have been tested
+				model.setAlignment(options.getAlignment());
+			}
+		}
+		return true;
+	}
+
+	@Override
+	public boolean isCompatible(ApplicationStatus other) {
+		if (other instanceof ProtTestStatus) {
+			ProtTestStatus otherStatus = (ProtTestStatus)other;
+			if (otherStatus.getApplicationOptions().equals(getApplicationOptions()))
+				return true;
+		}
+		return false;
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/status/package.html b/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/status/package.html
new file mode 100755
index 0000000..a0613c3
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/checkpoint/status/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains the application status.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/collection/ModelCollection.java b/src/main/java/es/uvigo/darwin/prottest/util/collection/ModelCollection.java
new file mode 100755
index 0000000..a95e594
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/collection/ModelCollection.java
@@ -0,0 +1,349 @@
+/*
+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.prottest.util.collection;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Properties;
+
+import pal.alignment.Alignment;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.factory.ProtTestFactory;
+
+/**
+ * An common interface for substitution models, that includes
+ * some specific operations to work with model collections.  
+ * 
+ * @author Diego Darriba
+ * @version 3.0
+ */
+public abstract class ModelCollection implements List<Model>, Serializable {
+
+    protected Alignment alignment;
+    /** The serialVersionUID. */
+    private static final long serialVersionUID = 515892620727410572L;
+    /** The set of all models inside the collection. */
+    protected List<Model> allModels;
+
+    public Alignment getAlignment() {
+        return alignment;
+    }
+
+    /**
+     * Instantiates a new model collection.
+     */
+    public ModelCollection(Alignment alignment) {
+        this.alignment = alignment;
+        allModels = new ArrayList<Model>();
+    }
+
+    /**
+     * Instantiates a new model collection with the array of models.
+     */
+    public ModelCollection(Model[] models, Alignment alignment) {
+        this.alignment = alignment;
+        for (Model model : models) {
+            checkAlignment(model);
+        }
+        allModels = new ArrayList<Model>();
+        allModels.addAll(Arrays.asList(models));
+    }
+
+    /**
+     * Instantiates a new model collection with another model collection.
+     */
+    public ModelCollection(ModelCollection mc) {
+        this.alignment = mc.getAlignment();
+        allModels = new ArrayList<Model>();
+        allModels.addAll(mc);
+    }
+
+    /**
+     * Creates a new model and adds it to the collection.
+     *
+     * @param matrix the substitution matrix name
+     * @param distribution the distribution of the model
+     * @param modelProperties the model specific properties
+     *
+     * @return true, if successfully added the model to the iterator
+     */
+    public boolean addModel(String matrix, int distribution, Properties modelProperties,
+            Alignment alignment, Tree tree, int ncat) {
+        Model model = ProtTestFactory.getInstance().createModel(matrix, distribution, modelProperties,
+                alignment, tree, ncat);
+
+        boolean toAdd = !allModels.contains(model);
+        if (toAdd) {
+            checkAlignment(model);
+            toAdd &= allModels.add(model);
+        }
+
+        return toAdd;
+    }
+
+    /**
+     * Adds a substitution model to the collection.
+     *
+     * @param model the substitution model to add
+     *
+     * @return true, if successfully added the model to the iterator
+     */
+    public boolean addModel(Model model) {
+        boolean toAdd = !allModels.contains(model);
+        if (toAdd) {
+            checkAlignment(model);
+            toAdd &= allModels.add(model);
+        }
+
+        return toAdd;
+    }
+
+    /**
+     * Adds the models result of combine each matrix with each distribution.
+     * There will be MxD new models in the iterator, where
+     * M is the number of matrices
+     * D is the number of distributions
+     *
+     * @param matrices collection of all the substitution matrices
+     * @param distributions collection of all the distributions
+     * @param modelProperties the model properties
+     *
+     * @return true, if successfully added all models
+     */
+    public boolean addModelCartesian(Collection<String> matrices, Collection<Integer> distributions,
+            Properties modelProperties, Alignment alignment, Tree tree, int ncat) {
+        boolean allDone = true;
+        boolean plusF = Boolean.parseBoolean(
+                modelProperties.getProperty(
+                Model.PROP_PLUS_F, "false"));
+        Properties modelPropertiesFalse = new Properties();
+        Properties modelPropertiesTrue = new Properties();
+        modelPropertiesFalse.setProperty(Model.PROP_PLUS_F, "false");
+        modelPropertiesTrue.setProperty(Model.PROP_PLUS_F, "true");
+        for (String matrix : matrices) {
+            for (Integer distribution : distributions) {
+                allDone &= addModel(matrix, distribution, modelPropertiesFalse,
+                        alignment, tree, ncat);
+                if (plusF) {
+                    allDone &= addModel(matrix, distribution, modelPropertiesTrue,
+                            alignment, tree, ncat);
+                }
+            }
+        }
+        return allDone;
+    }
+
+    /**
+     * Gets the weight of the collection. This attribute is only used in
+     * order to heuristically sort models.
+     *
+     * @return the whole weight of the collection
+     */
+    public int getWeight(ModelWeightComparator mwc) {
+        int weight = 0;
+        for (Model model : allModels) {
+            weight += mwc.getWeight(model);
+        }
+        return weight;
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#size()
+     */
+    public int size() {
+        return allModels.size();
+    }
+
+//	public abstract void printModelsSorted(char sortBy, PrintWriter out) 
+//	throws ProtTestInternalException;
+
+    /* (non-Javadoc)
+     * @see java.util.List#add(java.lang.Object)
+     */
+    public boolean add(Model e) {
+        return allModels.add(e);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#add(int, java.lang.Object)
+     */
+    public void add(int index, Model element) {
+        allModels.add(index, element);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#addAll(java.util.Collection)
+     */
+    public boolean addAll(Collection<? extends Model> c) {
+        return allModels.addAll(c);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#addAll(int, java.util.Collection)
+     */
+    public boolean addAll(int index, Collection<? extends Model> c) {
+        return allModels.addAll(index, c);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#clear()
+     */
+    public void clear() {
+        allModels.clear();
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#contains(java.lang.Object)
+     */
+    public boolean contains(Object o) {
+        return allModels.contains(o);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#containsAll(java.util.Collection)
+     */
+    public boolean containsAll(Collection<?> c) {
+        return allModels.containsAll(c);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#get(int)
+     */
+    public Model get(int index) {
+        return allModels.get(index);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#indexOf(java.lang.Object)
+     */
+    public int indexOf(Object o) {
+        return allModels.indexOf(o);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#isEmpty()
+     */
+    public boolean isEmpty() {
+        return allModels.isEmpty();
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#iterator()
+     */
+    public Iterator<Model> iterator() {
+        return allModels.iterator();
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#lastIndexOf(java.lang.Object)
+     */
+    public int lastIndexOf(Object o) {
+        return allModels.lastIndexOf(o);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#listIterator()
+     */
+    public ListIterator<Model> listIterator() {
+        return allModels.listIterator();
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#listIterator(int)
+     */
+    public ListIterator<Model> listIterator(int index) {
+        return allModels.listIterator(index);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#remove(java.lang.Object)
+     */
+    public boolean remove(Object o) {
+        return allModels.remove(o);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#remove(int)
+     */
+    public Model remove(int index) {
+        return allModels.remove(index);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#removeAll(java.util.Collection)
+     */
+    public boolean removeAll(Collection<?> c) {
+        return allModels.removeAll(c);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#retainAll(java.util.Collection)
+     */
+    public boolean retainAll(Collection<?> c) {
+        return allModels.retainAll(c);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#set(int, java.lang.Object)
+     */
+    public Model set(int index, Model element) {
+        return allModels.set(index, element);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#subList(int, int)
+     */
+    public List<Model> subList(int fromIndex, int toIndex) {
+        return allModels.subList(fromIndex, toIndex);
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#toArray()
+     */
+    public Object[] toArray() {
+        return allModels.toArray();
+    }
+
+    /* (non-Javadoc)
+     * @see java.util.List#toArray(T[])
+     */
+    public <T> T[] toArray(T[] a) {
+        return allModels.toArray(a);
+    }
+
+    private void checkAlignment(Model model) {
+        if (this.alignment == null) {
+            throw new ProtTestInternalException("Internal error: Alignment is not initialized");
+        } else if (!model.checkAlignment(this.alignment)) {
+            throw new ProtTestInternalException("Different alignments among model collection");
+        }
+    }
+
+    @Override
+    public ModelCollection clone() {
+        return new SingleModelCollection(this);
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/collection/ParallelModelCollection.java b/src/main/java/es/uvigo/darwin/prottest/util/collection/ParallelModelCollection.java
new file mode 100755
index 0000000..628cde6
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/collection/ParallelModelCollection.java
@@ -0,0 +1,269 @@
+/*
+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.prottest.util.collection;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+import pal.alignment.Alignment;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator;
+
+/**
+ * A complex implementation of model collection, which is able to
+ * distribute whole set of substitution models amongst a certain
+ * number of groups, generally amongst the number of processors.
+ * 
+ * This class is a composition of model collections, that will have
+ * disjunction and completeness properties.
+ */
+public class ParallelModelCollection extends ModelCollection {
+
+	/** The serialVersionUID. */
+	private static final long serialVersionUID = 20090903L;
+	
+	/** The list of model collections. */
+	private List<ModelCollection> modelCollections;
+	
+	/** The number of groups. */
+	private int groups;
+	
+	/** Defines if the current distribution is valid. */
+	private boolean validDistribution = false;
+	
+	/** The heuristic algorithm to compare models. */
+	private ModelWeightComparator comparator;
+	
+	/**
+	 * Instantiates a new parallel model collection.
+	 * 
+	 * @param allModels the whole set of models
+	 * @param groups the number of groups, typically the size of the MPJ communicator
+	 */
+	public ParallelModelCollection(Model[] allModels, int groups, ModelWeightComparator comparator, Alignment alignment) {
+                super(alignment);
+		ArrayList<Model> models = new ArrayList<Model>(Arrays.asList(allModels));
+		this.comparator = comparator;
+		Collections.sort(models, comparator);
+		initialize(models, groups);
+	}
+	
+	/**
+	 * Instantiates a new parallel model collection.
+	 * 
+	 * @param allModels the whole set of models.
+	 * @param groups the number of groups, typically the size of the MPJ communicator
+	 */
+	public ParallelModelCollection(ModelCollection allModels, int groups, ModelWeightComparator comparator) {
+                super(allModels.getAlignment());
+		List<Model> models = new ArrayList<Model>(allModels);
+		this.comparator = comparator;
+		Collections.sort(models, comparator);
+		initialize(models, groups);
+	}
+	
+	/**
+	 * Initialize.
+	 * 
+	 * @param allModels the whole set of models
+	 * @param groups the number of groups, typically the size of the MPJ communicator
+	 */
+	private void initialize(List<Model> allModels, int groups) {
+		this.allModels = allModels;
+		this.groups = groups;
+		modelCollections = new ArrayList<ModelCollection>();
+		distributeModels(this.allModels, this.groups);		
+	}
+	
+	/**
+	 * Distribute models amongst groups. This method grants completeness
+	 * and disjunction of single collections.
+	 * 
+	 * @param allModels the whole set of models.
+	 * @param groups the number of groups to distribute models into
+	 */
+	private void distributeModels(List<Model> allModels, int groups) {
+		
+		modelCollections.clear();
+		
+		// initialize
+		for (int i = 0; i < groups; i++)
+			modelCollections.add(new SingleModelCollection(getAlignment()));
+		
+		int maxWeight = 1;
+		int currentGroup = 0;
+		boolean modelAdded = false;
+		
+		for (Model model : allModels) {
+			modelAdded = false;
+			ModelCollection minModelGroup = modelCollections.get(0);
+			for (currentGroup = 0; currentGroup < groups; currentGroup++) {
+				ModelCollection currentModelGroup = modelCollections.get(currentGroup);
+				if (currentModelGroup.getWeight(comparator) + comparator.getWeight(model) <= maxWeight)
+				{
+					modelAdded = currentModelGroup.addModel(model);
+					maxWeight = currentModelGroup.getWeight(comparator);
+					break;
+				} else if (currentModelGroup.getWeight(comparator) < minModelGroup.getWeight(comparator))
+					minModelGroup = currentModelGroup;
+			}
+			if (!modelAdded) {
+				minModelGroup.addModel(model);
+				maxWeight = minModelGroup.getWeight(comparator);
+			}
+		}
+		
+		validDistribution = true;
+	}
+	
+	/**
+	 * Gets a single model collection. This method will return null
+	 * if the group parameter is out of rank.
+	 * 
+	 * @param group the group
+	 * 
+	 * @return the model iterator
+	 */
+	public ModelCollection getModelCollection(int group) {
+		
+		if (!validDistribution)
+			distributeModels(this.allModels, this.groups);
+		
+		if (group < 0 || group > groups)
+			return null;
+		
+		return modelCollections.get(group);
+	}
+
+	/* (non-Javadoc)
+	 * @see java.util.List#add(int, java.lang.Object)
+	 */
+        @Override
+	public void add(int index, Model element) {
+		validDistribution = false;
+		super.add(index, element);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#add(es.uvigo.darwin.prottest.model.Model)
+	 */
+	@Override
+	public boolean add(Model e) {
+		validDistribution = false;
+		return super.add(e);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#addModel(java.lang.String, int, java.util.Properties)
+	 */
+	@Override
+	public boolean addModel(String matrix, int distribution, Properties modelProperties,
+			Alignment alignment, Tree tree, int ncat) {
+		validDistribution = false;
+		return super.addModel(matrix, distribution, modelProperties,
+				alignment, tree, ncat);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#addModel(es.uvigo.darwin.prottest.model.Model)
+	 */
+	@Override
+	public boolean addModel(Model model) {
+		validDistribution = false;
+		return super.addModel(model);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#addModelCartesian(java.util.Collection, java.util.Collection, java.util.Properties)
+	 */
+	@Override
+	public boolean addModelCartesian(Collection<String> matrices, Collection<Integer> distributions, 
+			Properties modelProperties, Alignment alignment, Tree tree, int ncat) {
+		validDistribution = false;
+		return super.addModelCartesian(matrices, distributions, modelProperties,
+				alignment, tree, ncat);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#addAll(java.util.Collection)
+	 */
+	@Override
+	public boolean addAll(Collection<? extends Model> c) {
+		validDistribution = false;
+		return super.addAll(c);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#addAll(int, java.util.Collection)
+	 */
+	@Override
+	public boolean addAll(int index, Collection<? extends Model> c) {
+		validDistribution = false;
+		return super.addAll(index, c);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#clear()
+	 */
+	@Override
+	public void clear() {
+		validDistribution = false;
+		super.clear();
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#remove(java.lang.Object)
+	 */
+	@Override
+	public boolean remove(Object o) {
+		validDistribution = false;
+		return super.remove(o);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#remove(int)
+	 */
+	@Override
+	public Model remove(int index) {
+		validDistribution = false;
+		return super.remove(index);
+	}
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#removeAll(java.util.Collection)
+	 */
+	@Override
+	public boolean removeAll(Collection<?> c) {
+		validDistribution = false;
+		return super.removeAll(c);
+	}
+	
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.collection.ModelCollection#set(int, es.uvigo.darwin.prottest.model.Model)
+	 */
+	@Override
+	public Model set(int index, Model element) {
+		validDistribution = false;
+		return super.set(index, element);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/collection/ParallelModelQueue.java b/src/main/java/es/uvigo/darwin/prottest/util/collection/ParallelModelQueue.java
new file mode 100755
index 0000000..e2099bc
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/collection/ParallelModelQueue.java
@@ -0,0 +1,81 @@
+/*
+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.prottest.util.collection;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.comparator.ModelDistributionHeuristic;
+import java.util.Collections;
+
+/**
+ *
+ * @author Diego Darriba
+ */
+public class ParallelModelQueue {
+
+    /** List of models */
+    private ModelCollection sortedModelList;
+    /** Number of threads to schedule */
+    private int maxAvThreads;
+    /** Available threads */
+    private int availableThreads;
+
+    public ParallelModelQueue(int maxAvThreads, ModelCollection modelList) {
+
+        this.maxAvThreads = maxAvThreads;
+        this.availableThreads = maxAvThreads;
+
+        this.sortedModelList = modelList;
+        Collections.sort(this.sortedModelList, new ModelDistributionHeuristic());
+
+    }
+
+    public synchronized Model getNextModel() {
+
+        if (availableThreads < 1) {
+            return null;
+        }
+
+        Model nextModel = null;
+        for (Model model : sortedModelList) {
+
+            if (getNumberOfThreads(model) <= availableThreads) {
+                nextModel = model;
+                break;
+            }
+
+        }
+        availableThreads -= getNumberOfThreads(nextModel);
+        sortedModelList.remove(nextModel);
+        return nextModel;
+
+    }
+
+    private int getNumberOfThreads(Model model) {
+
+        int numberOfProcessors;
+        if (!model.isGamma()) {
+            numberOfProcessors = 1;
+        } else if (!model.isInv()) {
+            numberOfProcessors = 2;
+        } else {
+            numberOfProcessors = 4;
+        }
+        return Math.min(numberOfProcessors, maxAvThreads);
+
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/collection/SingleModelCollection.java b/src/main/java/es/uvigo/darwin/prottest/util/collection/SingleModelCollection.java
new file mode 100755
index 0000000..f8d7b73
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/collection/SingleModelCollection.java
@@ -0,0 +1,56 @@
+/*
+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.prottest.util.collection;
+
+import es.uvigo.darwin.prottest.model.Model;
+import pal.alignment.Alignment;
+
+/**
+ * A single implementation of ModelCollection.
+ */
+public class SingleModelCollection extends ModelCollection {
+
+	/** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 20090804L;
+
+	/**
+	 * Instantiates a new single model collection.
+	 */
+	public SingleModelCollection(Alignment alignment) {
+		super(alignment);
+	}
+	
+	/**
+	 * Instantiates a new single model collection.
+	 * 
+	 * @param models the models
+	 */
+	public SingleModelCollection(Model[] models, Alignment alignment) {
+		super(models, alignment);
+	}
+
+        /**
+	 * Instantiates a new single model collection.
+	 *
+	 * @param models the models
+	 */
+	public SingleModelCollection(ModelCollection models) {
+		super(models);
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/collection/package.html b/src/main/java/es/uvigo/darwin/prottest/util/collection/package.html
new file mode 100755
index 0000000..9e6323f
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/collection/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains utilities to manage substitution model collections with group operations.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/comparator/AminoAcidModelNaturalComparator.java b/src/main/java/es/uvigo/darwin/prottest/util/comparator/AminoAcidModelNaturalComparator.java
new file mode 100755
index 0000000..b3f8cd5
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/comparator/AminoAcidModelNaturalComparator.java
@@ -0,0 +1,63 @@
+/*
+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.prottest.util.comparator;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+import static es.uvigo.darwin.prottest.global.AminoAcidApplicationGlobals.*;
+import es.uvigo.darwin.prottest.model.AminoAcidModel;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+public class AminoAcidModelNaturalComparator implements Comparator<Model> {
+
+	@Override
+	public int compare(Model model0, Model model1) {
+		
+		if (model0 instanceof AminoAcidModel && model1 instanceof AminoAcidModel) {
+			AminoAcidModel arg0 = (AminoAcidModel) model0;
+			AminoAcidModel arg1 = (AminoAcidModel) model1;
+			int value = 0;
+			if (!arg0.getMatrix().equals(arg1.getMatrix())) {
+				List<String> matrices = Arrays.asList(ALL_MATRICES);
+				int pos0 = matrices.indexOf(arg0.getMatrix());
+				int pos1 = matrices.indexOf(arg1.getMatrix());
+				if ( pos0 < pos1 )
+					value = -1;
+				else
+					value = 1;
+			} else if (arg0.getDistribution() != arg1.getDistribution()) {
+				if (arg0.getDistribution() < arg1.getDistribution())
+					value = -1;
+				else if (arg1.getDistribution() < arg0.getDistribution())
+					value = 1;
+			} else if (arg0.isPlusF() != arg1.isPlusF()) {
+				if (arg0.isPlusF())
+					value = 1;
+				else
+					value = -1;
+			} else
+				value = 0;
+			return value;
+		} else
+			throw new ProtTestInternalException("Wrong use of Amino-acid Model Comparator");
+	}
+	
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/comparator/LKComparator.java b/src/main/java/es/uvigo/darwin/prottest/util/comparator/LKComparator.java
new file mode 100755
index 0000000..86c9643
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/comparator/LKComparator.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.prottest.util.comparator;
+
+import java.util.Comparator;
+
+import es.uvigo.darwin.prottest.model.Model;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class LKComparator.
+ */
+public class LKComparator implements Comparator<Model> {
+
+	/* (non-Javadoc)
+	 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
+	 */
+	public int compare(Model arg0, Model arg1) {
+		
+		int value = 0;
+		if (arg0.getLk() > arg1.getLk())
+			value = 1;
+		else if (arg0.getLk() < arg1.getLk())
+			value = -1;
+		return value;
+		
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/comparator/ModelDistributionHeuristic.java b/src/main/java/es/uvigo/darwin/prottest/util/comparator/ModelDistributionHeuristic.java
new file mode 100755
index 0000000..65f8cc1
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/comparator/ModelDistributionHeuristic.java
@@ -0,0 +1,55 @@
+/*
+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.prottest.util.comparator;
+
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class ModelDistributionHeuristic.
+ */
+public class ModelDistributionHeuristic extends ModelWeightComparator {
+
+	/* (non-Javadoc)
+	 * @see es.uvigo.darwin.prottest.util.comparator.ModelWeightComparator#getWeight(es.uvigo.darwin.prottest.model.Model)
+	 */
+	public int getWeight(Model model) {
+		
+		int weight;
+		switch (model.getDistribution()) {
+		case 0:
+			weight = 1;
+			break;
+		case 1:
+			weight = 2;
+			break;
+		case 2:
+			weight = 6;
+			break;
+		case 3:
+			weight = 30;
+			break;
+		default:
+			throw new ProtTestInternalException("Invalid model distribution " + model.getDistribution());
+		}
+		
+		return weight;
+	}
+	
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/comparator/ModelWeightComparator.java b/src/main/java/es/uvigo/darwin/prottest/util/comparator/ModelWeightComparator.java
new file mode 100755
index 0000000..534e27c
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/comparator/ModelWeightComparator.java
@@ -0,0 +1,48 @@
+/*
+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.prottest.util.comparator;
+
+import java.util.Comparator;
+
+import es.uvigo.darwin.prottest.model.Model;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class ModelWeightComparator.
+ */
+public abstract class ModelWeightComparator 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;
+	}
+
+	/**
+	 * Gets the weight.
+	 * 
+	 * @param model the model
+	 * 
+	 * @return the weight
+	 */
+	public abstract int getWeight(Model model);
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/comparator/package.html b/src/main/java/es/uvigo/darwin/prottest/util/comparator/package.html
new file mode 100755
index 0000000..52b9784
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/comparator/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains utilities to compare models, like sorting heuristics.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/exception/AlignmentParseException.java b/src/main/java/es/uvigo/darwin/prottest/util/exception/AlignmentParseException.java
new file mode 100755
index 0000000..67534c0
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/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.prottest.util.exception;
+
+/**
+ * The Class AlignmentParseException.
+ * 
+ * @author Diego Darriba
+ */
+public class AlignmentParseException extends ProtTestCheckedException {
+
+    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/prottest/util/exception/ImportException.java b/src/main/java/es/uvigo/darwin/prottest/util/exception/ImportException.java
new file mode 100755
index 0000000..6e835d3
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/exception/ImportException.java
@@ -0,0 +1,59 @@
+package es.uvigo.darwin.prottest.util.exception;
+
+/**
+ * @author Andrew Rambaut
+ * @author Alexei Drummond
+ *
+ * @version $Id: ImportException.java 609 2007-01-08 00:40:49Z pepster $
+ */
+public class ImportException extends Exception {
+	public ImportException() { super(); }
+	public ImportException(String message) { super(message); }
+    public String userMessage() { return getMessage(); }
+
+    public static class DuplicateFieldException extends ImportException {
+		public DuplicateFieldException() { super(); }
+		public DuplicateFieldException(String message) { super(message); }
+	}
+
+	public static class BadFormatException extends ImportException {
+		public BadFormatException() { super(); }
+		public BadFormatException(String message) { super(message); }
+	}
+
+	public static class UnparsableDataException extends ImportException {
+		public UnparsableDataException() { super(); }
+		public UnparsableDataException(String message) { super(message); }
+	}
+
+	public static class MissingFieldException extends ImportException {
+		public MissingFieldException() { super(); }
+		public MissingFieldException(String message) { super(message); }
+        public String userMessage() { return "Unsupported value for field " + getMessage(); }
+	}
+
+	public static class ShortSequenceException extends ImportException {
+		public ShortSequenceException() { super(); }
+		public ShortSequenceException(String message) { super(message); }
+        public String userMessage() { return "Sequence is too short: " + getMessage(); }
+    }
+
+	public static class TooFewTaxaException extends ImportException {
+		public TooFewTaxaException() { super(); }
+		public TooFewTaxaException(String message) { super(message); }
+        public String userMessage() { return "Number of taxa is less than expected: " +
+                (getMessage() != null ? getMessage() : ""); }
+    }
+
+    public static class DuplicateTaxaException extends ImportException {
+		public DuplicateTaxaException() { super(); }
+		public DuplicateTaxaException(String message) { super(message); }
+	}
+
+    public static class UnknownTaxonException extends ImportException {
+		public UnknownTaxonException() { super(); }
+		public UnknownTaxonException(String message) { super(message); }
+	}
+
+}
+
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/exception/ModelOptimizationException.java b/src/main/java/es/uvigo/darwin/prottest/util/exception/ModelOptimizationException.java
new file mode 100755
index 0000000..d0dabdc
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/exception/ModelOptimizationException.java
@@ -0,0 +1,165 @@
+/*
+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.prottest.util.exception;
+
+/**
+ * Generic exception when model optimization
+ * 
+ * @author Diego Darriba
+ * @since 3.0
+ */
+public class ModelOptimizationException extends ProtTestCheckedException {
+
+    /** The Constant serialVersionUID. */
+    private static final long serialVersionUID = 20090728L;
+
+    /**
+     * Instantiates a new external execution exception.
+     */
+    public ModelOptimizationException() {
+        super("Model optimization exception");
+    }
+
+    /**
+     * Instantiates a new external execution exception.
+     * 
+     * @param description the description
+     */
+    public ModelOptimizationException(String description) {
+        super("Model optimization exception: " + description);
+    }
+
+    /**
+     * Exception which occurs while execution a third-party application
+     * 
+     * @author Diego Darriba
+     * @since 3.0
+     */
+    public static class ExternalExecutionException extends ModelOptimizationException {
+
+        public ExternalExecutionException() {
+            super();
+        }
+
+        public ExternalExecutionException(String application) {
+            super("there was an error while executing " + application);
+        }
+
+        public ExternalExecutionException(String application, String message) {
+            super("there was an error while executing " + application + ": " + message);
+        }
+    }
+
+    /**
+     * Exception which occurs when the current operating system is not supported
+     * (only when running non-portable applications)
+     * 
+     * @author Diego Darriba
+     * @since 3.0
+     */
+    public static class OSNotSupportedException extends ExternalExecutionException {
+
+        /**
+         * Instantiates a new oS not supported exception.
+         */
+        public OSNotSupportedException(String application) {
+            super(application, "this operating system (" + System.getProperty("os.name") + ") is not supported.");
+        }
+    }
+
+    /**
+     * Exception while parsing the stats file provided by a third-party application
+     * 
+     * @author Diego Darriba
+     * @since 3.0
+     */
+    public static class StatsFileFormatException extends ExternalExecutionException {
+
+        /** The Constant serialVersionUID. */
+        private static final long serialVersionUID = 20090728L;
+
+        /**
+         * Instantiates a new stats file format exception.
+         * 
+         * @param application the external model optimizer
+         */
+        public StatsFileFormatException(String application) {
+            super("there was an error parsing " + application + " stats file");
+        }
+
+        /**
+         * Instantiates a new stats file format exception.
+         * 
+         * @param application the external model optimizer
+         * @param description the description
+         */
+        public StatsFileFormatException(String application, String description) {
+            super("there was an error parsing " + application + " stats file: " + description);
+        }
+    }
+
+    /**
+     * Exception while a required model matrix is not found
+     * 
+     * @author diego
+     * @since 3.0
+     */
+    public static class ModelNotFoundException extends ExternalExecutionException {
+
+        /** The Constant serialVersionUID. */
+        private static final long serialVersionUID = 20090728L;
+
+        /**
+         * Instantiates a new model not found exception.
+         * 
+         * @param model the non existent model name
+         */
+        public ModelNotFoundException(String model) {
+            super("cannot find " + model + " matrix description");
+        }
+
+        /**
+         * Instantiates a new model not found exception.
+         * 
+         * @param model the non existent model name
+         * @param description the description
+         */
+        public ModelNotFoundException(String model, String description) {
+            super("cannot find " + model + " matrix description: " + description);
+        }
+    }
+
+    /**
+     * External execution exception localized in PhyML
+     * 
+     * @author diego
+     * @since 3.0
+     */
+    public static class PhyMLExecutionException extends ExternalExecutionException {
+
+        private static final String applicationName = "PhyML";
+
+        public PhyMLExecutionException() {
+            super(applicationName);
+        }
+
+        public PhyMLExecutionException(String message) {
+            super(applicationName, message);
+        }
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/exception/ProtTestCheckedException.java b/src/main/java/es/uvigo/darwin/prottest/util/exception/ProtTestCheckedException.java
new file mode 100755
index 0000000..ca4ea71
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/exception/ProtTestCheckedException.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.prottest.util.exception;
+
+/**
+ *
+ * @author Diego Darriba
+ */
+public class ProtTestCheckedException extends Exception {
+
+    /** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 20100525L;
+
+	/**
+	 * Instantiates a new prot test internal exception.
+	 */
+	public ProtTestCheckedException() {}
+	
+	/**
+	 * Instantiates a new prot test internal exception.
+	 * 
+	 * @param description the description
+	 */
+	public ProtTestCheckedException(String description) {
+		super(description);
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/exception/ProtTestInternalException.java b/src/main/java/es/uvigo/darwin/prottest/util/exception/ProtTestInternalException.java
new file mode 100755
index 0000000..2c29288
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/exception/ProtTestInternalException.java
@@ -0,0 +1,45 @@
+/*
+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.prottest.util.exception;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class ProtTestInternalException.
+ * 
+ * @author Diego Darriba López
+ */
+public class ProtTestInternalException extends RuntimeException {
+
+	/** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 20090728L;
+
+	/**
+	 * Instantiates a new prot test internal exception.
+	 */
+	public ProtTestInternalException() {}
+	
+	/**
+	 * Instantiates a new prot test internal exception.
+	 * 
+	 * @param description the description
+	 */
+	public ProtTestInternalException(String description) {
+		super(description);
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/exception/TreeFormatException.java b/src/main/java/es/uvigo/darwin/prottest/util/exception/TreeFormatException.java
new file mode 100755
index 0000000..fd51901
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/exception/TreeFormatException.java
@@ -0,0 +1,45 @@
+/*
+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.prottest.util.exception;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class TreeFormatException.
+ * 
+ * @author Diego Darriba López
+ */
+public class TreeFormatException extends ProtTestInternalException {
+
+	/** The Constant serialVersionUID. */
+	private static final long serialVersionUID = 20090728L;
+
+	/**
+	 * Instantiates a new tree format exception.
+	 */
+	public TreeFormatException() {}
+	
+	/**
+	 * Instantiates a new tree format exception.
+	 * 
+	 * @param description the description
+	 */
+	public TreeFormatException(String description) {
+		super(description);
+	}
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/factory/ProtTestFactory.java b/src/main/java/es/uvigo/darwin/prottest/util/factory/ProtTestFactory.java
new file mode 100755
index 0000000..d784a98
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/factory/ProtTestFactory.java
@@ -0,0 +1,317 @@
+/*
+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.prottest.util.factory;
+
+import static es.uvigo.darwin.prottest.global.ApplicationGlobals.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+import java.util.Calendar;
+import java.text.SimpleDateFormat;
+
+import pal.alignment.Alignment;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.exe.PhyMLv3AminoAcidRunEstimator;
+import es.uvigo.darwin.prottest.exe.RaxMLAminoAcidRunEstimator;
+import es.uvigo.darwin.prottest.exe.RunEstimator;
+import es.uvigo.darwin.prottest.global.AminoAcidApplicationGlobals;
+import es.uvigo.darwin.prottest.global.ApplicationGlobals;
+import es.uvigo.darwin.prottest.global.RaxmlAminoAcidApplicationGlobals;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.AminoAcidModel;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.printer.AminoAcidPrintFramework;
+import es.uvigo.darwin.prottest.selection.printer.PrintFramework;
+import es.uvigo.darwin.prottest.util.argumentparser.AminoAcidArgumentParser;
+import es.uvigo.darwin.prottest.util.argumentparser.ProtTestArgumentParser;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogFormatter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.StreamHandler;
+
+/**
+ * A factory for creating ProtTest objects.
+ */
+public class ProtTestFactory {
+
+    /** The Constant PROTEIC. */
+    public static final int PROTEIC = 1;
+    /** The Constant NUCLEIC. */
+    public static final int NUCLEIC = 2;
+    /** The Constant MAX_SORT. */
+    private static final int MAX_SORT = 2;
+    /** The instance. */
+    private static ProtTestFactory instance;
+    /** The sort. */
+    private int sort;
+    /** Unique log handler. */
+    private Handler logHandler;
+
+    /**
+     * Instantiates a new prot test factory.
+     * 
+     * @param sort the sort
+     * 
+     * @throws IllegalArgumentException the illegal argument exception
+     */
+    private ProtTestFactory(int sort)
+            throws IllegalArgumentException {
+        if (sort <= 0 || sort > MAX_SORT) {
+            throw new IllegalArgumentException(
+                    "Cannot create factory (unexistent sort : " + sort + ")");
+        }
+        this.sort = sort;
+    }
+
+    /**
+     * Initialize.
+     * 
+     * @param args the args
+     * 
+     * @return the string[]
+     */
+    public static String[] initialize(String[] args) {
+        if (instance == null) {
+            int sort;
+            List<String> argList = new ArrayList<String>(Arrays.asList(args));
+            int index = argList.indexOf(ProtTestArgumentParser.ARG_TOKEN + ProtTestArgumentParser.PARAM_DATA_TYPE);
+            if (index < 0) //set default
+            {
+                sort = PROTEIC;
+            } else {
+                String value = argList.get(index + 1);
+                argList.remove(index + 1);
+                argList.remove(index);
+                args = argList.toArray(new String[0]);
+                if (value.equals(ProtTestArgumentParser.DATA_TYPE_AMINOACID)) {
+                    sort = PROTEIC;
+                } else if (value.equals(ProtTestArgumentParser.DATA_TYPE_NUCLEOTIDE)) {
+                    sort = NUCLEIC;
+                } else {
+                    throw new IllegalArgumentException("Invalid data type " + value);
+                }
+            }
+            instance = new ProtTestFactory(sort);
+            return args;
+        } else {
+            throw new ProtTestInternalException("ModelTestFactory was already initialized");
+        }
+    }
+
+    /**
+     * Gets the single instance of ProtTestFactory.
+     * 
+     * @return single instance of ProtTestFactory
+     */
+    public static ProtTestFactory getInstance() {
+        if (instance == null) {
+            initialize(new String[0]);
+        }
+//			throw new ProtTestInternalException("ModelTestFactory should be initialized");
+
+        return instance;
+    }
+
+    /**
+     * Creates a new ProtTest object.
+     * 
+     * @param args the args
+     * @param options the options
+     * 
+     * @return the prot test argument parser
+     */
+    public ProtTestArgumentParser createProtTestArgumentParser(String[] args, ApplicationOptions options) 
+        throws IllegalArgumentException{
+        ProtTestArgumentParser mtap = null;
+        switch (sort) {
+            case PROTEIC:
+                mtap = new AminoAcidArgumentParser(args, options);
+                break;
+            case NUCLEIC:
+                throw new ProtTestInternalException("Unsupported operation: nucleic data");
+        }
+        return mtap;
+    }
+
+    /**
+     * Gets the application globals.
+     * 
+     * @return the application globals
+     */
+    public ApplicationGlobals getApplicationGlobals() {
+        ApplicationGlobals ap = null;
+        String analyzer = APPLICATION_PROPERTIES.getProperty("analyzer");
+        switch (sort) {
+            case PROTEIC:
+                if (analyzer.equals(ANALYZER_RAXML)) {
+                    ap = new RaxmlAminoAcidApplicationGlobals();
+                } else if (analyzer.equals(ANALYZER_PHYML)) {
+                    ap = new AminoAcidApplicationGlobals();
+                } else {
+                    throw new ProtTestInternalException("Analyzer " + analyzer + " not supported by RunEstimator. Check your prottest.properties file");
+                }
+                break;
+            case NUCLEIC:
+                throw new ProtTestInternalException("Unsupported operation: nucleic data");
+        }
+        return ap;
+    }
+
+    /**
+     * Creates a new ProtTest object.
+     * 
+     * @param matrix the matrix
+     * @param distribution the distribution
+     * @param modelProperties the model APPLICATION_PROPERTIES
+     * 
+     * @return the model
+     */
+    public Model createModel(String matrix, int distribution, Properties modelProperties,
+            Alignment alignment, Tree tree, int ncat) {
+        Model model = null;
+        boolean plusF;
+        if (modelProperties != null) {
+            plusF = Boolean.parseBoolean(
+                    modelProperties.getProperty(
+                    AminoAcidModel.PROP_PLUS_F, "false"));
+        } else {
+            plusF = false;
+        }
+        switch (sort) {
+            case PROTEIC:
+                model = new AminoAcidModel(matrix, distribution, plusF,
+                        alignment, tree, ncat);
+                break;
+            case NUCLEIC:
+                throw new ProtTestInternalException("Unsupported operation: nucleic data");
+        }
+        return model;
+    }
+
+    /**
+     * Creates a new ProtTest object.
+     * 
+     * @param options the options
+     * @param model the model
+     * 
+     * @return the run estimator
+     */
+    public RunEstimator createRunEstimator(ApplicationOptions options, Model model) {
+        return createRunEstimator(options, model, 1);
+    }
+
+    /**
+     * Creates a new ProtTest object.
+     * 
+     * @param options the options
+     * @param model the model
+     * 
+     * @return the run estimator
+     */
+    public RunEstimator createRunEstimator(ApplicationOptions options, Model model, int numberOfThreads) {
+        RunEstimator runEstimator = null;
+        String analyzer = APPLICATION_PROPERTIES.getProperty("analyzer");
+        if (analyzer.equals(ANALYZER_PHYML)) {
+            switch (sort) {
+                case PROTEIC:
+                    runEstimator = new PhyMLv3AminoAcidRunEstimator(options, model, numberOfThreads);
+                    break;
+                case NUCLEIC:
+                    throw new ProtTestInternalException("Unsupported operation: nucleic data");
+            }
+        } else if (analyzer.equals(ANALYZER_RAXML)) {
+            switch (sort) {
+                case PROTEIC:
+                    runEstimator = new RaxMLAminoAcidRunEstimator(options, model);
+                    break;
+                case NUCLEIC:
+                    throw new ProtTestInternalException("Unsupported operation: nucleic data");
+            }
+        } else {
+            throw new ProtTestInternalException("Analyzer " + analyzer + " not supported by RunEstimator");
+        }
+        return runEstimator;
+    }
+
+    public Handler createLogHandler() throws IOException {
+        //   Log level is configurable:
+        //   'info'    Only general information messages are logged (default)
+        //   'fine'    General debug information is also logged
+        //   'finer'   More complex debug information is logged
+        //   'finest'  All activity is tracked
+
+        if (logHandler == null) {
+
+            String[] supportedLevels = {"INFO", "FINE", "FINER", "FINEST"};
+
+            String logDirName = APPLICATION_PROPERTIES.getProperty("log_dir");
+            String level = APPLICATION_PROPERTIES.getProperty("log_level", "info").toUpperCase();
+            boolean supported = false;
+            for (String testLevel : supportedLevels) {
+                supported |= testLevel.equals(level);
+            }
+
+            if (logDirName != null && supported) {
+                File logDir = new File(logDirName);
+                if (!logDir.isAbsolute()) {
+                	logDir = new File(ApplicationGlobals.PATH + File.separator + logDir);
+                }
+                if (!logDir.exists()) {
+                    logDir.mkdirs();
+                }
+
+		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+                //File logFile = new File(logDir.getAbsolutePath() + File.separator + "prottest3_" +
+		//	sdf.format(Calendar.getInstance().getTime()));
+		File logFile = File.createTempFile("prottest3_"+sdf.format(Calendar.getInstance().getTime())+"_",
+			 ".log", logDir);
+                FileOutputStream fos = new FileOutputStream(logFile);
+                logHandler = new StreamHandler(fos, new ProtTestLogFormatter());
+                logHandler.setLevel(Level.parse(level));
+            }
+
+        }
+        return logHandler;
+
+    }
+
+    /**
+     * Creates a new ProtTest object.
+     *
+     * @return the prints the framework
+     */
+    public PrintFramework createPrintFramework() {
+        PrintFramework pf = null;
+
+        switch (sort) {
+            case PROTEIC:
+                pf = new AminoAcidPrintFramework();
+                break;
+            case NUCLEIC:
+                throw new ProtTestInternalException("Unsupported operation: nucleic data");
+        }
+
+        return pf;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/factory/package.html b/src/main/java/es/uvigo/darwin/prottest/util/factory/package.html
new file mode 100755
index 0000000..da0f30b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/factory/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains the application factory.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/fileio/AlignmentReader.java b/src/main/java/es/uvigo/darwin/prottest/util/fileio/AlignmentReader.java
new file mode 100755
index 0000000..b39a4c1
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/fileio/AlignmentReader.java
@@ -0,0 +1,285 @@
+/*
+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.prottest.util.fileio;
+
+import converter.Converter;
+import converter.DefaultFactory;
+import converter.Factory;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.PushbackReader;
+
+import es.uvigo.darwin.prottest.util.exception.AlignmentParseException;
+import es.uvigo.darwin.prottest.util.exception.TreeFormatException;
+
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import pal.alignment.Alignment;
+import pal.alignment.ReadAlignment;
+import pal.tree.ReadTree;
+import pal.tree.Tree;
+import pal.tree.TreeParseException;
+
+// TODO: Auto-generated Javadoc
+import parser.ParseException;
+/**
+ * The Class AlignmentReader.
+ */
+public class AlignmentReader {
+
+    /**
+     * Instantiates a new alignment reader.
+     */
+    public AlignmentReader() {
+
+    }
+
+    /**
+     * Read alignment.
+     * 
+     * @param output the output writer
+     * @param filename the filename
+     * @param debug the debug
+     * 
+     * @return the alignment
+     * 
+     * @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 Alignment readAlignment(PrintWriter output, String filename, boolean debug)
+            throws AlignmentParseException, FileNotFoundException, IOException {
+
+        Alignment alignment;
+        StringBuilder text = new StringBuilder();
+
+        BufferedReader br = new BufferedReader(new FileReader(filename));
+        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";
+        String os = System.getProperty("os.name");
+        if (os.startsWith("Mac")) {
+            outO = "MacOS";
+        } else if (os.startsWith("Linux")) {
+            outO = "Linux";
+        } else if (os.startsWith("Win")) {
+            outO = "Windows";
+        }
+        String outP = "ProtTest";
+        String outF = "PHYLIP";
+        boolean lower = false;
+        boolean numbers = false;
+        boolean sequential = true;
+        boolean match = false;
+
+        //Get converter and convert MSA
+        Factory factory = new DefaultFactory();
+        Converter converter;
+
+        //Inicializar logger
+        Logger logger = Logger.getLogger("alter" + System.currentTimeMillis());
+        logger.setUseParentHandlers(false);
+        logger.setLevel(Level.ALL);
+        for (Handler handler : ProtTestLogger.getDefaultLogger().getHandlers()) {
+            logger.addHandler(handler);
+        }
+
+        try {
+            converter = factory.getConverter(inO, inP, inF, autodetect,
+                    collapse, gaps, missing, limit,
+                    outO, outP, outF, lower, numbers, sequential, match, logger.getName());
+            out = converter.convert(in);
+        } catch (UnsupportedOperationException ex) {
+            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());
+        }
+
+        try {
+        	PushbackReader pr = new PushbackReader(new StringReader(out));
+        	alignment = readAlignment(output, pr, debug);
+        } catch (AlignmentParseException ex) {
+        	sequential = false;
+        	try {
+                converter = factory.getConverter(inO, inP, inF, autodetect,
+                        collapse, gaps, missing, limit,
+                        outO, outP, outF, lower, numbers, sequential, match, logger.getName());
+                out = converter.convert(in);
+            } catch (UnsupportedOperationException exUO) {
+                throw new AlignmentParseException("There's some error in your data: " + ex.getMessage());
+            } catch (ParseException exP) {
+                throw new AlignmentParseException("There's some error in your data: " + ex.getMessage());
+            }
+        	PushbackReader pr = new PushbackReader(new StringReader(out));
+        	alignment = readAlignment(output, pr, debug);
+        }
+        
+        if (alignment == null) {
+            throw new AlignmentParseException("There's some error in your data, exiting...");
+        }
+
+        return alignment;
+    }
+
+    /**
+     * Read alignment.
+     * 
+     * @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 readAlignment(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 = (String) 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);
+                }
+            }
+        }
+
+        //TODO: print TAXA and check if data is in correct format
+        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;
+    }
+
+    /**
+     * Read tree.
+     * 
+     * @param out the out
+     * @param filename the filename
+     * @param debug the debug
+     * 
+     * @return the tree
+     * 
+     * @throws TreeFormatException When the input filename is not in the right format
+     * @throws FileNotFoundException Signals that the input filename does not exist.
+     * @throws IOException Signals that an I/O exception has occured.
+     */
+    public static Tree readTree(PrintWriter out, String filename, boolean debug)
+            throws TreeFormatException, FileNotFoundException, IOException {
+        //FOR PHYML:
+        //if tree is not in newick format, reformat and save to a new file:
+        //TreeUtils: public static void printNH(Tree tree, java.io.PrintWriter out)
+        if (debug) {
+            out.println("Reading tree...");
+        }
+        Tree tree;
+        try {
+            tree = new ReadTree(filename);
+        } catch (TreeParseException e) {
+            throw new TreeFormatException("Error: Wrong tree format : " + e.getMessage());
+        }
+        if (debug) {
+            out.println("Tree contains " + tree.getExternalNodeCount() + " external nodes");
+            out.println("");
+        }
+        return tree;
+    }
+
+    /**
+     * Read tree.
+     * 
+     * @param out the out
+     * @param in the tree pushback reader
+     * @param debug the debug
+     * 
+     * @return the tree
+     * 
+     * @throws TreeFormatException the tree format exception
+     */
+    public static Tree readTree(PrintWriter out, PushbackReader in, boolean debug)
+            throws TreeFormatException {
+        //FOR PHYML:
+        //if tree is not in newick format, reformat and save to a new file:
+        //TreeUtils: public static void printNH(Tree tree, java.io.PrintWriter out)
+        if (debug) {
+            out.println("Reading tree...");
+        }
+        Tree tree;
+        try {
+            tree = new ReadTree(in);
+        } catch (TreeParseException e) {
+            throw new TreeFormatException("Error: Wrong tree format : " + e.getMessage());
+        }
+        if (debug) {
+            out.println("Tree contains " + tree.getExternalNodeCount() + " external nodes");
+            out.println("");
+        }
+        return tree;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/fileio/ImportHelper.java b/src/main/java/es/uvigo/darwin/prottest/util/fileio/ImportHelper.java
new file mode 100755
index 0000000..05023c1
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/fileio/ImportHelper.java
@@ -0,0 +1,573 @@
+/*
+ * ImportHelper.java
+ *
+ * (c) 2002-2005 BEAST Development Core Team
+ *
+ * This package may be distributed under the
+ * Lesser Gnu Public Licence (LGPL)
+ */
+package es.uvigo.darwin.prottest.util.fileio;
+
+import es.uvigo.darwin.prottest.util.exception.ImportException;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * A helper class for phylogenetic file format importers
+ *
+ * @author Andrew Rambaut
+ * @author Alexei Drummond
+ *
+ * @version $Id: ImportHelper.java 699 2007-04-28 07:07:49Z matthew_cheung $
+ */
+public class ImportHelper {
+    private long totalCharactersRead = 0;
+
+    // Expected length of input in bytes, or 0 if unknown
+    private long expectedInputLength = 0;
+
+    /**
+     * ATTENTION: The ImportHelper never closes the reader passed to the constructor.
+     * If the reader holds resources (e.g. a FileReader, which holds an open file),
+     * then it is the client class' responsibility to close the reader when it has
+     * finished using it.
+     * @param reader
+     */
+    public ImportHelper(Reader reader) {
+        this.reader = new LineNumberReader(reader);
+        this.commentWriter = null;
+    }
+
+    public void setExpectedInputLength(long l) {
+        this.expectedInputLength = l;
+    }
+
+    public ImportHelper(Reader reader, Writer commentWriter) {
+        this.reader = new LineNumberReader(reader);
+        this.commentWriter = commentWriter;
+    }
+
+    /**
+     * @return  If the length of the input is known (because a file was
+     * passed to the constructor), this reports a value between 0.0 and 1.0
+     * indicating the relative read position in the file. Otherwise, this
+     * always returns 0.0.
+     *
+     * This method assumes that all characters in the input are one byte
+     * long (to get its estimate, it divides the number of *characters* read
+     * by the number of *bytes* in the file). If there is an efficient way
+     * to fix this, we should do so :)
+     */
+    public double getProgress() {
+        if (expectedInputLength == 0) {
+            return 0.0;
+        } else {
+            return (double) totalCharactersRead / expectedInputLength;
+        }
+    }
+
+    public void closeReader() throws IOException {
+        reader.close();
+    }
+
+    public void setCommentDelimiters(char line) {
+        hasComments = true;
+        this.lineComment = line;
+    }
+
+    public void setCommentDelimiters(char start, char stop) {
+        hasComments = true;
+        this.startComment = start;
+        this.stopComment = stop;
+    }
+
+    public void setCommentDelimiters(char start, char stop, char line) {
+        hasComments = true;
+        this.startComment = start;
+        this.stopComment = stop;
+        this.lineComment = line;
+    }
+
+    public void setCommentDelimiters(char start, char stop, char line, char write, char meta) {
+        hasComments = true;
+        this.startComment = start;
+        this.stopComment = stop;
+        this.lineComment = line;
+        this.writeComment = write;
+        this.metaComment = meta;
+    }
+
+    public void setCommentWriter(Writer commentWriter) {
+        this.commentWriter = commentWriter;
+    }
+
+    public int getLineNumber() {
+        return reader.getLineNumber();
+    }
+
+    public int getLastDelimiter() {
+        return lastDelimiter;
+    }
+
+    public char nextCharacter() throws IOException {
+        if (lastChar == '\0') {
+            lastChar = readCharacter();
+        }
+        return (char)lastChar;
+    }
+
+    public char readCharacter() throws IOException {
+
+        skipSpace();
+
+        char ch = read();
+
+        while (hasComments && (ch == startComment || ch == lineComment)) {
+            skipComments(ch);
+            skipSpace();
+            ch = read();
+        }
+
+        return ch;
+    }
+
+    public void unreadCharacter(char ch) {
+        lastChar = ch;
+    }
+
+    public char next() throws IOException {
+        if (lastChar == '\0') {
+            lastChar = read();
+        }
+        return (char)lastChar;
+    }
+
+    /**
+     * All read attempts pass through this function.
+     * 
+     * @return the next char
+     * @throws IOException
+     */
+    public char read() throws IOException {
+        int ch;
+        if (lastChar == '\0') {
+            // this is the only point where anything is read from the reader
+            ch = reader.read();
+            if (ch != -1) {
+                totalCharactersRead++;
+            } else {
+                throw new EOFException();
+            }
+        } else {
+            ch = lastChar;
+            lastChar = '\0';
+        }
+        return (char)ch;
+    }
+
+    /**
+     * Reads a line, skipping over any comments.
+     */
+    public String readLine() throws IOException {
+
+        StringBuffer line = new StringBuffer();
+        char ch = read();
+        try {
+            while (ch != '\n' && ch != '\r') {
+                if (hasComments) {
+                    if (ch == lineComment) {
+                        skipComments(ch);
+                        break;
+                    }
+                    if (ch == startComment) {
+                        skipComments(ch);
+                        ch = read();
+                    }
+                }
+                line.append(ch);
+                ch = read();
+            }
+
+            // accommodate DOS line endings..
+            if (ch == '\r') {
+                if (next() == '\n') read();
+            }
+            lastDelimiter = ch;
+
+        } catch (EOFException e) {
+            // We catch an EOF and return the line we have so far
+//            encounteredEndOfFile();
+        }
+
+        return line.toString();
+    }
+
+    /**
+     * Attempts to read and parse an integer delimited by whitespace.
+     */
+    public int readInteger() throws IOException, ImportException {
+        String token = readToken();
+        try {
+            return Integer.parseInt(token);
+        } catch (NumberFormatException nfe) {
+            throw new ImportException("Number format error: " + nfe.getMessage());
+        }
+    }
+
+    /**
+     * Attempts to read and parse an integer delimited by whitespace or by
+     * any character in delimiters.
+     */
+    public int readInteger(String delimiters) throws IOException, ImportException {
+        String token = readToken(delimiters);
+        try {
+            return Integer.parseInt(token);
+        } catch (NumberFormatException nfe) {
+            throw new ImportException("Number format error: " + nfe.getMessage());
+        }
+    }
+
+    /**
+     * Attempts to read and parse a double delimited by whitespace.
+     */
+    public double readDouble() throws IOException, ImportException {
+        String token = readToken();
+        try {
+            return Double.parseDouble(token);
+        } catch (NumberFormatException nfe) {
+            throw new ImportException("Number format error: " + nfe.getMessage());
+        }
+    }
+
+    /**
+     * Attempts to read and parse a double delimited by whitespace or by
+     * any character in delimiters.
+     */
+    public double readDouble(String delimiters) throws IOException, ImportException {
+        String token = readToken(delimiters);
+        try {
+            return Double.parseDouble(token);
+        } catch (NumberFormatException nfe) {
+            throw new ImportException("Number format error: " + nfe.getMessage());
+        }
+    }
+
+    /**
+     * Reads a token stopping when any whitespace or a comment is found.
+     * If the token begins with a quote char then all characters will be
+     * included in token until a matching quote is found (including whitespace or comments).
+     */
+    public String readToken() throws IOException {
+        return readToken("");
+    }
+
+    /**
+     * Reads a token stopping when any whitespace, a comment or when any character
+     * in delimiters is found. If the token begins with a quote char
+     * then all characters will be included in token until a matching
+     * quote is found (including whitespace or comments).
+     */
+    public String readToken(String delimiters) throws IOException {
+        int space = 0;
+        char ch, ch2, quoteChar = '\0';
+        boolean done = false, first = true, quoted = false, isSpace;
+
+        nextCharacter();
+
+        StringBuffer token = new StringBuffer();
+
+        while (!done) {
+            ch = read();
+
+            try {
+                isSpace = Character.isWhitespace(ch);
+
+                if (quoted && ch == quoteChar) { // Found the closing quote
+                    ch2 = read();
+
+                    if (ch == ch2) {
+                        // A repeated quote character so add this to the token
+                        token.append(ch);
+                    } else {
+                        // otherwise it terminates the token
+
+                        lastDelimiter = ' ';
+
+                        if (hasComments && (ch2 == startComment || ch2 == lineComment)) {
+                            skipComments(ch2, startComment!= '\"' && startComment != '\'');
+                        } else {
+                            unreadCharacter(ch2);
+                        }
+                        done = true;
+                        quoted = false;
+                    }
+                } else if (first && (ch == '\'' || ch == '"')) {
+                    // if the opening character is a quote
+                    // read everything up to the closing quote
+                    quoted = true;
+                    quoteChar = ch;
+                    first = false;
+                    space = 0;
+                } else if (!quoted && (ch == startComment || ch == lineComment) ) {
+                    // comment markers don't count if we are quoted
+                    skipComments(ch, startComment!= '\"' && startComment != '\'');
+                    lastDelimiter = ' ';
+                    done = true;
+                } else {
+                    if (quoted) {
+                        token.append(ch);
+                    } else if (isSpace) {
+                        lastDelimiter = ' ';
+                        done = true;
+                    } else if (delimiters.indexOf(ch) != -1) {
+                        done = true;
+                        lastDelimiter = ch;
+                    } else {
+                        token.append(ch);
+                        first = false;
+                    }
+                }
+            } catch (EOFException e) {
+                // We catch an EOF and return the token we have so far
+                done = true;
+            }
+        }
+
+        if (Character.isWhitespace((char)lastDelimiter)) {
+            ch = nextCharacter();
+            while (Character.isWhitespace(ch)) {
+                read();
+                ch = nextCharacter();
+            }
+
+            if (delimiters.indexOf(ch) != -1) {
+                lastDelimiter = readCharacter();
+            }
+        }
+
+        return token.toString();
+    }
+
+    /**
+     * Skips over any comments. The opening comment delimiter is passed.
+     * @param delimiter
+     * @throws java.io.IOException
+     */
+    protected void skipComments(char delimiter) throws IOException {
+       skipComments(delimiter, false);
+    }
+
+    /**
+     * Skips over any comments. The opening comment delimiter is passed.
+     * @param delimiter 
+     * @param gobbleStrings
+     * @throws java.io.IOException
+     */
+    protected void skipComments(char delimiter, boolean gobbleStrings) throws IOException {
+
+        char ch;
+        int n=1;
+        boolean write = true;
+        StringBuffer meta = null;
+
+        if (lastComment == null) {
+            lastComment = new StringBuffer();
+        }
+        if (nextCharacter() == writeComment) {
+            read();
+//            if (commentWriter != null) {
+//                commentWriter.write(writeComment);
+//            }
+        } else if (nextCharacter() == metaComment) {
+            read();
+            meta = new StringBuffer();
+            write = false;
+        }
+        lastMetaComment = null;
+
+        if (delimiter == lineComment) {
+            String line = readLine();
+            if (write && commentWriter != null) {
+                commentWriter.write(line, 0, line.length());
+                commentWriter.write('\n');//.newLine();
+            } else if (meta != null) {
+                meta.append(line);
+            }
+        } else {
+            Character inString = null;
+            do {
+                ch = read();
+
+                if( ch == '\"' || ch == '\'' ) {
+                    if( gobbleStrings ) {
+                        if( inString == null ) {
+                            inString = ch;
+                        } else if( inString == ch ) {
+                          inString = null;
+                        }
+                    }
+                }
+                if( inString == null )  {
+                    if (ch == startComment) {
+                        lastComment = new StringBuffer();
+                        n++;
+                        continue;
+                    } else if (ch == stopComment) {
+                        if (write && commentWriter != null) {
+                            if (lastComment.toString().contains("ID")) {
+                                commentWriter.write(lastComment.toString());
+                            } 
+                            lastComment = new StringBuffer();
+                        }
+//                        if (write && commentWriter != null) {
+//                            commentWriter.write('\n');//.newLine();
+//                        }
+                        n--;
+                        continue;
+                    }
+                }
+
+                if (write && commentWriter != null) {
+                    lastComment.append(ch);
+//                    commentWriter.write(ch);
+                } else if (meta != null) {
+                    meta.append(ch);
+                }
+            } while (n > 0);
+
+        }
+
+        if (meta != null) {
+            lastMetaComment = meta.toString();
+        }
+    }
+
+    /**
+     * Skips to the end of the line. If a comment is found then this is read.
+     */
+    public void skipToEndOfLine() throws IOException {
+
+        char ch;
+
+        do {
+            ch = read();
+            if (hasComments) {
+                if (ch == lineComment) {
+                    skipComments(ch);
+                    break;
+                }
+                if (ch == startComment) {
+                    skipComments(ch);
+                    ch = read();
+                }
+            }
+
+        } while (ch != '\n' && ch != '\r');
+
+        if (ch == '\r') {
+            if (nextCharacter() == '\n') read();
+        }
+    }
+
+    /**
+     * Skips char any contiguous characters in skip. Will also skip
+     * comments.
+     */
+    public void skipWhile(String skip) throws IOException {
+
+        char ch;
+
+        do {
+            ch = read();
+        } while ( skip.indexOf(ch) > -1 );
+
+        unreadCharacter(ch);
+    }
+
+    /**
+     * Skips over any space (plus tabs and returns) in the file. Will also skip
+     * comments.
+     */
+    public void skipSpace() throws IOException {
+        skipWhile(" \t\r\n");
+    }
+
+    /**
+     * Skips over any contiguous characters in skip. Will also skip
+     * comments and space.
+     */
+    public void skipCharacters(String skip) throws IOException {
+        skipWhile(skip + " \t\r\n");
+    }
+
+    /**
+     * Skips over the file until a character from delimiters is found. Returns
+     * the delimiter found. Will skip comments and will ignore delimiters within
+     * comments.
+     */
+    public char skipUntil(String skip) throws IOException {
+        char ch;
+
+        do {
+            ch = readCharacter();
+        } while ( skip.indexOf(ch) == -1 );
+
+        return ch;
+    }
+
+    public String getLastMetaComment() {
+        return lastMetaComment;
+    }
+
+    public void clearLastMetaComment() {
+        lastMetaComment = null;
+    }
+
+    static String safeName(String name) {
+        if( ! name.matches("[a-zA-Z0-9_.]+") ) {
+            name = "\"" + name + "\"";
+        }
+        return name;
+    }
+
+    /**
+     * Convert control (unprintable) characters to something printable
+     * @param token
+     * @return token printable version
+     */
+    static String convertControlsChars(String token) {
+        if( ! token.matches("[^\\p{Cntrl}]+") ) {
+            StringBuilder b = new StringBuilder();
+            for( char c : token.toCharArray() ) {
+                if( c < 0x20 || c >= 0xfe ) {
+                    b.append("#").append(Integer.toHexString(c));
+                } else {
+                    b.append(c);
+                }
+            }
+            return b.toString();
+        }
+        return token;
+    }
+
+    // Private stuff
+
+    private LineNumberReader reader;
+    private Writer commentWriter = null;
+
+    private int lastChar = '\0';
+    private int lastDelimiter = '\0';
+
+    private boolean hasComments = false;
+    private char startComment = (char)-1;
+    private char stopComment = (char)-1;
+    private char lineComment = (char)-1;
+    private char writeComment = (char)-1;
+    private char metaComment = (char)-1;
+
+    private StringBuffer lastComment;
+    private String lastMetaComment = null;
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/fileio/NexusExporter.java b/src/main/java/es/uvigo/darwin/prottest/util/fileio/NexusExporter.java
new file mode 100755
index 0000000..9250c53
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/fileio/NexusExporter.java
@@ -0,0 +1,248 @@
+/*
+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.prottest.util.fileio;
+
+import es.uvigo.darwin.prottest.tree.TreeUtils;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import pal.tree.Tree;
+
+/**
+ *
+ * @author Diego Darriba
+ */
+public class NexusExporter {
+
+    private static final String HEADER = "#NEXUS";
+    private File outFile;
+    private PrintWriter outputWriter;
+
+    private enum NexusBlock {
+
+        TAXA {
+
+            public void beginSection(PrintWriter outputWriter) {
+                outputWriter.println("begin taxa;");
+            }
+
+            public void endSection(PrintWriter outputWriter) {
+                outputWriter.println("end taxa;");
+            }
+
+            public String getSectionName() {
+                return "taxa";
+            }
+
+            public void export(PrintWriter outputWriter, List taxa, Properties properties) {
+
+            }
+        },
+        TREES {
+
+            public void beginSection(PrintWriter outputWriter) {
+                outputWriter.println("begin trees;");
+            }
+
+            public void endSection(PrintWriter outputWriter) {
+                outputWriter.println("end trees;");
+            }
+
+            public String getSectionName() {
+                return "trees";
+            }
+
+            public void export(PrintWriter outputWriter, List trees, Properties properties) {
+
+                printBlankLine(outputWriter);
+                for (Object o : trees) {
+                    if (!(o instanceof Tree)) {
+                        throw new TypeMismatchException(Tree.class, o.getClass());
+                    }
+
+                    Tree tree = (Tree) o;
+
+                    boolean printCladeSupport = properties.getProperty(PRINT_CLADE_SUPPORT, "false").equalsIgnoreCase("true");
+                    String treeName = (String) tree.getAttribute(tree.getRoot(), TreeUtils.TREE_NAME_ATTRIBUTE);
+                    String treeNewick = TreeUtils.toNewick(tree, true, true, printCladeSupport);
+
+                    outputWriter.print("    " + treeName + " = ");
+                    outputWriter.println(treeNewick);
+                }
+                printBlankLine(outputWriter);
+
+            }
+        },
+        CONSENSUS {
+
+            public void beginSection(PrintWriter outputWriter) {
+                TREES.beginSection(outputWriter);
+            }
+
+            public void endSection(PrintWriter outputWriter) {
+                TREES.endSection(outputWriter);
+            }
+
+            public void export(PrintWriter outputWriter, List trees, Properties properties) {
+
+                printBlankLine(outputWriter);
+                String fullTreeComment = "Note: This tree contains information on the topology," +
+                        " branch lengths (if present), and the probability " +
+                        " of the partition indicated by the branch.";
+                addComment(outputWriter, fullTreeComment, 0);
+
+                properties.setProperty(PRINT_CLADE_SUPPORT, "true");
+                TREES.export(outputWriter, trees, properties);
+
+                String simpleTreeComment = "Note: This tree contains information only on the topology" +
+                        " and branch lengths (mean of the posterior probability density).";
+                addComment(outputWriter, simpleTreeComment, 0);
+
+                properties.setProperty(PRINT_CLADE_SUPPORT, "false");
+                TREES.export(outputWriter, trees, properties);
+                printBlankLine(outputWriter);
+            }
+        },
+        DEFAULT {
+
+            public void beginSection(PrintWriter outputWriter) {
+                throw new UndefinedBlockException();
+            }
+
+            public void endSection(PrintWriter outputWriter) {
+                throw new UndefinedBlockException();
+            }
+
+            public void export(PrintWriter outputWriter, List objects, Properties properties) {
+                throw new UndefinedBlockException();
+            }
+        };
+        public static final String PRINT_CLADE_SUPPORT = "pcs";
+
+        public void addComment(PrintWriter outputWriter, String comment, int lineWidth) {
+
+            comment = "[" + comment + "] ";
+            int commentLength = comment.length();
+
+            if (lineWidth <= 0) {
+                lineWidth = comment.length();
+            }
+
+            int column = 0;
+            while (column < commentLength) {
+                String toWrite;
+                if (column + lineWidth + 1 < comment.length()) {
+                    toWrite = comment.substring(column, column + lineWidth + 1);
+                } else {
+                    toWrite = comment.substring(column);
+                }
+                int toWriteLength = toWrite.lastIndexOf(" ");
+                if (toWriteLength > 0 && toWriteLength < toWrite.length()) {
+                    outputWriter.println(toWrite.substring(0, toWriteLength));
+                } else {
+                    toWriteLength = lineWidth;
+                    outputWriter.println(toWrite);
+                }
+                column += toWriteLength;
+            }
+
+        }
+
+        public void printBlankLine(PrintWriter outputWriter) {
+            outputWriter.println(" ");
+        }
+        
+        public abstract void beginSection(PrintWriter outputWriter);
+
+        public abstract void endSection(PrintWriter outputWriter);
+
+        public abstract void export(PrintWriter outputWriter, List objects, Properties properties);
+
+        private static class TypeMismatchException extends ProtTestInternalException {
+
+            public TypeMismatchException(Class classRequired, Class classObtained) {
+                super("Required class " + classRequired + " but obtained " + classObtained);
+            }
+            
+        }
+
+        private static class UndefinedBlockException extends ProtTestInternalException {
+
+            public UndefinedBlockException() {
+                super("No Nexus block is defined");
+            }
+            
+        }
+    }
+
+    public NexusExporter(File outFile) throws IOException {
+
+        this.outFile = outFile;
+        if (!outFile.exists()) {
+            outFile.createNewFile();
+        }
+
+        this.outputWriter = new PrintWriter(outFile);
+
+        initStructure(this.outputWriter);
+
+    }
+
+    public void printTreeBlock(List<Tree> trees) {
+        NexusBlock treeBlock = NexusBlock.TREES;
+
+        treeBlock.beginSection(outputWriter);
+        treeBlock.export(outputWriter, trees, new Properties());
+        treeBlock.endSection(outputWriter);
+
+    }
+
+    public void printConsensusBlock(Tree tree, String id) {
+        NexusBlock treeBlock = NexusBlock.CONSENSUS;
+
+        List<Tree> trees = new ArrayList<Tree>();
+        trees.add(tree);
+
+        if (id != null) {
+            treeBlock.addComment(outputWriter, id, 0);
+        }
+        treeBlock.beginSection(outputWriter);
+        treeBlock.export(outputWriter, trees, new Properties());
+        treeBlock.endSection(outputWriter);
+
+    }
+
+    public void printComment(String msg, int colWidth) {
+        NexusBlock.DEFAULT.addComment(outputWriter, msg, colWidth);
+    }
+
+    public void close() {
+        outputWriter.close();
+    }
+
+    private void initStructure(PrintWriter outputWriter) {
+
+        outputWriter.println(HEADER);
+        outputWriter.println(" ");
+
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/fileio/NexusImporter.java b/src/main/java/es/uvigo/darwin/prottest/util/fileio/NexusImporter.java
new file mode 100755
index 0000000..92cd9ea
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/fileio/NexusImporter.java
@@ -0,0 +1,686 @@
+package es.uvigo.darwin.prottest.util.fileio;
+
+/*
+ * NexusImporter.java
+ *
+ * (c) 2002-2005 JEBL development team
+ *
+ * This package may be distributed under the
+ * Lesser Gnu Public Licence (LGPL)
+ */
+import es.uvigo.darwin.prottest.util.attributable.Attributable;
+import es.uvigo.darwin.prottest.taxa.Taxon;
+import es.uvigo.darwin.prottest.tree.TreeUtils;
+import es.uvigo.darwin.prottest.util.exception.ImportException;
+import pal.tree.SimpleTree;
+import pal.tree.Tree;
+
+import java.awt.*;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.*;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import pal.misc.Identifier;
+import pal.tree.Node;
+import pal.tree.NodeFactory;
+
+/**
+ * Class for importing NEXUS file format
+ *
+ * @version $Id: NexusImporter.java 723 2007-06-11 05:40:44Z matt_kearse $
+ *
+ * @author Andrew Rambaut
+ * @author Alexei Drummond
+ */
+public class NexusImporter {
+
+    public enum NexusBlock {
+
+        UNKNOWN,
+        TAXA,
+        CHARACTERS,
+        DATA,
+        UNALIGNED,
+        DISTANCES,
+        TREES
+    }
+    
+    private boolean compactTrees = false;
+    private Writer commentWriter;
+    private String nexusId;
+    
+    public String getNexusId() {
+        return nexusId;
+    }
+    
+    // NEXUS specific ImportException classes
+    public static class MissingBlockException extends ImportException {
+
+        public MissingBlockException() {
+            super();
+        }
+
+        public MissingBlockException(String message) {
+            super(message);
+        }
+    }
+
+    /**
+     * Constructor
+     */
+    public NexusImporter(Reader reader, long expectedLength) {
+        helper = new ImportHelper(reader);
+        helper.setExpectedInputLength(expectedLength);
+        initHelper();
+    }
+
+    /**
+     * Constructor
+     */
+    public NexusImporter(Reader reader) {
+        this(reader, 0);
+    }
+
+    public NexusImporter(Reader reader, boolean compactTrees, long expectedInputLength) {
+        this(reader, expectedInputLength);
+        this.compactTrees = compactTrees;
+    }
+
+    private void initHelper() {
+        // ! defines a comment to be written out to a log file
+        // & defines a meta comment
+        helper.setCommentDelimiters('[', ']', '\0', '!', '&');
+        commentWriter = new StringWriter();
+        helper.setCommentWriter(commentWriter);
+    }
+
+//    public long findId() {
+//        
+//    }
+    
+    /**
+     * This function returns an integer to specify what the
+     * next block in the file is. The internal variable nextBlock is also set to this
+     * value. This should be overridden to provide support for other blocks. Once
+     * the block is read in, nextBlock is automatically set to UNKNOWN_BLOCK by
+     * findEndBlock.
+     */
+    public NexusBlock findNextBlock() throws IOException {
+        findToken("BEGIN", true);
+        nextBlockName = helper.readToken(";").toUpperCase();
+        return findBlockName(nextBlockName);
+    }
+
+    /**
+     * This function returns an enum class to specify what the
+     * block given by blockName is.
+     */
+    private NexusBlock findBlockName(String blockName) {
+        try {
+            nextBlock = NexusBlock.valueOf(blockName);
+        } catch (IllegalArgumentException e) {
+            // handle unknown blocks. java 1.5 throws an exception in valueOf
+            nextBlock = null;
+        }
+
+        if (nextBlock == null) {
+            nextBlock = NexusBlock.UNKNOWN;
+        }
+
+        return nextBlock;
+    }
+
+    public String getNextBlockName() {
+        return nextBlockName;
+    }
+
+    /**
+     * Returns an iterator over a set of elements of type T.
+     *
+     * @return an Iterator.
+     */
+    public Iterator<Tree> iterator() {
+        return new Iterator<Tree>() {
+
+            public boolean hasNext() {
+                boolean hasNext = false;
+                try {
+                    hasNext = hasTree();
+                } catch (IOException e) {
+                // deal with errors by stopping the iteration
+                } catch (ImportException e) {
+                // deal with errors by stopping the iteration
+                }
+                return hasNext;
+            }
+
+            public Tree next() {
+                Tree tree = null;
+                try {
+                    tree = importNextTree();
+                } catch (IOException e) {
+                // deal with errors by stopping the iteration
+                } catch (ImportException e) {
+                // deal with errors by stopping the iteration
+                }
+                if (tree == null) {
+                    throw new NoSuchElementException("No more trees in this file");
+                }
+                return tree;
+            }
+
+            public void remove() {
+                throw new UnsupportedOperationException("operation is not supported by this Iterator");
+            }
+        };
+    }
+
+    /**
+     * Parses a 'TREES' block.
+     */
+    public List<Tree> parseTreesBlock(List<Taxon> taxonList) throws ImportException, IOException {
+        return readTreesBlock(taxonList);
+    }
+
+    // **************************************************************
+    // TreeImporter IMPLEMENTATION
+    // **************************************************************
+    private boolean isReadingTreesBlock = false;
+    private List<Taxon> treeTaxonList = null;
+    private Map<String, Taxon> translationList = Collections.emptyMap();
+    private Tree nextTree = null;
+    private String[] lastToken = new String[1];
+
+    /**
+     * return whether another tree is available.
+     */
+    public boolean hasTree() throws IOException, ImportException {
+        if (!isReadingTreesBlock) {
+            isReadingTreesBlock = startReadingTrees();
+            translationList = readTranslationList(treeTaxonList, lastToken);
+        }
+
+        if (!isReadingTreesBlock) {
+            return false;
+        }
+
+        if (nextTree == null) {
+            nextTree = readNextTree(lastToken);
+        }
+
+        return (nextTree != null);
+    }
+
+    /**
+     * import the next tree.
+     * return the tree or null if no more trees are available
+     */
+    public Tree importNextTree() throws IOException, ImportException {
+        // call hasTree to do the hard work...
+        if (!hasTree()) {
+            isReadingTreesBlock = false;
+            return null;
+        }
+
+        Tree tree = nextTree;
+        nextTree = null;
+
+        return tree;
+    }
+
+    public List<Tree> importTrees() throws IOException, ImportException {
+        isReadingTreesBlock = false;
+        if (!startReadingTrees()) {
+            throw new MissingBlockException("TREES block is missing");
+        }
+        List<Tree> treesBlock = readTreesBlock(treeTaxonList);
+        helper.closeReader();
+        nexusId = commentWriter.toString();
+        commentWriter.close();
+        return treesBlock;
+    }
+
+    public boolean startReadingTrees() throws IOException, ImportException {
+        treeTaxonList = null;
+
+        while (true) {
+            try {
+                NexusBlock block = findNextBlock();
+                switch (block) {
+//					case TAXA: treeTaxonList = readTaxaBlock(); break;
+                    case TREES:
+                        return true;
+                    // Ignore the block..
+                    default:
+                        break;
+                }
+            } catch (EOFException ex) {
+                break;
+            }
+        }
+
+        return false;
+    }
+
+    // **************************************************************
+    // DistanceMatrixImporter IMPLEMENTATION
+    // **************************************************************
+
+    // **************************************************************
+    // PRIVATE Methods
+    // **************************************************************
+    /**
+     * Finds the end of the current block.
+     */
+    private void findToken(String query, boolean ignoreCase) throws IOException {
+        String token;
+        boolean found = false;
+
+        do {
+            token = helper.readToken();
+
+            if ((ignoreCase && token.equalsIgnoreCase(query)) || token.equals(query)) {
+                found = true;
+            }
+        } while (!found);
+    }
+
+    /**
+     * Finds the end of the current block.
+     */
+    public void findEndBlock() throws IOException {
+        try {
+            String token;
+
+            do {
+                token = helper.readToken(";");
+            } while (!token.equalsIgnoreCase("END") && !token.equalsIgnoreCase("ENDBLOCK"));
+        } catch (EOFException e) {
+        // Doesn't matter if the End is missing
+        }
+
+        nextBlock = NexusBlock.UNKNOWN;
+    }
+
+    /**
+     * Reads a 'TREES' block.
+     */
+    private List<Tree> readTreesBlock(List<Taxon> taxonList) throws ImportException, IOException {
+        List<Tree> trees = new ArrayList<Tree>();
+        double cumWeight = 0.0;
+        
+        String[] localLastToken = new String[1];
+        translationList = readTranslationList(taxonList, localLastToken);
+
+        while (true) {
+
+            SimpleTree tree = readNextTree(localLastToken);
+
+            if (tree == null) {
+                break;
+            }
+
+            cumWeight += (Double) tree.getAttribute(tree.getRoot(), TreeUtils.TREE_WEIGHT_ATTRIBUTE);
+            trees.add(tree);
+            
+        }
+
+        if (trees.size() == 0) {
+            throw new ImportException.BadFormatException("No trees defined in TREES block");
+        }
+        
+        if (cumWeight > 1.0) {
+            // normalization is required
+            for (Tree tree : trees) {
+                double treeWeight = (Double) tree.getAttribute(tree.getRoot(), TreeUtils.TREE_WEIGHT_ATTRIBUTE);
+                treeWeight /= cumWeight;
+                tree.setAttribute(tree.getRoot(), TreeUtils.TREE_WEIGHT_ATTRIBUTE, treeWeight);
+            }
+        }
+
+        nextBlock = NexusBlock.UNKNOWN;
+
+        return trees;
+    }
+
+    private Map<String, Taxon> readTranslationList(List<Taxon> taxonList, String[] lastToken) throws ImportException, IOException {
+        Map<String, Taxon> localTranslationList = new HashMap<String, Taxon>();
+
+        String token = helper.readToken(";");
+
+        if (token.equalsIgnoreCase("TRANSLATE")) {
+
+            do {
+                String token2 = helper.readToken(",;");
+
+                if (helper.getLastDelimiter() == ',' || helper.getLastDelimiter() == ';') {
+                    if (token2.length() == 0 && (char) helper.getLastDelimiter() == ';') {
+                        //assume an extra comma at end of list
+                        break;
+
+                    }
+                    throw new ImportException.BadFormatException("Missing taxon label in TRANSLATE command of TREES block");
+                }
+
+                String token3 = helper.readToken(",;");
+
+                if (helper.getLastDelimiter() != ',' && helper.getLastDelimiter() != ';') {
+                    throw new ImportException.BadFormatException("Expecting ',' or ';' after taxon label in TRANSLATE command of TREES block");
+                }
+
+                Taxon taxon = Taxon.getTaxon(token3);
+
+                if (taxonList != null && !taxonList.contains(taxon)) {
+                    // taxon not found in taxon list...
+                    // ...perhaps it is a numerical taxon reference?
+                    throw new ImportException.UnknownTaxonException(token3);
+                }
+                localTranslationList.put(token2, taxon);
+
+            } while (helper.getLastDelimiter() != ';');
+
+            token = helper.readToken(";");
+
+        } else if (taxonList != null) {
+            for (Taxon taxon : taxonList) {
+                localTranslationList.put(taxon.getName(), taxon);
+            }
+        }
+
+        lastToken[0] = token;
+
+        return localTranslationList;
+    }
+
+    private SimpleTree readNextTree(String[] lastToken) throws ImportException, IOException {
+        try {
+            SimpleTree tree = null;
+            String token = lastToken[0];
+            double weight;
+            String treeName;
+
+            boolean isUnrooted = token.equalsIgnoreCase("UTREE");
+            if (isUnrooted || token.equalsIgnoreCase("TREE")) {
+
+                if (helper.nextCharacter() == '*') {
+                    // Star is used to specify a default tree - ignore it
+                    helper.readCharacter();
+                }
+
+                final String meta = helper.getLastMetaComment();
+                if (meta != null) {
+                    // Look for the unrooted meta comment [&U]
+                    if (meta.equalsIgnoreCase("U")) {
+                        isUnrooted = true;
+                    }
+                    helper.clearLastMetaComment();
+                }
+
+                treeName = helper.readToken("=;");
+
+                if (helper.getLastDelimiter() != '=') {
+                    throw new ImportException.BadFormatException("Missing label for tree'" + treeName + "' or missing '=' in TREE command of TREES block");
+                }
+
+                try {
+
+                    if (helper.nextCharacter() != '(') {
+                        throw new ImportException.BadFormatException("Missing tree definition in TREE command of TREES block");
+                    }
+
+                    // Save tree comment and attach it later
+                    final String comment = helper.getLastMetaComment();
+                    helper.clearLastMetaComment();
+
+                    Node internalNode = readInternalNode();
+                    tree = new SimpleTree(internalNode);
+                                        
+                    int last = helper.getLastDelimiter();
+                    if (last == ':') {
+                        // root length - discard for now
+						/*double rootLength = */ helper.readDouble(";");
+                        last = helper.getLastDelimiter();
+                    }
+
+                    if (last != ';') {
+                        throw new ImportException.BadFormatException("Expecting ';' after tree, '" + treeName + "', TREE command of TREES block");
+                    }
+
+                    weight = 1.0;
+                    if (comment != null) {
+                        // if '[W number]' (MrBayes), set weight attribute
+                        // ignore any other comment
+                        if (comment.matches("^W\\s+[\\+\\-]?[\\d\\.]+")) {
+                            weight = new Double(comment.substring(2));
+                        } 
+                    }
+                    tree.setAttribute(internalNode, TreeUtils.TREE_WEIGHT_ATTRIBUTE, weight);
+                    tree.setAttribute(internalNode, TreeUtils.TREE_NAME_ATTRIBUTE, treeName);
+
+                } catch (EOFException e) {
+                    // If we reach EOF we may as well return what we have?
+                    return tree;
+                }
+
+                token = helper.readToken(";");
+            } else if (token.equalsIgnoreCase("ENDBLOCK") || token.equalsIgnoreCase("END")) {
+                return null;
+            } else {
+                throw new ImportException.BadFormatException("Unknown command '" + token + "' in TREES block");
+            }
+
+            //added this to escape readNextTree loop correctly -- AJD
+            lastToken[0] = token;
+
+            return tree;
+
+        } catch (EOFException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Reads a branch in. This could be a node or a tip (calls readNode or readTip
+     * accordingly). It then reads the branch length and SimpleNode that will
+     * point at the new node or tip.
+     */
+    private Node readBranch() throws IOException, ImportException {
+        Node branch;
+
+        helper.clearLastMetaComment();
+        if (helper.nextCharacter() == '(') {
+            // is an internal node
+            branch = readInternalNode();
+
+        } else {
+            // is an external node
+            branch = readExternalNode();
+        }
+
+        if (helper.getLastDelimiter() == ':') {
+            final double length = helper.readDouble(",():;");
+            branch.setBranchLength(length);
+        }
+
+        return branch;
+    }
+
+    /**
+     * Reads a node in. This could be a polytomy. Calls readBranch on each branch
+     * in the node.
+     * @param tree
+     * @return
+     */
+    private Node readInternalNode() throws IOException, ImportException {
+        List<Node> children = new ArrayList<Node>();
+
+        // read the opening '('
+        helper.readCharacter();
+
+        // read the first child
+        children.add(readBranch());
+
+        if (helper.getLastDelimiter() != ',') {
+        //throw new ImportException.BadFormatException("Missing ',' in tree");
+        }
+        // MK: previously, an internal node must have at least 2 children.
+        // MK: We we now allow trees with a single child so that we can create proper taxonomy
+        // MK: trees with only a single child at a taxonomy level.
+
+        // read subsequent children
+
+        while (helper.getLastDelimiter() == ',') {
+            children.add(readBranch());
+        }
+
+        // should have had a closing ')'
+        if (helper.getLastDelimiter() != ')') {
+            throw new ImportException.BadFormatException("Missing closing ')' in tree");
+        }
+
+        Node node = NodeFactory.createNode(children.toArray(new Node[0]));
+
+        // find the next delimiter
+        String token = helper.readToken(":(),;").trim();
+
+        // if there is a token before the branch length, treat it as a node label
+        // and store it as an attribute of the node...
+        if (token.length() > 0) {
+            node.setIdentifier(new Identifier((String) parseValue(token)));
+        }
+
+        return node;
+    }
+
+    /**
+     * Reads an external node in.
+     */
+    private Node readExternalNode() throws ImportException, IOException {
+        String label = helper.readToken(":(),;");
+
+        Taxon taxon;
+        try {
+            taxon = Taxon.getTaxon(label);
+        } catch (IllegalArgumentException e) {
+            throw new ImportException.UnknownTaxonException(e.getMessage());
+        }
+
+        if (translationList.size() > 0) {
+            taxon = translationList.get(label);
+
+            if (taxon == null) {
+                // taxon not found in taxon list...
+                throw new ImportException.UnknownTaxonException("Taxon in tree, '" + label + "' is unknown");
+            }
+        }
+
+        try {
+            final Node node = NodeFactory.createNode(new Identifier(taxon.getName()));
+
+            return node;
+        } catch (IllegalArgumentException e) {
+            throw new ImportException.DuplicateTaxaException(e.getMessage());
+        }
+    }
+
+    static void parseMetaCommentPairs(String meta, Attributable item) throws ImportException.BadFormatException {
+        // This regex should match key=value pairs, separated by commas
+        // This can match the following types of meta comment pairs:
+        // value=number, value="string", value={item1, item2, item3}
+        // (label must be quoted if it contains spaces (i.e. "my label"=label)
+
+        Pattern pattern = Pattern.compile("(\"[^\"]*\"+|[^,=\\s]+)\\s*(=\\s*(\\{[^=}]*\\}|\"[^\"]*\"+|[^,]+))?");
+        Matcher matcher = pattern.matcher(meta);
+
+        while (matcher.find()) {
+            String label = matcher.group(1);
+            if (label.charAt(0) == '\"') {
+                label = label.substring(1, label.length() - 1);
+            }
+            if (label == null || label.trim().length() == 0) {
+                throw new ImportException.BadFormatException("Badly formatted attribute: '" + matcher.group() + "'");
+            }
+            final String value = matcher.group(2);
+            if (value != null && value.trim().length() > 0) {
+                // there is a specified value so try to parse it
+                item.setAttribute(label, parseValue(value.substring(1)));
+            } else {
+                item.setAttribute(label, Boolean.TRUE);
+            }
+        }
+    }
+
+    /**
+     * This method takes a string and tries to decode it returning the object
+     * that best fits the data. It will recognize command delimited lists enclosed
+     * in {..} and call parseValue() on each element. It will also recognize Boolean,
+     * Integer and Double. If the value starts with a # then it will attempt to decode
+     * the following integer as an RGB colour - see Color.decode(). If nothing else fits
+     * then the value will be returned as a string but trimmed of leading and trailing
+     * white space.
+     * @param value the string
+     * @return the object
+     */
+    static Object parseValue(String value) {
+
+        value = value.trim();
+
+        if (value.startsWith("{")) {
+            // the value is a list so recursively parse the elements
+            // and return an array
+            String[] elements = value.substring(1, value.length() - 1).split(",");
+            Object[] values = new Object[elements.length];
+            for (int i = 0; i < elements.length; i++) {
+                values[i] = parseValue(elements[i]);
+            }
+            return values;
+        }
+
+        if (value.startsWith("#")) {
+            // I am not sure whether this is a good idea but
+            // I am going to assume that a # denotes an RGB colour
+            try {
+                return Color.decode(value.substring(1));
+            } catch (NumberFormatException nfe1) {
+            // not a colour
+            }
+        }
+
+        // A string qouted by the nexus exporter and such
+        if (value.startsWith("\"") && value.endsWith("\"")) {
+            return value.subSequence(1, value.length() - 1);
+        }
+
+        if (value.equalsIgnoreCase("TRUE") || value.equalsIgnoreCase("FALSE")) {
+            return Boolean.valueOf(value);
+        }
+
+        // Attempt to format the value as an integer
+        try {
+            return Integer.parseInt(value);
+        } catch (NumberFormatException nfe1) {
+        // not an integer
+        }
+
+        // Attempt to format the value as a double
+        try {
+            return Double.parseDouble(value);
+        } catch (NumberFormatException nfe2) {
+        // not a double
+        }
+
+        // return the trimmed string
+        return value;
+    }
+
+    // private stuff
+    private NexusBlock nextBlock = null;
+    private String nextBlockName = null;
+    protected final ImportHelper helper;
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/fileio/NexusTreeReader.java b/src/main/java/es/uvigo/darwin/prottest/util/fileio/NexusTreeReader.java
new file mode 100755
index 0000000..f829740
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/fileio/NexusTreeReader.java
@@ -0,0 +1,71 @@
+/*
+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.prottest.util.fileio;
+
+import es.uvigo.darwin.prottest.consensus.*;
+import es.uvigo.darwin.prottest.tree.TreeUtils;
+import es.uvigo.darwin.prottest.tree.WeightedTree;
+import es.uvigo.darwin.prottest.util.exception.ImportException;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import pal.tree.Tree;
+
+/**
+ *
+ * @author Diego Darriba
+ */
+public class NexusTreeReader extends TreeReader {
+
+    private NexusImporter imp;
+    
+    public String getNexusId() {
+        return imp.getNexusId();
+    }
+    
+    public NexusTreeReader(File treeFile) throws ImportException {
+        
+        try {
+            FileReader fileReader = new FileReader(treeFile);
+            imp = new NexusImporter(fileReader);
+            List<Tree> importedTrees = imp.importTrees();
+            for (Tree tree : importedTrees) {
+                double weight = (Double) tree.getAttribute(tree.getRoot(), TreeUtils.TREE_WEIGHT_ATTRIBUTE);
+                trees.add(new WeightedTree(tree, weight));
+                cumWeight += weight;
+                if (idGroup == null) {
+                    idGroup = TreeUtils.getLeafIdGroup(tree);
+                    numTaxa = idGroup.getIdCount();
+                }
+            }
+            fileReader.close();
+        } catch (IOException ex) {
+            Logger.getLogger(NexusTreeReader.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+    
+    public static void main(String args[]) throws ImportException {
+        String filename = args[0];
+        File file = new File(filename);
+        NexusTreeReader ntr = new NexusTreeReader(file);
+    }
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/fileio/SimpleNewickTreeReader.java b/src/main/java/es/uvigo/darwin/prottest/util/fileio/SimpleNewickTreeReader.java
new file mode 100755
index 0000000..60847cf
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/fileio/SimpleNewickTreeReader.java
@@ -0,0 +1,135 @@
+/*
+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.prottest.util.fileio;
+
+import java.io.File;
+import java.util.List;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.PushbackReader;
+import java.io.PrintWriter;
+
+import pal.tree.Tree;
+
+import java.io.IOException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+
+import es.uvigo.darwin.prottest.util.exception.TreeFormatException;
+import es.uvigo.darwin.prottest.tree.WeightedTree;
+
+/**
+ *
+ * @author Diego Darriba
+ */
+public class SimpleNewickTreeReader extends TreeReader {
+
+    /** The first element. */
+    private static final int FIRST = 0;
+
+    public SimpleNewickTreeReader(File treeFile)
+            throws ProtTestInternalException, IOException {
+
+        FileReader fr = new FileReader(treeFile);
+        BufferedReader br = new BufferedReader(fr);
+
+        //PushbackReader in = new PushbackReader(fr);
+
+        try {
+            while (br.ready()) {
+                String line = br.readLine();
+                if (line == null || line.equals("")) {
+                    break;
+                }
+
+                line = line.replace('[', ';');
+                line = line.replace(']', ';');
+                String[] values = line.split(";");
+                String weightStr = values[1];
+                double weight;
+                weight = Double.parseDouble(weightStr);
+
+                File tempFile = File.createTempFile("consensus", "tmp");
+                tempFile.deleteOnExit();
+                FileWriter fw = new FileWriter(tempFile);
+                BufferedWriter bw = new BufferedWriter(fw);
+                bw.write(values[0]);
+                bw.append(';');
+                bw.close();
+                fw.close();
+
+                PushbackReader in = new PushbackReader(new FileReader(tempFile));
+
+                PrintWriter out = new PrintWriter(System.out);
+                Tree tree = AlignmentReader.readTree(out, in, false);
+                out.flush();
+
+                addTree(trees, new WeightedTree(tree, weight));
+            }
+        } catch (TreeFormatException tfe) {
+            throw new ProtTestInternalException("Bad file format. Cannot parse tree");
+        } catch (NumberFormatException nfe) {
+            throw new ProtTestInternalException("Bad file format. Expecting double value");
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    /**
+     * Adds a weighted tree to the set.
+     *
+     * @param wTree the weighted tree
+     *
+     * @return true, if successful
+     */
+    private boolean addTree(List<WeightedTree> trees, WeightedTree wTree) {
+        //check integrity
+        if (wTree.getTree() == null || wTree.getWeight() < 0.0) {
+            throw new ProtTestInternalException();
+        }
+        //check compatibility
+        if (trees.size() == 0) {
+            trees.add(wTree);
+            numTaxa = wTree.getTree().getIdCount();
+            idGroup = pal.tree.TreeUtils.getLeafIdGroup(wTree.getTree());
+        } else {
+            if (wTree.getTree().getIdCount() != numTaxa) {
+                return false;
+            }
+            Tree pTree = trees.get(FIRST).getTree();
+            for (int i = 0; i < numTaxa; i++) {
+                boolean found = false;
+                for (int j = 0; j < numTaxa; j++) {
+                    if (wTree.getTree().getIdentifier(i).equals(pTree.getIdentifier(j))) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found) {
+                    System.out.println("NOT COMPATIBLE TREES");
+                    return false;
+                }
+            }
+            trees.add(wTree);
+        }
+        cumWeight += wTree.getWeight();
+        return true;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/fileio/TreeReader.java b/src/main/java/es/uvigo/darwin/prottest/util/fileio/TreeReader.java
new file mode 100755
index 0000000..cec71fb
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/fileio/TreeReader.java
@@ -0,0 +1,43 @@
+/*
+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.prottest.util.fileio;
+
+import es.uvigo.darwin.prottest.tree.WeightedTree;
+import java.util.ArrayList;
+import java.util.List;
+import pal.misc.IdGroup;
+
+/**
+ *
+ * This class allows reading a set of trees from a file
+ *
+ * @author Diego Darriba
+ */
+public abstract class TreeReader {
+
+    protected int numTaxa;
+    protected IdGroup idGroup;
+    protected double cumWeight;
+    protected List<WeightedTree> trees = new ArrayList<WeightedTree>();
+
+    public int getNumTaxa(){ return numTaxa; }
+    public IdGroup getIdGroup() { return idGroup; }
+    public double getCumWeight() { return cumWeight; }
+    public List<WeightedTree> getWeightedTreeList() { return trees; }
+    
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/logging/ProtTestLogFormatter.java b/src/main/java/es/uvigo/darwin/prottest/util/logging/ProtTestLogFormatter.java
new file mode 100755
index 0000000..05a6c71
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/logging/ProtTestLogFormatter.java
@@ -0,0 +1,47 @@
+/*
+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.prottest.util.logging;
+
+import java.util.logging.Formatter;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+/**
+ *
+ * @author Diego Darriba
+ */
+public class ProtTestLogFormatter extends Formatter {
+
+    @Override
+    public String format(LogRecord lr) {
+        
+        StringBuffer text = new StringBuffer();
+        
+        if (lr.getLevel().intValue() < Level.FINE.intValue()) {
+            text.append(lr.getLevel().getName() + " : ");
+        }
+        if (lr.getLevel().intValue() == Level.WARNING.intValue()) {
+            text.append("WARNING: ");
+        }
+        text.append(lr.getMessage());
+        
+        return text.toString();
+        
+    }
+
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/logging/ProtTestLogger.java b/src/main/java/es/uvigo/darwin/prottest/util/logging/ProtTestLogger.java
new file mode 100755
index 0000000..1d12961
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/logging/ProtTestLogger.java
@@ -0,0 +1,361 @@
+/*
+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.prottest.util.logging;
+
+import es.uvigo.darwin.prottest.util.WriterOutputStream;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.StreamHandler;
+
+public class ProtTestLogger {
+
+	public static final String DEFAULT_LOGGER_NAME = "default";
+	public static final Level DEFAULT_LEVEL = Level.INFO;
+
+	private static HashMap<String, ProtTestLogger> loggers;
+
+	static {
+
+		loggers = new HashMap<String, ProtTestLogger>();
+		ProtTestLogger defaultLogger = new ProtTestLogger(DEFAULT_LOGGER_NAME);
+		loggers.put(DEFAULT_LOGGER_NAME, defaultLogger);
+
+	}
+
+	private String loggerName;
+	private Level loggerLevel;
+	private List<Handler> handlers;
+	private Handler stdHandler;
+	private Handler lowLevelHandler = null;
+
+	public static ProtTestLogger getLogger(String loggerName, boolean force) {
+		if (!loggers.containsKey(loggerName)) {
+			if (force)
+				loggers.put(loggerName, new ProtTestLogger(loggerName));
+			else
+				return null;
+		}
+		return loggers.get(loggerName);
+	}
+
+	public static boolean exists(Class classLogger) {
+		return getLogger(classLogger.getName(), false) != null;
+	}
+
+	public ProtTestLogger(String loggerName) {
+		this.loggerName = loggerName;
+		if (loggers.containsKey(loggerName))
+			throw new ProtTestInternalException("ProtTestLogger with name "
+					+ loggerName + " already exists. "
+					+ " Use getLogger() instead");
+		this.loggerLevel = Level.ALL;
+
+		// Add standard output handler
+		this.handlers = new ArrayList<Handler>();
+		stdHandler = new StreamHandler(System.out, new ProtTestLogFormatter());
+		stdHandler.setLevel(Level.OFF);
+		handlers.add(stdHandler);
+	}
+
+	public static ProtTestLogger getDefaultLogger() {
+		return getLogger(DEFAULT_LOGGER_NAME, true);
+	}
+
+	/**
+	 * Check if a message of the given level would actually be logged by this
+	 * logger. This check is based on the Loggers effective level, which may be
+	 * inherited from its parent.
+	 * 
+	 * @param level
+	 *            a message logging level
+	 * @return true if the given message level is currently being logged.
+	 */
+	public boolean isLoggable(Level level) {
+		if (level.intValue() < loggerLevel.intValue()
+				|| loggerLevel.intValue() == Level.OFF.intValue()) {
+			return false;
+		}
+		return true;
+	}
+
+	public void addHandler(Handler handler) {
+		if (handler == null) {
+			throw new NullPointerException();
+		}
+		this.handlers.add(handler);
+	}
+
+	public void addHandler(Handler[] newHandlers) {
+		for (Handler handler : newHandlers) {
+			if (handler == null) {
+				throw new NullPointerException();
+			}
+			if (!handlers.contains(handler))
+				this.handlers.add(handler);
+		}
+	}
+
+	public Handler addHandler(OutputStream out) {
+		return addHandler(out, DEFAULT_LEVEL);
+	}
+
+	public Handler addHandler(OutputStream out, Level level) {
+		if (out == null) {
+			throw new NullPointerException();
+		}
+		Handler handler = new StreamHandler(out, new ProtTestLogFormatter());
+		handler.setLevel(level);
+		this.handlers.add(handler);
+		return handler;
+	}
+
+	public Handler addHandler(Writer out) {
+		return addHandler(out, DEFAULT_LEVEL);
+	}
+
+	public Handler addHandler(Writer out, Level level) {
+		if (out == null) {
+			throw new NullPointerException();
+		}
+		Handler handler = new StreamHandler(new WriterOutputStream(out),
+				new ProtTestLogFormatter());
+		handler.setLevel(level);
+		this.handlers.add(handler);
+		return handler;
+	}
+
+	public Handler addLowLevelHandler(Writer out) {
+		if (out == null) {
+			throw new NullPointerException();
+		}
+		Handler handler = new StreamHandler(new WriterOutputStream(out),
+				new ProtTestLogFormatter());
+		handler.setLevel(Level.ALL);
+		lowLevelHandler = handler;
+		return handler;
+	}
+
+	public Handler getLowLevelHandler() {
+		return lowLevelHandler;
+	}
+
+	public boolean removeHandler(Handler handler) {
+		return this.handlers.remove(handler);
+	}
+
+	public Handler[] getHandlers() {
+		return handlers.toArray(new Handler[0]);
+	}
+
+	public void setStdHandlerLevel(Level newLevel) {
+		if (newLevel == null) {
+			throw new NullPointerException();
+		}
+		stdHandler.setLevel(newLevel);
+	}
+
+	public Level getStdHandlerLevel() {
+		return stdHandler.getLevel();
+	}
+
+	public void setLevel(Level newLevel) {
+		if (newLevel == null) {
+			throw new NullPointerException();
+		}
+		loggerLevel = newLevel;
+	}
+
+	public Level getLevel() {
+		return loggerLevel;
+	}
+
+	public void info(String text) {
+		log(Level.INFO, text);
+	}
+
+	public void warning(String text) {
+		log(Level.WARNING, text);
+	}
+
+	public void config(String text) {
+		log(Level.CONFIG, text);
+	}
+
+	public void severe(String text) {
+		log(Level.SEVERE, text);
+	}
+
+	public void fine(String text) {
+		log(Level.FINE, text);
+	}
+
+	public void finer(String text) {
+		log(Level.FINER, text);
+	}
+
+	public void finest(String text) {
+		log(Level.FINEST, text);
+	}
+
+	public void infoln(String text) {
+		log(Level.INFO, text + "\n");
+		flush();
+	}
+
+	public void warningln(String text) {
+		log(Level.WARNING, text + "\n");
+		flush();
+	}
+
+	public void configln(String text) {
+		log(Level.CONFIG, text + "\n");
+		flush();
+	}
+
+	public void severeln(String text) {
+		log(Level.SEVERE, text + "\n");
+		flush();
+	}
+
+	public void fineln(String text) {
+		log(Level.FINE, text + "\n");
+		flush();
+	}
+
+	public void finerln(String text) {
+		log(Level.FINER, text + "\n");
+		flush();
+	}
+
+	public void finestln(String text) {
+		log(Level.FINEST, text + "\n");
+		flush();
+	}
+
+	public static void info(String text, Class loggingClass) {
+		log(Level.INFO, text, loggingClass);
+	}
+
+	public static void warning(String text, Class loggingClass) {
+		log(Level.WARNING, text, loggingClass);
+	}
+
+	public static void config(String text, Class loggingClass) {
+		log(Level.CONFIG, text, loggingClass);
+	}
+
+	public static void severe(String text, Class loggingClass) {
+		log(Level.SEVERE, text, loggingClass);
+	}
+
+	public static void fine(String text, Class loggingClass) {
+		log(Level.FINE, text, loggingClass);
+	}
+
+	public static void finer(String text, Class loggingClass) {
+		log(Level.FINER, text, loggingClass);
+	}
+
+	public static void finest(String text, Class loggingClass) {
+		log(Level.FINEST, text, loggingClass);
+	}
+
+	public static void infoln(String text, Class loggingClass) {
+		log(Level.INFO, text + "\n", loggingClass);
+		flush(loggingClass);
+	}
+
+	public static void warningln(String text, Class loggingClass) {
+		log(Level.WARNING, text + "\n", loggingClass);
+		flush(loggingClass);
+	}
+
+	public static void configln(String text, Class loggingClass) {
+		log(Level.CONFIG, text + "\n", loggingClass);
+		flush(loggingClass);
+	}
+
+	public static void severeln(String text, Class loggingClass) {
+		log(Level.SEVERE, text + "\n", loggingClass);
+		flush(loggingClass);
+	}
+
+	public static void fineln(String text, Class loggingClass) {
+		log(Level.FINE, text + "\n", loggingClass);
+		flush(loggingClass);
+	}
+
+	public static void finerln(String text, Class loggingClass) {
+		log(Level.FINER, text + "\n", loggingClass);
+		flush(loggingClass);
+	}
+
+	public static void finestln(String text, Class loggingClass) {
+		log(Level.FINEST, text + "\n", loggingClass);
+		flush(loggingClass);
+	}
+
+	public static void log(Level level, String text, Class loggingClass) {
+		// default logging + class logging
+		getDefaultLogger().log(level, text);
+		if (exists(loggingClass))
+			getLogger(loggingClass.getName(), false).log(level, text);
+	}
+
+	public void log(Level level, String text) {
+		log(new LogRecord(level, text));
+	}
+
+	public void log(LogRecord lr) {
+
+		if (lr.getLevel().intValue() > loggerLevel.intValue()
+				&& loggerLevel.intValue() != Level.OFF.intValue()) {
+
+			for (Handler handler : handlers)
+				handler.publish(lr);
+
+		}
+
+	}
+
+	public static void lowLevelLog(String text) {
+		if (getDefaultLogger().lowLevelHandler != null) {
+			LogRecord lr = new LogRecord(Level.INFO, text + "\n");
+			getDefaultLogger().lowLevelHandler.publish(lr);
+			getDefaultLogger().lowLevelHandler.flush();
+		}
+	}
+
+	public void flush() {
+		for (Handler handler : handlers)
+			handler.flush();
+	}
+
+	public static void flush(Class loggingClass) {
+		getDefaultLogger().flush();
+		if (exists(loggingClass))
+			getLogger(loggingClass.getName(), false).flush();
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/package.html b/src/main/java/es/uvigo/darwin/prottest/util/package.html
new file mode 100755
index 0000000..4844b25
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/package.html
@@ -0,0 +1,21 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+ @(#)package.html	3.0 2010/07/01
+
+Diego Darriba López
+Bioinformatics and Molecular Evolution Group
+Universidade de Vigo, Spain
+http://darwin.uvigo.es/
+-->
+
+</head>
+<body bgcolor="white">
+
+Contains common utilities for ProtTest-HPC.
+
+ at since 3.0
+
+</body>
+</html>
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/printer/ProtTestFormattedOutput.java b/src/main/java/es/uvigo/darwin/prottest/util/printer/ProtTestFormattedOutput.java
new file mode 100755
index 0000000..7efd92f
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/printer/ProtTestFormattedOutput.java
@@ -0,0 +1,182 @@
+/*
+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.prottest.util.printer;
+
+import java.io.PrintWriter;
+
+import pal.io.FormattedOutput;
+
+// TODO: Auto-generated Javadoc
+/**
+ * The Class ProtTestFormattedOutput.
+ */
+public class ProtTestFormattedOutput {
+
+    /** The Constant NAN. */
+    private static final String NAN = "NaN";
+    /** The formatter. */
+    private static FormattedOutput formatter;
+
+    static {
+        formatter = FormattedOutput.getInstance();
+    }
+
+    /**
+     * Space.
+     * 
+     * @param size the size
+     * @param c the c
+     * 
+     * @return the string
+     */
+    public static String space(int size, char c) {
+        return FormattedOutput.space(size, c);
+    }
+
+    /**
+     * Gets the decimal string.
+     * 
+     * @param number the number
+     * @param width the width
+     * 
+     * @return the decimal string
+     */
+    public static String getDecimalString(double number, int width) {
+        String strValue;
+        if (Double.isNaN(number))//.isInfinite(number))
+        {
+            strValue = NAN;
+        } else {
+            strValue = formatter.getDecimalString(number, width);
+        }
+
+        return strValue;
+    }
+
+    /**
+     * Display decimal.
+     * 
+     * @param out the out
+     * @param number the number
+     * @param width the width
+     * 
+     * @return the int
+     */
+    public static int displayDecimal(PrintWriter out, double number, int width) {
+        int result = 0;
+        if (Double.isNaN(number)) {
+            formatter.displayLabel(out, NAN, width);
+            result = NAN.length();
+        } else {
+            result = formatter.displayDecimal(out, number, width);
+        }
+
+        return result;
+    }
+
+    /**
+     * turns an integer into a String, aligned to a reference number,
+     * (introducing space at the left side)
+     *
+     * @param num number to be printed
+     * @param maxNum reference number
+     */
+    public static String getIntegerString(int num, int maxNum) {
+        StringBuffer sb = new StringBuffer();
+        int lenNum = Integer.toString(num).length();
+        int lenMaxNum = Integer.toString(maxNum).length();
+
+        if (lenNum < lenMaxNum) {
+            for (int i = 0; i < num; i++) {
+                sb.append(' ');
+            }
+        }
+        sb.append(num);
+
+        return sb.toString();
+    }
+
+    /**
+     * print integer, aligned to a reference number,
+     * (introducing space at the left side)
+     *
+     * @param out output stream
+     * @param num number to be printed
+     * @param maxNum reference number
+     */
+    public static void displayInteger(PrintWriter out, int num, int maxNum) {
+        int lenNum = Integer.toString(num).length();
+        int lenMaxNum = Integer.toString(maxNum).length();
+
+        if (lenNum < lenMaxNum) {
+            multiplePrint(out, ' ', lenMaxNum - lenNum);
+        }
+        out.print(num);
+    }
+
+    /**
+     * print whitespace of length of a string displaying a given integer
+     *
+     * @param out the writer
+     * @param maxNum the number of white spaces
+     */
+    public static void displayIntegerWhite(PrintWriter out, int maxNum) {
+        int lenMaxNum = Integer.toString(maxNum).length();
+
+        multiplePrint(out, ' ', lenMaxNum);
+    }
+
+    /**
+     * print label with a prespecified length
+     * (label will be shortened or spaces will introduced, if necessary)
+     *
+     * @param out output stream
+     * @param label label to be printed
+     * @param width desired length
+     */
+    public static void displayLabel(PrintWriter out, String label, int width) {
+        int len = label.length();
+
+        if (len == width) {
+            // Print as is
+            out.print(label);
+        } else if (len < width) {
+            // fill rest with spaces
+            out.print(label);
+            multiplePrint(out, ' ', width - len);
+        } else {
+            // Print first width characters
+            for (int i = 0; i < width; i++) {
+                out.print(label.charAt(i));
+            }
+        }
+    }
+
+    /**
+     * repeatedly print a character
+     *
+     * @param out output stream
+     * @param c   character
+     * @param num number of repeats
+     */
+    public static void multiplePrint(PrintWriter out, char c, int num) {
+        for (int i = 0; i < num; i++) {
+            out.print(c);
+        }
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/prottest/util/printer/ProtTestPrinter.java b/src/main/java/es/uvigo/darwin/prottest/util/printer/ProtTestPrinter.java
new file mode 100755
index 0000000..1a7cb51
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/prottest/util/printer/ProtTestPrinter.java
@@ -0,0 +1,200 @@
+/*
+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.prottest.util.printer;
+
+import java.io.PrintWriter;
+import java.util.Date;
+
+import es.uvigo.darwin.prottest.ProtTest;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import java.io.File;
+
+/**
+ * The Class ProtTestPrinter provides a common PrintWriter module to
+ * the whole application. It encapsulates both output and error
+ * PrintWriter.
+ */
+public class ProtTestPrinter {
+
+    private static final String H_RULE =
+            "********************************************************";
+    /** The output print writer. */
+    private PrintWriter out;
+    /** The error print writer. */
+    private PrintWriter err;
+
+    /**
+     * Instantiates a new ProtTestPrinter.
+     * 
+     * @param out the output writer
+     * @param err the error writer
+     */
+    public ProtTestPrinter(PrintWriter out, PrintWriter err) {
+        this.out = out;
+        this.err = err;
+    }
+
+    /**
+     * Prints out the header section of the application.
+     */
+    public static void printHeader() {
+        println("");
+        println("");
+        println("ProtTest " + ProtTest.versionNumber
+                + ProtTestFormattedOutput.space(27 - ProtTest.versionNumber.length(), ' ') +
+                                                    "Fast selection of the best-fit models of protein evolution");
+        println("(c) 2009-2010   Diego Darriba (1,2), Guillermo Taboada (2), Ramón Doallo (2), David Posada (1)");
+        println("(1)                               Facultad de Biologia, Universidad de Vigo, 36200 Vigo, Spain");
+        println("(2)                    Facultade de Informática, Universidade da Coruña, 15071 A Coruña, Spain");
+        println("Contact:                                                     ddarriba at udc.es, dposada at uvigo.es");
+        println("----------------------------------------------------------------------------------------------");
+        println("");
+        println((new Date()).toString());
+        println("OS = " + System.getProperty("os.name") +
+                " (" + System.getProperty("os.version") + ")");
+        println("");
+        println("Citation: Darriba D, Taboada GL, Doallo R, Posada D. ProtTest 3: fast selection of best-fit ");
+        println("          models of protein evolution. Bioinformatics, 27:1164-1165, 2011");
+        println("");
+    }
+
+    /**
+     * Prints out the header of the pre-analysis section.
+     */
+    public static void printPreAnalysisHeader() {
+        println("");
+        println(H_RULE);
+        println(center("ALIGNMENT ANALYSIS"));
+        println(H_RULE);
+        println("");
+    }
+
+    /**
+     * Prints out the header of the selection section
+     */
+    public static void printSelectionHeader(String criterionName) {
+        println("");
+        println("");
+        println(H_RULE);
+        println(center(criterionName));
+        println(H_RULE);
+    }
+
+    /**
+     * Prints out the header of the tree display
+     */
+    public static void printTreeHeader(String modelName) {
+        println("");
+        println(H_RULE);
+        println(center(modelName));
+        println(H_RULE);
+        println("");
+    }
+
+    public static void printExecutionHeader(ApplicationOptions options) {
+        println("");
+        println(H_RULE);
+        println(center("MODEL OPTIMIZATION"));
+        println(H_RULE);
+        options.reportModelOptimization();
+        println("");
+    }
+
+    /**
+     * Prints file data
+     */
+    public static void printFileData(File f) {
+        println("");
+        println("File: " + f.getAbsolutePath());
+        println("Size: " + f.length());
+        println("");
+    }
+    public static void println(String text) {
+        ProtTestLogger.infoln(text, ProtTestPrinter.class);
+    }
+
+    /**
+     * Prints out the footer section of the application.
+     */
+    public static void printFooter() {
+        println("");
+        println("");
+        println("ProtTest-HPC - " + ProtTest.versionNumber);
+    }
+    private static String center(String text) {
+        return ProtTestFormattedOutput.space((H_RULE.length() - text.length())/2, ' ') + text;
+    }
+
+    /**
+     * Gets the output writer.
+     * 
+     * @return the output writer
+     */
+    public PrintWriter getOutputWriter() {
+        return out;
+    }
+
+    /**
+     * Sets the output writer.
+     * 
+     * @param out the new output writer
+     */
+    public void setOutputWriter(PrintWriter out) {
+        this.out = out;
+    }
+
+    /**
+     * Gets the error writer.
+     * 
+     * @return the error writer
+     */
+    public PrintWriter getErrorWriter() {
+        return err;
+    }
+
+    /**
+     * Sets the error writer.
+     * 
+     * @param err the new error writer
+     */
+    public void setErrorWriter(PrintWriter err) {
+        this.err = err;
+    }
+
+    /**
+     * Flushes output writer.
+     */
+    public void flush() {
+        out.flush();
+    }
+
+    /**
+     * Flushes error writer.
+     */
+    public void flushError() {
+        err.flush();
+    }
+
+    /**
+     * Closes error writer.
+     */
+    public void closeError() {
+        err.close();
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/CreditsBox.java b/src/main/java/es/uvigo/darwin/xprottest/CreditsBox.java
new file mode 100755
index 0000000..47de742
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/CreditsBox.java
@@ -0,0 +1,80 @@
+/*
+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.xprottest;
+
+import javax.swing.GroupLayout;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.WindowConstants;
+
+/**
+ *
+ * @author Diego Darriba
+ */
+public class CreditsBox extends JDialog {
+
+    /** Creates new form Credits */
+    public CreditsBox(java.awt.Frame parent) {
+        super(parent);
+        initComponents();
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        namesLabel = new JLabel();
+
+        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle("Credits"); // NOI18N
+        setAlwaysOnTop(true);
+
+        namesLabel.setText("Diego Darriba, Guillermo L.Taboada, Ramon Doallo, David Posada"); // NOI18N
+        namesLabel.setName("namesLabel"); // NOI18N
+
+        GroupLayout layout = new GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(namesLabel)
+                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(namesLabel)
+                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private JLabel namesLabel;
+    // End of variables declaration//GEN-END:variables
+
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/PreferencesView.java b/src/main/java/es/uvigo/darwin/xprottest/PreferencesView.java
new file mode 100755
index 0000000..a1749dc
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/PreferencesView.java
@@ -0,0 +1,197 @@
+/*
+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.xprottest;
+
+import org.jdesktop.application.Action;
+/**
+ *
+ * @author  Diego Darriba
+ */
+public class PreferencesView extends javax.swing.JFrame {
+    
+    XProtTestView mainFrame;
+    
+    /** Creates new form PreferencesView */
+    public PreferencesView(XProtTestView mainFrame) {
+        this.mainFrame = mainFrame;
+        initComponents();
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        txtContinueDesc = new javax.swing.JTextArea();
+        lblErrorBehavior = new javax.swing.JLabel();
+        cmbErrorBehavior = new javax.swing.JComboBox();
+        btnAccept = new javax.swing.JButton();
+        btnCancel = new javax.swing.JButton();
+        lblContinue = new javax.swing.JLabel();
+        txtStopDesc = new javax.swing.JTextArea();
+        lblStop = new javax.swing.JLabel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class).getContext().getResourceMap(PreferencesView.class);
+        setTitle(resourceMap.getString("Form.title")); // NOI18N
+        setAlwaysOnTop(true);
+        setBackground(resourceMap.getColor("Form.background")); // NOI18N
+        setName("Form"); // NOI18N
+        setResizable(false);
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosed(java.awt.event.WindowEvent evt) {
+                onClose(evt);
+            }
+        });
+
+        txtContinueDesc.setBackground(resourceMap.getColor("Form.background")); // NOI18N
+        txtContinueDesc.setColumns(20);
+        txtContinueDesc.setEditable(false);
+        txtContinueDesc.setForeground(resourceMap.getColor("txtContinueDesc.foreground")); // NOI18N
+        txtContinueDesc.setRows(2);
+        txtContinueDesc.setText(resourceMap.getString("error-continue-desc")); // NOI18N
+        txtContinueDesc.setBorder(null);
+        txtContinueDesc.setName("txtContinueDesc"); // NOI18N
+        txtContinueDesc.setOpaque(false);
+
+        lblErrorBehavior.setText(resourceMap.getString("lblErrorBehavior.text")); // NOI18N
+        lblErrorBehavior.setName("lblErrorBehavior"); // NOI18N
+
+        cmbErrorBehavior.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Continue", "Stop" }));
+        cmbErrorBehavior.setSelectedIndex(mainFrame.getErrorBehavior());
+        cmbErrorBehavior.setName("cmbErrorBehavior"); // NOI18N
+
+        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class).getContext().getActionMap(PreferencesView.class, this);
+        btnAccept.setAction(actionMap.get("Accept")); // NOI18N
+        btnAccept.setText(resourceMap.getString("button-accept")); // NOI18N
+        btnAccept.setName("btnAccept"); // NOI18N
+
+        btnCancel.setAction(actionMap.get("Cancel")); // NOI18N
+        btnCancel.setText(resourceMap.getString("button-cancel")); // NOI18N
+        btnCancel.setName("btnCancel"); // NOI18N
+
+        lblContinue.setForeground(resourceMap.getColor("lblContinue.foreground")); // NOI18N
+        lblContinue.setText(resourceMap.getString("lblContinue.text")); // NOI18N
+        lblContinue.setName("lblContinue"); // NOI18N
+
+        txtStopDesc.setBackground(resourceMap.getColor("txtStopDesc.background")); // NOI18N
+        txtStopDesc.setColumns(20);
+        txtStopDesc.setEditable(false);
+        txtStopDesc.setForeground(resourceMap.getColor("txtStopDesc.foreground")); // NOI18N
+        txtStopDesc.setRows(2);
+        txtStopDesc.setText(resourceMap.getString("error-stop-desc")); // NOI18N
+        txtStopDesc.setBorder(null);
+        txtStopDesc.setName("txtStopDesc"); // NOI18N
+        txtStopDesc.setOpaque(false);
+
+        lblStop.setForeground(resourceMap.getColor("lblStop.foreground")); // NOI18N
+        lblStop.setText(resourceMap.getString("lblStop.text")); // NOI18N
+        lblStop.setName("lblStop"); // NOI18N
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(layout.createSequentialGroup()
+                        .addGap(24, 24, 24)
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(lblContinue)
+                            .addComponent(lblStop, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE))
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(txtContinueDesc, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
+                            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                                .addGroup(layout.createSequentialGroup()
+                                    .addComponent(btnAccept)
+                                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                                    .addComponent(btnCancel))
+                                .addComponent(txtStopDesc, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE))))
+                    .addGroup(layout.createSequentialGroup()
+                        .addContainerGap()
+                        .addComponent(lblErrorBehavior, javax.swing.GroupLayout.DEFAULT_SIZE, 303, Short.MAX_VALUE))
+                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                        .addContainerGap(24, Short.MAX_VALUE)
+                        .addComponent(cmbErrorBehavior, 0, 291, Short.MAX_VALUE)))
+                .addContainerGap())
+        );
+
+        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {lblContinue, lblStop});
+
+        layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {txtContinueDesc, txtStopDesc});
+
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(lblErrorBehavior)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(cmbErrorBehavior, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(lblContinue)
+                    .addComponent(txtContinueDesc, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(txtStopDesc, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(lblStop))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(btnCancel, javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addComponent(btnAccept, javax.swing.GroupLayout.Alignment.TRAILING))
+                .addContainerGap())
+        );
+
+        layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {lblContinue, lblStop});
+
+        layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {txtContinueDesc, txtStopDesc});
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void onClose(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_onClose
+        mainFrame.unloadPreferencesView();
+    }//GEN-LAST:event_onClose
+
+    @Action
+    public void Accept() {
+        mainFrame.setErrorBehavior(cmbErrorBehavior.getSelectedIndex());
+        this.dispose();
+    }
+
+    @Action
+    public void Cancel() {
+        this.dispose();
+    }
+    
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton btnAccept;
+    private javax.swing.JButton btnCancel;
+    private javax.swing.JComboBox cmbErrorBehavior;
+    private javax.swing.JLabel lblContinue;
+    private javax.swing.JLabel lblErrorBehavior;
+    private javax.swing.JLabel lblStop;
+    private javax.swing.JTextArea txtContinueDesc;
+    private javax.swing.JTextArea txtStopDesc;
+    // End of variables declaration//GEN-END:variables
+    
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/XProtTestAboutBox.java b/src/main/java/es/uvigo/darwin/xprottest/XProtTestAboutBox.java
new file mode 100755
index 0000000..eaff622
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/XProtTestAboutBox.java
@@ -0,0 +1,229 @@
+/*
+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.xprottest;
+
+import javax.swing.ActionMap;
+import javax.swing.GroupLayout;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.LayoutStyle;
+import javax.swing.WindowConstants;
+
+import org.jdesktop.application.Action;
+
+public class XProtTestAboutBox extends JDialog {
+
+	public XProtTestAboutBox(java.awt.Frame parent) {
+		super(parent);
+		initComponents();
+		getRootPane().setDefaultButton(closeButton);
+	}
+
+	@Action
+	public void closeAboutBox() {
+		setVisible(false);
+	}
+
+	/**
+	 * This method is called from within the constructor to initialize the form.
+	 * WARNING: Do NOT modify this code. The content of this method is always
+	 * regenerated by the Form Editor.
+	 */
+	// <editor-fold defaultstate="collapsed"
+	// desc="Generated Code">//GEN-BEGIN:initComponents
+	private void initComponents() {
+
+		closeButton = new JButton();
+		JLabel appTitleLabel = new JLabel();
+		JLabel versionLabel = new JLabel();
+		JLabel appVersionLabel = new JLabel();
+		JLabel homepageLabel = new JLabel();
+		JLabel appHomepageLabel = new JLabel();
+		JLabel citationLabel = new JLabel();
+		JLabel appCitation1Label = new JLabel();
+		JLabel appCitation2Label = new JLabel();
+		JLabel appDescLabel = new JLabel();
+		JLabel imageLabel = new JLabel();
+
+		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+		org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application
+				.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class)
+				.getContext().getResourceMap(XProtTestAboutBox.class);
+		setTitle(resourceMap.getString("title")); // NOI18N
+		setModal(true);
+		setName("aboutBox"); // NOI18N
+		setResizable(false);
+
+		ActionMap actionMap = org.jdesktop.application.Application
+				.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class)
+				.getContext().getActionMap(XProtTestAboutBox.class, this);
+		closeButton.setAction(actionMap.get("closeAboutBox")); // NOI18N
+		closeButton.setName("closeButton"); // NOI18N
+
+		appTitleLabel.setFont(appTitleLabel.getFont().deriveFont(
+				appTitleLabel.getFont().getStyle() | java.awt.Font.BOLD,
+				appTitleLabel.getFont().getSize() + 4));
+		appTitleLabel.setText(resourceMap.getString("Application.title")); // NOI18N
+		appTitleLabel.setName("appTitleLabel"); // NOI18N
+
+		versionLabel.setFont(versionLabel.getFont().deriveFont(
+				versionLabel.getFont().getStyle() | java.awt.Font.BOLD));
+		versionLabel.setText(resourceMap.getString("versionLabel.text")); // NOI18N
+		versionLabel.setName("versionLabel"); // NOI18N
+
+		appVersionLabel.setText(resourceMap.getString("Application.version")); // NOI18N
+		appVersionLabel.setName("appVersionLabel"); // NOI18N
+
+		homepageLabel.setFont(homepageLabel.getFont().deriveFont(
+				homepageLabel.getFont().getStyle() | java.awt.Font.BOLD));
+		homepageLabel.setText(resourceMap.getString("homepageLabel.text")); // NOI18N
+		homepageLabel.setName("homepageLabel"); // NOI18N
+
+		appHomepageLabel.setText(resourceMap.getString("Application.homepage")); // NOI18N
+		appHomepageLabel.setName("appHomepageLabel"); // NOI18N
+
+		citationLabel.setFont(citationLabel.getFont().deriveFont(
+				citationLabel.getFont().getStyle() | java.awt.Font.BOLD));
+		citationLabel.setText(resourceMap.getString("citationLabel.text")); // NOI18N
+		citationLabel.setName("citationLabel"); // NOI18N
+
+		appCitation1Label.setText(resourceMap.getString("Application.citation1")); // NOI18N
+		appCitation1Label.setName("appCitationLabel"); // NOI18N
+		appCitation2Label.setText(resourceMap.getString("Application.citation2")); // NOI18N
+		appCitation2Label.setName("appCitationLabel"); // NOI18N
+
+		appDescLabel.setText(resourceMap.getString("appDescLabel.text")); // NOI18N
+		appDescLabel.setName("appDescLabel"); // NOI18N
+
+		imageLabel.setIcon(resourceMap.getIcon("imageLabel.icon")); // NOI18N
+		imageLabel.setName("imageLabel"); // NOI18N
+
+		GroupLayout layout = new GroupLayout(getContentPane());
+		getContentPane().setLayout(layout);
+		layout.setHorizontalGroup(layout
+				.createParallelGroup(GroupLayout.Alignment.LEADING)
+				.addGroup(
+						layout.createSequentialGroup()
+								.addComponent(imageLabel)
+								.addGap(18, 18, 18)
+								.addGroup(
+										layout.createParallelGroup(
+												GroupLayout.Alignment.LEADING)
+												.addGroup(
+														layout.createSequentialGroup()
+																.addComponent(
+																		versionLabel)
+																.addPreferredGap(
+																		LayoutStyle.ComponentPlacement.RELATED)
+																.addComponent(
+																		appVersionLabel)
+																.addGap(238,
+																		238,
+																		238))
+												.addComponent(appTitleLabel)
+												.addComponent(
+														appDescLabel,
+														GroupLayout.DEFAULT_SIZE,
+														367, Short.MAX_VALUE)
+												.addComponent(
+														closeButton,
+														GroupLayout.Alignment.TRAILING)
+												.addGroup(
+														layout.createSequentialGroup()
+																.addComponent(
+																		homepageLabel)
+																.addPreferredGap(
+																		LayoutStyle.ComponentPlacement.RELATED)
+																.addComponent(
+																		appHomepageLabel,
+																		GroupLayout.DEFAULT_SIZE,
+																		289,
+																		Short.MAX_VALUE))
+												.addGroup(
+														layout.createSequentialGroup()
+																.addComponent(
+																		citationLabel)
+																.addPreferredGap(
+																		LayoutStyle.ComponentPlacement.RELATED)
+																.addComponent(
+																		appCitation1Label,
+																		GroupLayout.DEFAULT_SIZE,
+																		289,
+																		Short.MAX_VALUE))
+																		.addGroup(
+														layout.createSequentialGroup()
+																.addComponent(
+																		citationLabel)
+																.addPreferredGap(
+																		LayoutStyle.ComponentPlacement.RELATED)
+																.addComponent(
+																		appCitation2Label,
+																		GroupLayout.DEFAULT_SIZE,
+																		289,
+																		Short.MAX_VALUE)))
+								.addContainerGap()));
+		layout.setVerticalGroup(layout
+				.createParallelGroup(GroupLayout.Alignment.LEADING)
+				.addComponent(imageLabel, GroupLayout.PREFERRED_SIZE, 190,
+						Short.MAX_VALUE)
+				.addGroup(
+						layout.createSequentialGroup()
+								.addContainerGap()
+								.addComponent(appTitleLabel)
+								.addPreferredGap(
+										LayoutStyle.ComponentPlacement.RELATED)
+								.addComponent(appDescLabel)
+								.addPreferredGap(
+										LayoutStyle.ComponentPlacement.RELATED)
+								.addGroup(
+										layout.createParallelGroup(
+												GroupLayout.Alignment.BASELINE)
+												.addComponent(versionLabel)
+												.addComponent(appVersionLabel))
+								.addPreferredGap(
+										LayoutStyle.ComponentPlacement.RELATED)
+								.addGroup(
+										layout.createParallelGroup(
+												GroupLayout.Alignment.BASELINE)
+												.addComponent(homepageLabel)
+												.addComponent(appHomepageLabel))
+								.addPreferredGap(
+										LayoutStyle.ComponentPlacement.RELATED)
+								.addGroup(
+										layout.createParallelGroup(
+												GroupLayout.Alignment.BASELINE)
+												.addComponent(citationLabel)
+												.addComponent(appCitation1Label))
+												.addGroup(
+										layout.createParallelGroup(
+												GroupLayout.Alignment.BASELINE)
+												.addComponent(appCitation2Label))
+								.addPreferredGap(
+										LayoutStyle.ComponentPlacement.RELATED,
+										63, Short.MAX_VALUE)
+								.addComponent(closeButton).addContainerGap()));
+
+		pack();
+	}// </editor-fold>//GEN-END:initComponents
+
+	// Variables declaration - do not modify//GEN-BEGIN:variables
+	private JButton closeButton;
+	// End of variables declaration//GEN-END:variables
+
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/XProtTestApp.java b/src/main/java/es/uvigo/darwin/xprottest/XProtTestApp.java
new file mode 100755
index 0000000..7a7b53b
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/XProtTestApp.java
@@ -0,0 +1,97 @@
+/*
+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.xprottest;
+
+import org.jdesktop.application.Application;
+import org.jdesktop.application.SingleFrameApplication;
+import es.uvigo.darwin.prottest.facade.ProtTestFacade;
+import es.uvigo.darwin.prottest.facade.ProtTestFacadeThread;
+import es.uvigo.darwin.prottest.util.Utilities;
+import java.awt.Font;
+import java.io.File;
+import javax.swing.JFileChooser;
+
+/**
+ * The main class of the application.
+ */
+public class XProtTestApp extends SingleFrameApplication {
+
+    public static final int ERROR_BEHAVIOR_CONTINUE = 0;
+    public static final int ERROR_BEHAVIOR_STOP = 1;
+    public static final Font FONT_CONSOLE;
+    public static final Font FONT_LABEL;
+    public static final Font FONT_PANEL_TITLE;
+    public static final Font FONT_OPTION_LABEL;
+    
+    private ProtTestFacade prottestFacade;
+
+    static {
+        if (Utilities.isWindows() == false) {
+            FONT_CONSOLE = new Font(Font.MONOSPACED, 0, 10);
+        } else {
+            FONT_CONSOLE = new Font("Lucida Console", 0, 11);
+        }
+        FONT_LABEL = new Font("Application", 1, 9);
+        FONT_OPTION_LABEL = new Font("Application", 0, 10);
+        FONT_PANEL_TITLE = new Font("Application", 1, 10);
+    }
+
+    /**
+     * At startup create and show the main frame of the application.
+     */
+    @Override
+    protected void startup() {
+        prottestFacade = new ProtTestFacadeThread(
+                Runtime.getRuntime().availableProcessors());
+//        prottestFacade = new ProtTestFacadeSequential();
+        XProtTestView view = new XProtTestView(this, prottestFacade);
+        show(view);
+    }
+
+    /**
+     * This method is to initialize the specified window by injecting resources.
+     * Windows shown in our application come fully initialized from the GUI
+     * builder, so this additional configuration is not needed.
+     */
+    @Override
+    protected void configureWindow(java.awt.Window root) {
+    }
+
+    /**
+     * A convenient static getter for the application instance.
+     * @return the instance of XProtTestApp
+     */
+    public static XProtTestApp getApplication() {
+        return Application.getInstance(XProtTestApp.class);
+    }
+
+    /**
+     * Main method launching the application.
+     */
+    public static void main(String[] args) {
+        launch(XProtTestApp.class, args);
+    }
+
+    public static JFileChooser createFileChooser(String title) {
+        JFileChooser fc = new JFileChooser();
+        fc.setDialogTitle(title);
+        fc.setFileFilter(fc.getAcceptAllFileFilter());
+        fc.setCurrentDirectory(new File("."));
+        return fc;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/XProtTestView.java b/src/main/java/es/uvigo/darwin/xprottest/XProtTestView.java
new file mode 100755
index 0000000..a72094a
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/XProtTestView.java
@@ -0,0 +1,1138 @@
+/*
+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.xprottest;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.FileDialog;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.print.PrinterException;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.ActionMap;
+import javax.swing.Icon;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextArea;
+import javax.swing.KeyStroke;
+import javax.swing.Timer;
+import javax.swing.plaf.BorderUIResource;
+
+import org.jdesktop.application.Action;
+import org.jdesktop.application.Application;
+import org.jdesktop.application.ApplicationContext;
+import org.jdesktop.application.FrameView;
+import org.jdesktop.application.ResourceMap;
+import org.jdesktop.application.SingleFrameApplication;
+import org.jdesktop.application.Task;
+import org.jdesktop.application.TaskMonitor;
+import org.jdesktop.application.TaskService;
+
+import pal.alignment.Alignment;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.ProtTest;
+import es.uvigo.darwin.prottest.facade.ProtTestFacade;
+import es.uvigo.darwin.prottest.facade.TreeFacade;
+import es.uvigo.darwin.prottest.facade.TreeFacadeImpl;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.ProtTestAlignment;
+import es.uvigo.darwin.prottest.util.exception.AlignmentParseException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.factory.ProtTestFactory;
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import es.uvigo.darwin.prottest.util.printer.ProtTestFormattedOutput;
+import es.uvigo.darwin.prottest.util.printer.ProtTestPrinter;
+import es.uvigo.darwin.xprottest.analysis.FrequenciesView;
+import es.uvigo.darwin.xprottest.analysis.TreeView;
+import es.uvigo.darwin.xprottest.analysis.consensus.Consensus;
+import es.uvigo.darwin.xprottest.compute.OptionsView;
+import es.uvigo.darwin.xprottest.compute.RunningFrame;
+import es.uvigo.darwin.xprottest.results.ErrorLogView;
+import es.uvigo.darwin.xprottest.results.ResultsView;
+import es.uvigo.darwin.xprottest.util.BrowserLauncher;
+import es.uvigo.darwin.xprottest.util.TextAreaAppender;
+
+/**
+ * The XProtTest main frame offers whole connection between the application
+ * componentes providing the full functionality of ProtTest-HPC.
+ * 
+ * @author Diego Darriba
+ */
+public final class XProtTestView extends FrameView {
+
+	/* Application colors */
+	public static final Color NORMAL_COLOR = Color.BLACK;
+	public static final Color CRITIC_COLOR = new Color(153, 0, 0);
+	public static final Color DONE_COLOR = new Color(102, 102, 153);
+	/* Settings */
+	private int errorBehavior;
+	/* General variables */
+	private ResourceMap resourceMap;
+	private Alignment alignment;
+	private Tree tree;
+	private ProtTestFacade prottestFacade;
+	private boolean alignmentLoaded;
+	private File alignmentFile;
+	private boolean lnlCalculated;
+	private Model[] models;
+	private PrintWriter displayWriter;
+	private Handler mainHandler;
+	private PrintWriter lowLevelDisplayWriter;
+	private Handler lowLevelHandler;
+	/* WINDOWS */
+	private ResultsView resultsView;
+	private TreeView treeView;
+	private Consensus consensusView;
+	private FrequenciesView frequenciesView;
+	private ErrorLogView errorLogView;
+
+	public int getErrorBehavior() {
+		return errorBehavior;
+	}
+
+	protected void setErrorBehavior(int errorBehavior) {
+		this.errorBehavior = errorBehavior;
+	}
+
+	public ProtTestFacade getFacade() {
+		return prottestFacade;
+	}
+
+	private void setAlignmentFile(File alignmentFile) {
+		enableHandler();
+		int numDecimals = 5;
+		alignmentLoaded = (alignmentFile != null);
+		if (alignmentLoaded) {
+			lblDataFileStatus.setText(resourceMap.getString("msg-data-loaded")
+					+ " " + alignmentFile.getName());
+			lblDataFileStatus.setForeground(DONE_COLOR);
+			this.alignmentFile = alignmentFile;
+			showFrequenciesItem.setEnabled(true);
+			double[] frequencies = ProtTestAlignment.getFrequencies(alignment);
+			displayWriter.println("");
+			displayWriter.println(resourceMap.getString("aa-frequencies"));
+			displayWriter.println(ProtTestFormattedOutput.space(resourceMap
+					.getString("aa-frequencies").length(), '-'));
+
+			for (int i = 0; i < frequencies.length; i++) {
+				displayWriter.println(ProtTestAlignment.charOfIndex(i)
+						+ " - "
+						+ ProtTestFormattedOutput.getDecimalString(
+								frequencies[i], numDecimals));
+			}
+		} else {
+			lblDataFileStatus.setText(resourceMap.getString("msg-no-data"));
+			lblDataFileStatus.setForeground(CRITIC_COLOR);
+			showFrequenciesItem.setEnabled(false);
+		}
+		frequenciesView = null;
+		computeMenuItem.setEnabled(alignmentLoaded);
+		resultsMenuItem.setEnabled(false);
+		if (resultsView != null) {
+			resultsView.dispose();
+			resultsView = null;
+		}
+		showTreeMenuItem.setEnabled(false);
+		if (treeView != null) {
+			treeView.dispose();
+			treeView = null;
+		}
+		averagingMenuItem.setEnabled(false);
+		if (consensusView != null) {
+			consensusView.dispose();
+			consensusView = null;
+		}
+		disableHandler();
+	}
+
+	public PrintWriter getDisplayWriter() {
+		return displayWriter;
+	}
+
+	public XProtTestView(SingleFrameApplication app, ProtTestFacade facade) {
+		super(app);
+
+		resourceMap = Application
+				.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class)
+				.getContext().getResourceMap(XProtTestView.class);
+
+		this.errorBehavior = Application
+				.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class)
+				.getContext().getResourceMap(XProtTestApp.class)
+				.getInteger("default-error-behavior");
+
+		this.prottestFacade = facade;
+
+		initComponents();
+
+		displayWriter = new PrintWriter(new TextAreaAppender(mainTextArea));
+		lowLevelDisplayWriter = new PrintWriter(new TextAreaAppender(
+				phymlTextArea));
+
+		mainHandler = ProtTestLogger.getDefaultLogger().addHandler(
+				displayWriter);
+		lowLevelHandler = ProtTestLogger.getDefaultLogger().addLowLevelHandler(
+				lowLevelDisplayWriter);
+		try {
+			Handler logHandler = ProtTestFactory.getInstance()
+					.createLogHandler();
+			if (logHandler != null) {
+				ProtTestLogger.getDefaultLogger().addHandler(logHandler);
+			}
+		} catch (IOException ex) {
+			ProtTestLogger.getDefaultLogger().severeln(ex.getMessage());
+		}
+		// status bar initialization - message timeout, idle icon and busy
+		// animation, etc
+
+		int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
+		messageTimer = new Timer(messageTimeout, new ActionListener() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				lblLikelihoodStatus.setText("");
+			}
+		});
+		messageTimer.setRepeats(false);
+		int busyAnimationRate = resourceMap
+				.getInteger("StatusBar.busyAnimationRate");
+		for (int i = 0; i < busyIcons.length; i++) {
+			busyIcons[i] = resourceMap
+					.getIcon("StatusBar.busyIcons[" + i + "]");
+		}
+		busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
+				lblDataFileStatus.setIcon(busyIcons[busyIconIndex]);
+			}
+		});
+		idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
+		lblDataFileStatus.setIcon(idleIcon);
+
+		TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
+		taskMonitor
+				.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
+
+					@Override
+					public void propertyChange(
+							java.beans.PropertyChangeEvent evt) {
+						String propertyName = evt.getPropertyName();
+						if ("started".equals(propertyName)) {
+							if (!busyIconTimer.isRunning()) {
+								lblDataFileStatus.setIcon(busyIcons[0]);
+								busyIconIndex = 0;
+								busyIconTimer.start();
+							}
+						} else if ("done".equals(propertyName)) {
+							busyIconTimer.stop();
+							lblDataFileStatus.setIcon(idleIcon);
+						} else if ("message".equals(propertyName)) {
+							String text = (String) (evt.getNewValue());
+							lblLikelihoodStatus.setText((text == null) ? ""
+									: text);
+							messageTimer.restart();
+						} else if ("progress".equals(propertyName)) {
+							int value = (Integer) (evt.getNewValue());
+						}
+					}
+				});
+		lblMoreInfo.setVisible(false);
+
+		ProtTestPrinter.printHeader();
+		disableHandler();
+	}
+
+	public void disableHandler() {
+		mainHandler.setLevel(Level.OFF);
+	}
+
+	public void enableHandler() {
+		mainHandler.setLevel(Level.INFO);
+	}
+
+	@Action
+	public void showAboutBox() {
+		if (aboutBox == null) {
+			JFrame mainFrame = XProtTestApp.getApplication().getMainFrame();
+			aboutBox = new XProtTestAboutBox(mainFrame);
+			aboutBox.setLocationRelativeTo(mainFrame);
+		}
+		aboutBox.setVisible(true);
+	}
+
+	@Action
+	public void showCreditsBox() {
+		if (creditsBox == null) {
+			JFrame mainFrame = XProtTestApp.getApplication().getMainFrame();
+			creditsBox = new CreditsBox(mainFrame);
+			creditsBox.setLocationRelativeTo(mainFrame);
+		}
+		creditsBox.setVisible(true);
+	}
+
+	/**
+	 * This method is called from within the constructor to initialize the form.
+	 * WARNING: Do NOT modify this code. The content of this method is always
+	 * regenerated by the Form Editor.
+	 */
+	private void initComponents() {
+
+		mainPanel = new JPanel();
+		mainTabbedPane = new JTabbedPane();
+		mainScrollPane = new JScrollPane();
+		mainTextArea = new JTextArea();
+		phymlScrollPane = new JScrollPane();
+		phymlTextArea = new JTextArea();
+		statusPanel = new JPanel();
+		lblDataFileStatus = new JLabel();
+		lblLikelihoodStatus = new JLabel();
+		lblMoreInfo = new JLabel();
+		menuBar = new JMenuBar();
+		fileMenu = new JMenu();
+		loadAlignmentMenuItem = new JMenuItem();
+		exitMenuItem = new JMenuItem();
+		saveConsoleMenuItem = new JMenuItem();
+		printConsoleMenuItem = new JMenuItem();
+		editMenu = new JMenu();
+		editCopyMenuItem = new JMenuItem();
+		editSelectAllMenuItem = new JMenuItem();
+		preferencesMenuItem = new JMenuItem();
+		analysisMenu = new JMenu();
+		computeMenuItem = new JMenuItem();
+		showFrequenciesItem = new JMenuItem();
+		showTreeMenuItem = new JMenuItem();
+		averagingMenuItem = new JMenuItem();
+		resultsMenu = new JMenu();
+		resultsMenuItem = new JMenuItem();
+		errorMenuItem = new JMenuItem();
+		helpMenu = new JMenu();
+		manualMenuItem = new JMenuItem();
+		aboutMenuItem = new JMenuItem();
+
+		org.jdesktop.application.ResourceMap appResourceMap = org.jdesktop.application.Application
+				.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class)
+				.getContext().getResourceMap(XProtTestView.class);
+
+		mainPanel.setSize(new java.awt.Dimension(500, 860));
+		mainPanel.setBorder(new BorderUIResource.EmptyBorderUIResource(
+				new java.awt.Insets(20, 20, 20, 20)));
+		mainPanel.setLocation(new java.awt.Point(10, -10));
+		mainPanel.setVisible(true);
+		mainPanel.setAutoscrolls(true);
+		mainPanel.setLayout(new BorderLayout());
+		mainPanel.setBackground(null);
+
+		// mainPanel.setBackground(resourceMap.getColor("mainPanel.background"));
+		mainPanel.setName("mainPanel");
+		// mainPanel.setPreferredSize(new java.awt.Dimension(500, 600));
+
+		mainScrollPane.setSize(590, 800);// new java.awt.Dimension(590, 600));
+		mainScrollPane.setLocation(new java.awt.Point(20, 20));
+		mainScrollPane.setVisible(true);
+		mainScrollPane.setAutoscrolls(true);
+
+		mainScrollPane.setName("mainScrollPane");
+		// mainScrollPane.setPreferredSize(new java.awt.Dimension(460, 500));
+
+		mainTextArea.setMargin(new Insets(5, 5, 5, 5));
+		mainTextArea.setBackground(Color.white);
+		mainTextArea.setEditable(false);
+		mainTextArea.setSize(500, 800);// new java.awt.Dimension(15, 10));
+		mainTextArea.setAutoscrolls(true);
+		mainTextArea.setVisible(true);
+
+		// mainTextArea.setColumns(15);
+		// mainTextArea.setEditable(false);
+		mainTextArea.setFont(XProtTestApp.FONT_CONSOLE);
+		// mainTextArea.setRows(30);
+		mainTextArea.setName("mainTextArea");
+		// mainScrollPane.setViewportView(mainTextArea);
+		mainScrollPane
+				.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+		mainTextArea.setWrapStyleWord(true);
+		mainTextArea.setLineWrap(true);
+
+		phymlTextArea.setMargin(new Insets(5, 5, 5, 5));
+		phymlTextArea.setBackground(Color.white);
+		phymlTextArea.setEditable(false);
+		phymlTextArea.setSize(500, 800);// new java.awt.Dimension(15, 10));
+		phymlTextArea.setAutoscrolls(true);
+		phymlTextArea.setVisible(true);
+		phymlTextArea.setFont(XProtTestApp.FONT_CONSOLE);
+		phymlTextArea.setName("phymlTextArea");
+		phymlScrollPane
+				.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
+		phymlTextArea.setWrapStyleWord(true);
+		phymlTextArea.setLineWrap(true);
+
+		statusPanel.setPreferredSize(new java.awt.Dimension(592, 30));
+		statusPanel.setBorder(new BorderUIResource.EtchedBorderUIResource(1,
+				new java.awt.Color(182, 182, 182), new java.awt.Color(89, 89,
+						89)));
+		statusPanel.setLocation(new java.awt.Point(20, 630));
+		statusPanel.setVisible(true);
+		statusPanel.setLayout(new BorderLayout());
+		statusPanel.setForeground(java.awt.Color.blue);
+		statusPanel.setBackground(new java.awt.Color(220, 220, 220));
+		// statusPanel.setFont(new java.awt.Font("Dialog", 0, 9));
+
+		// statusPanel.setBorder(BorderFactory.createLineBorder(new
+		// java.awt.Color(0, 0, 0)));
+		statusPanel.setName("statusPanel");
+		// statusPanel.setPreferredSize(new java.awt.Dimension(100, 200));
+
+		lblDataFileStatus.setSize(new java.awt.Dimension(150, 40));
+		lblDataFileStatus.setVisible(true);
+		lblDataFileStatus.setForeground(CRITIC_COLOR);
+		lblDataFileStatus.setHorizontalAlignment(JLabel.RIGHT);
+		lblDataFileStatus.setFont(XProtTestApp.FONT_LABEL);
+
+		java.util.ResourceBundle bundle = java.util.ResourceBundle
+				.getBundle("es/uvigo/darwin/xprottest/resources/XProtTestView");
+		lblDataFileStatus.setText(bundle.getString("msg-no-data"));
+		lblDataFileStatus.setName("lblDataFileStatus");
+
+		lblLikelihoodStatus.setSize(new java.awt.Dimension(270, 40));
+		lblLikelihoodStatus.setVisible(true);
+		lblLikelihoodStatus.setForeground(CRITIC_COLOR);
+		lblLikelihoodStatus.setFont(XProtTestApp.FONT_LABEL);
+
+		lblLikelihoodStatus.setText(bundle.getString("msg-no-lnl-calculated"));
+		lblLikelihoodStatus.setName("lblLikelihoodStatus");
+
+		// mainPanel.add(mainScrollPane, BorderLayout.CENTER);
+		mainPanel.add(mainTabbedPane, BorderLayout.CENTER);
+		mainTabbedPane.addTab("Main", mainScrollPane);
+		mainTabbedPane.addTab("Phyml-log", phymlScrollPane);
+
+		mainPanel.add(statusPanel, BorderLayout.PAGE_END);
+		mainScrollPane.getViewport().add(mainTextArea);
+		phymlScrollPane.getViewport().add(phymlTextArea);
+		statusPanel.add(lblLikelihoodStatus, BorderLayout.LINE_START);
+		statusPanel.add(lblDataFileStatus, BorderLayout.LINE_END);
+
+		menuBar.setName("menuBar");
+
+		ActionMap actionMap = org.jdesktop.application.Application
+				.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class)
+				.getContext().getActionMap(XProtTestView.class, this);
+		fileMenu.setAction(actionMap.get("openDataFile"));
+		fileMenu.setMnemonic('F');
+		fileMenu.setText(bundle.getString("item-file"));
+		fileMenu.setName("fileMenu");
+
+		saveConsoleMenuItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_S,
+				java.awt.event.InputEvent.CTRL_MASK));
+		saveConsoleMenuItem.setMnemonic('S');
+		saveConsoleMenuItem.setText(bundle.getString("item-save-console"));
+		saveConsoleMenuItem.setName("saveConsoleMenuItem");
+		saveConsoleMenuItem
+				.addActionListener(new java.awt.event.ActionListener() {
+
+					@Override
+					public void actionPerformed(java.awt.event.ActionEvent evt) {
+						saveConsole(evt);
+					}
+				});
+		printConsoleMenuItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_P,
+				java.awt.event.InputEvent.CTRL_MASK));
+		printConsoleMenuItem.setMnemonic('P');
+		printConsoleMenuItem.setText(bundle.getString("item-print-console"));
+		printConsoleMenuItem.setName("printConsoleMenuItem");
+		printConsoleMenuItem
+				.addActionListener(new java.awt.event.ActionListener() {
+
+					@Override
+					public void actionPerformed(java.awt.event.ActionEvent evt) {
+						printConsole(evt);
+					}
+				});
+		loadAlignmentMenuItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_O,
+				java.awt.event.InputEvent.CTRL_MASK));
+		loadAlignmentMenuItem.setMnemonic('L');
+		loadAlignmentMenuItem.setText(bundle.getString("item-load-alignment"));
+		loadAlignmentMenuItem.setName("loadAlignmentMenuItem");
+		loadAlignmentMenuItem
+				.addActionListener(new java.awt.event.ActionListener() {
+
+					@Override
+					public void actionPerformed(java.awt.event.ActionEvent evt) {
+						openDataFile(evt);
+					}
+				});
+		fileMenu.add(loadAlignmentMenuItem);
+		fileMenu.add(saveConsoleMenuItem);
+		fileMenu.add(printConsoleMenuItem);
+		exitMenuItem.setAction(actionMap.get("quit"));
+		exitMenuItem.setMnemonic('x');
+		exitMenuItem.setName("menuFileExit");
+		fileMenu.add(exitMenuItem);
+
+		menuBar.add(fileMenu);
+
+		editMenu.setMnemonic('E');
+		editMenu.setText(appResourceMap.getString("menu-edit"));
+		editMenu.setName("editMenu");
+
+		editCopyMenuItem.setAction(actionMap.get("editCopy"));
+		editCopyMenuItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_C,
+				java.awt.event.InputEvent.CTRL_MASK));
+		editCopyMenuItem.setMnemonic('c');
+		editCopyMenuItem.setText(appResourceMap.getString("menu-copy"));
+		editCopyMenuItem.setToolTipText(appResourceMap
+				.getString("editCopyMenuItem.toolTipText"));
+		editCopyMenuItem.setName("editCopyMenuItem");
+		editMenu.add(editCopyMenuItem);
+
+		editSelectAllMenuItem.setAction(actionMap.get("editSelectAll"));
+		editSelectAllMenuItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_A,
+				java.awt.event.InputEvent.CTRL_MASK));
+		editSelectAllMenuItem.setMnemonic('a');
+		editSelectAllMenuItem.setText(appResourceMap
+				.getString("menu-selectAll"));
+		editSelectAllMenuItem.setToolTipText(appResourceMap
+				.getString("editSelectAllMenuItem.toolTipText"));
+		editSelectAllMenuItem.setName("editSelectAllMenuItem");
+		editMenu.add(editSelectAllMenuItem);
+
+		preferencesMenuItem.setMnemonic('p');
+		preferencesMenuItem.setText(appResourceMap
+				.getString("menu-preferences"));
+		preferencesMenuItem.setToolTipText(appResourceMap
+				.getString("editPreferencesMenuItem.toolTipText"));
+		preferencesMenuItem.setName("preferencesMenuItem");
+		preferencesMenuItem
+				.addActionListener(new java.awt.event.ActionListener() {
+
+					@Override
+					public void actionPerformed(java.awt.event.ActionEvent evt) {
+						loadPreferencesView(evt);
+					}
+				});
+		editMenu.add(preferencesMenuItem);
+
+		menuBar.add(editMenu);
+
+		analysisMenu.setMnemonic('A');
+		analysisMenu.setText(bundle.getString("item-analysis"));
+		analysisMenu.setName("analysisMenu");
+
+		computeMenuItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_L,
+				java.awt.event.InputEvent.CTRL_MASK));
+		computeMenuItem.setMnemonic('c');
+		computeMenuItem.setText(bundle.getString("item-compute-likelihood"));
+		computeMenuItem.setToolTipText(appResourceMap
+				.getString("computeMenuItem.toolTipText"));
+		computeMenuItem.setEnabled(false);
+		computeMenuItem.setName("computeMenuItem");
+		computeMenuItem.addActionListener(new java.awt.event.ActionListener() {
+
+			@Override
+			public void actionPerformed(java.awt.event.ActionEvent evt) {
+				loadOptionsView(evt);
+			}
+		});
+		analysisMenu.add(computeMenuItem);
+
+		showFrequenciesItem
+				.setAction(actionMap.get("showAminoacidFrequencies"));
+		showFrequenciesItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_F,
+				java.awt.event.InputEvent.SHIFT_MASK
+						| java.awt.event.InputEvent.CTRL_MASK));
+		showFrequenciesItem.setMnemonic('f');
+		showFrequenciesItem.setText(bundle.getString("item-show-frequencies"));
+		showFrequenciesItem.setToolTipText(appResourceMap
+				.getString("showFrequenciesItem.toolTipText"));
+		showFrequenciesItem.setEnabled(false);
+		showFrequenciesItem.setName("showFrequenciesItem");
+		analysisMenu.add(showFrequenciesItem);
+
+		showTreeMenuItem.setAction(actionMap.get("showTree"));
+		showTreeMenuItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_T,
+				java.awt.event.InputEvent.SHIFT_MASK
+						| java.awt.event.InputEvent.CTRL_MASK));
+		showTreeMenuItem.setMnemonic('t');
+		showTreeMenuItem.setText(bundle.getString("item-show-tree"));
+		showTreeMenuItem.setToolTipText(appResourceMap
+				.getString("showTreeMenuItem.toolTipText"));
+		showTreeMenuItem.setEnabled(false);
+		showTreeMenuItem.setName("showTreeMenuItem");
+		analysisMenu.add(showTreeMenuItem);
+
+		averagingMenuItem.setAction(actionMap.get("showConsensus"));
+		averagingMenuItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_C,
+				java.awt.event.InputEvent.SHIFT_MASK
+						| java.awt.event.InputEvent.CTRL_MASK));
+		averagingMenuItem.setMnemonic('p');
+		averagingMenuItem.setText(appResourceMap
+				.getString("averagingMenuItem.text"));
+		averagingMenuItem.setToolTipText(appResourceMap
+				.getString("averagingMenuItem.toolTipText"));
+		averagingMenuItem.setEnabled(false);
+		averagingMenuItem.setName("averagingMenuItem");
+		analysisMenu.add(averagingMenuItem);
+
+		menuBar.add(analysisMenu);
+
+		resultsMenu.setAction(actionMap.get("showResultsWindow"));
+		resultsMenu.setMnemonic('S');
+		resultsMenu.setText(bundle.getString("item-results"));
+		resultsMenu.setName("resultsMenu");
+
+		resultsMenuItem.setAction(actionMap.get("showResultsWindow"));
+		resultsMenuItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_R,
+				java.awt.event.InputEvent.SHIFT_MASK
+						| java.awt.event.InputEvent.CTRL_MASK));
+		resultsMenuItem.setMnemonic('r');
+		resultsMenuItem.setText(bundle.getString("item-results-sub"));
+		resultsMenuItem.setEnabled(false);
+		resultsMenuItem.setName("resultsMenuItem");
+		resultsMenuItem.setToolTipText(appResourceMap
+				.getString("resultsMenuItem.toolTipText"));
+		resultsMenu.add(resultsMenuItem);
+
+		errorMenuItem.setAction(actionMap.get("showErrorLog"));
+		errorMenuItem.setAccelerator(KeyStroke.getKeyStroke(
+				java.awt.event.KeyEvent.VK_E,
+				java.awt.event.InputEvent.SHIFT_MASK
+						| java.awt.event.InputEvent.CTRL_MASK));
+		errorMenuItem.setMnemonic('e');
+		errorMenuItem.setText(appResourceMap.getString("errorMenuItem.text"));
+		errorMenuItem.setToolTipText(appResourceMap
+				.getString("errorMenuItem.toolTipText"));
+		errorMenuItem.setEnabled(false);
+		errorMenuItem.setName("errorMenuItem");
+		resultsMenu.add(errorMenuItem);
+
+		menuBar.add(resultsMenu);
+
+		helpMenu.setMnemonic('H');
+		helpMenu.setText(bundle.getString("item-help"));
+		helpMenu.setName("helpMenu");
+
+		manualMenuItem.setAction(actionMap.get("showManual"));
+		manualMenuItem.setMnemonic('m');
+		manualMenuItem.setText(appResourceMap.getString("menu-manual"));
+		manualMenuItem.setName("manualMenuItem");
+		helpMenu.add(manualMenuItem);
+
+		aboutMenuItem.setAction(actionMap.get("showAboutBox"));
+		aboutMenuItem.setText(bundle.getString("item-about-window"));
+		aboutMenuItem.setName("aboutMenuItem");
+		helpMenu.add(aboutMenuItem);
+
+		creditsMenuItem.setAction(actionMap.get("showCreditsBox"));
+		creditsMenuItem.setText(bundle.getString("item-credits-window"));
+		creditsMenuItem.setName("creditsMenuItem");
+		helpMenu.add(creditsMenuItem);
+
+		menuBar.add(helpMenu);
+
+		setComponent(mainPanel);
+		setMenuBar(menuBar);
+
+		this.getFrame().setLayout(new BorderLayout());
+
+		this.getFrame().setLocation(new java.awt.Point(281, 80));
+		this.getFrame().getContentPane().setLayout(new BorderLayout());
+		this.getFrame().setTitle("ProtTest " + ProtTest.versionNumber);
+		this.getFrame().setSize(new java.awt.Dimension(630, 695));
+		this.getFrame().setResizable(true);
+		this.getFrame().setContentPane(mainPanel);
+	}
+
+	private void openDataFile(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_openDataFile
+		FileDialog fc = new FileDialog(this.getFrame(),
+				"Load amino-acid alignment", FileDialog.LOAD);
+		fc.setDirectory(System.getProperty("user.dir"));
+		fc.setVisible(true);
+
+		String dataFileName = fc.getFile();
+
+		if (dataFileName != null) {
+			enableHandler();
+			try {
+				ProtTestPrinter.printPreAnalysisHeader();
+				File f = new File(fc.getDirectory() + dataFileName);// fc.getSelectedFile();
+				ProtTestPrinter.printFileData(f);
+				if (alignmentFile == null
+						|| !f.getAbsolutePath().equals(
+								alignmentFile.getAbsolutePath())) {
+					lblLikelihoodStatus.setText(resourceMap
+							.getString("msg-no-lnl-calculated"));
+					lblLikelihoodStatus.setForeground(CRITIC_COLOR);
+					lnlCalculated = false;
+				}
+				alignment = prottestFacade.readAlignment(f.getAbsolutePath(),
+						true);
+				setAlignmentFile(f);
+			} catch (AlignmentParseException ex) {
+				displayWriter.println(ex.getMessage());
+				setAlignmentFile(null);
+			} catch (FileNotFoundException ex) {
+				displayWriter.println(ex.getMessage());
+				setAlignmentFile(null);
+			} catch (IOException ex) {
+				displayWriter.println(ex.getMessage());
+				setAlignmentFile(null);
+			}
+			disableHandler();
+		}
+	}// GEN-LAST:event_openDataFile
+
+	private void saveConsole(java.awt.event.ActionEvent evt) {
+		String text = mainTextArea.getText();
+
+		FileDialog fc = new FileDialog(this.getFrame(),
+				"Save ProtTest console", FileDialog.SAVE);
+		fc.setDirectory(System.getProperty("user.dir"));
+		fc.setVisible(true);
+
+		String dataFileName = fc.getFile();
+		try {
+			File f = new File(dataFileName);
+			FileWriter fw = new FileWriter(f);
+			fw.write(text);
+			fw.close();
+		} catch (IOException ex) {
+			Logger.getLogger(XProtTestView.class.getName()).log(Level.SEVERE,
+					null, ex);
+		}
+	}
+
+	private void printConsole(java.awt.event.ActionEvent evt) {
+		try {
+			mainTextArea.print();
+		} catch (PrinterException ex) {
+			Logger.getLogger(XProtTestView.class.getName()).log(Level.SEVERE,
+					null, ex);
+		}
+	}
+
+	private void loadOptionsView(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_loadOptionsView
+		OptionsView op = new OptionsView(this, alignment,
+				alignmentFile.getAbsolutePath());
+		op.setVisible(true);
+
+		enableItems(false);
+	}// GEN-LAST:event_loadOptionsView
+
+	private void loadPreferencesView(java.awt.event.ActionEvent evt) {// GEN-FIRST:event_loadPreferencesView
+		PreferencesView pv = new PreferencesView(this);
+		pv.setVisible(true);
+
+		enableItems(false);
+	}// GEN-LAST:event_loadPreferencesView
+
+	public void unloadOptionsView(boolean running) {
+		if (!running) {
+			enableItems(true);
+
+		}
+	}
+
+	public void unloadPreferencesView() {
+		enableItems(true);
+
+	}
+
+	// private JFileChooser createFileChooser(String title) {
+	// JFileChooser fc = new JFileChooser();
+	// fc.setDialogTitle(title);
+	// fc.setFileFilter(fc.getAcceptAllFileFilter());
+	// fc.setCurrentDirectory(new File("."));
+	// return fc;
+	// }
+
+	@Action
+	public void showAminoacidFrequencies() {
+		if (alignment != null) {
+			if (frequenciesView == null) {
+				frequenciesView = new FrequenciesView(alignment);
+
+			}
+			frequenciesView.setVisible(true);
+
+		}
+	}
+
+	private boolean correctDone;
+
+	@Action
+	public void showResultsWindow() {
+		if (models != null) {
+			if (resultsView == null) {
+				resultsView = new ResultsView(this, alignment, models,
+						correctDone);
+
+			}
+			resultsView.setVisible(true);
+
+		}
+	}
+
+	private int numModels;
+	private boolean taskRunning = false;
+
+	public void computeLikelihood(int numModels, ApplicationOptions options) {
+
+		enableHandler();
+
+		ProtTestPrinter.printExecutionHeader(options);
+
+		preferencesMenuItem.setEnabled(false);
+
+		this.numModels = numModels;
+
+		if (errorLogView != null) {
+			ProtTestLogger.getDefaultLogger().removeHandler(
+					errorLogView.getLogHandler());
+			errorLogView.setVisible(false);
+			errorLogView.dispose();
+			errorLogView = null;
+
+		}
+		if (resultsView != null) {
+			resultsView.setVisible(false);
+			resultsView.dispose();
+			resultsView = null;
+
+		}
+		if (treeView != null) {
+			treeView.setVisible(false);
+			treeView.dispose();
+			treeView = null;
+
+		}
+		if (consensusView != null) {
+			consensusView.setVisible(false);
+			consensusView.dispose();
+			consensusView = null;
+
+		}
+		errorLogView = new ErrorLogView();
+		ProtTestLogger.getDefaultLogger().addHandler(
+				errorLogView.getLogHandler());
+		RunningFrame runningFrame = new RunningFrame(this, numModels);
+		errorMenuItem.setEnabled(false);
+		prottestFacade.addObserver(runningFrame);
+		lblMoreInfo.setVisible(false);
+
+		Task task = new ComputeLikelihoodTask(getApplication(), runningFrame,
+				this, options);
+		// get the application's context...
+		ApplicationContext appC = Application.getInstance().getContext();
+		// ...to get the TaskMonitor and TaskService
+		TaskMonitor tM = appC.getTaskMonitor();
+		TaskService tS = appC.getTaskService();
+
+		// i.e. making the animated progressbar and busy icon visible
+		tS.execute(task);
+		taskRunning = true;
+
+		enableItems(false);
+		runningFrame.setVisible(true);
+
+	}
+
+	private void enableItems(boolean enable) {
+		menuBar.setEnabled(enable);
+		fileMenu.setEnabled(enable);
+		editMenu.setEnabled(enable);
+		analysisMenu.setEnabled(enable);
+		resultsMenu.setEnabled(enable);
+		helpMenu.setEnabled(enable);
+	}
+
+	protected void computationDone(boolean done, Model[] models) {
+
+		preferencesMenuItem.setEnabled(true);
+
+		if (done) {
+			correctDone = (models.length == this.numModels);
+
+			if (correctDone) {
+				lblLikelihoodStatus.setText(resourceMap
+						.getString("msg-lnl-calculated"));
+				lblLikelihoodStatus.setForeground(DONE_COLOR);
+				errorMenuItem.setEnabled(false);
+				lblMoreInfo.setVisible(false);
+
+				if (errorLogView != null) {
+					errorLogView.setVisible(false);
+					errorLogView.dispose();
+					errorLogView = null;
+
+				}
+			} else {
+				lblLikelihoodStatus.setText("Warning! "
+						+ resourceMap.getString("models-not-complete"));
+				lblLikelihoodStatus.setForeground(CRITIC_COLOR);
+				displayWriter.println("");
+				displayWriter.println(resourceMap
+						.getString("models-not-complete"));
+				displayWriter.println(resourceMap
+						.getString("msg-see-error-log"));
+				errorMenuItem.setEnabled(true);
+				lblMoreInfo.setVisible(true);
+
+			}
+		} else {
+			lblLikelihoodStatus.setText(resourceMap.getString("msg-lnl-error"));
+			lblLikelihoodStatus.setForeground(CRITIC_COLOR);
+			displayWriter.println(resourceMap.getString("msg-see-error-log"));
+			errorMenuItem.setEnabled(true);
+
+		}
+
+		lnlCalculated = done;
+		resultsMenuItem.setEnabled(done);
+		showTreeMenuItem.setEnabled(done);
+		averagingMenuItem.setEnabled(done);
+
+		this.models = models;
+
+		disableHandler();
+
+	}
+
+	public void computationInterrupted() {
+		lblLikelihoodStatus.setText(resourceMap.getString("msg-lnl-error"));
+		lblLikelihoodStatus.setForeground(CRITIC_COLOR);
+		errorMenuItem.setEnabled(true);
+		lblMoreInfo.setVisible(true);
+		disableHandler();
+
+	}
+
+	public void unloadRunningView(RunningFrame rf) {
+		enableItems(true);
+		rf.setVisible(false);
+		disableHandler();
+	}
+
+	private class ComputeLikelihoodTask extends Task<Object, Void> {
+
+		private RunningFrame runningFrame;
+		private XProtTestView mainFrame;
+		private Model[] models;
+		private ApplicationOptions options;
+
+		ComputeLikelihoodTask(Application app, RunningFrame runningFrame,
+				XProtTestView mainFrame, ApplicationOptions options) {
+			// Runs on the EDT. Copy GUI state that
+			// doInBackground() depends on from parameters
+			// to ComputeLikelihoodTask fields, here.
+			super(app);
+			this.options = options;
+			this.runningFrame = runningFrame;
+			this.mainFrame = mainFrame;
+			runningFrame.setTask(this);
+		}
+
+		@Override
+		protected Object doInBackground() {
+			// Your Task's code here. This method runs
+			// on a background thread, so don't reference
+			// the Swing GUI from here.
+			// ProtTestPrinter printer = new ProtTestPrinter(getDisplayWriter(),
+			// new PrintWriter(System.err));
+
+			try {
+				options.setAlignment(alignmentFile.getAbsolutePath());
+				models = prottestFacade.startAnalysis(options);
+			} catch (AlignmentParseException ex) {
+				ProtTestLogger.severeln(ex.getMessage(), this.getClass());
+			} catch (IOException ex) {
+				ProtTestLogger.severeln(ex.getMessage(), this.getClass());
+			} catch (ProtTestInternalException ex) {
+				ProtTestLogger.severeln(ex.getMessage(), this.getClass());
+			}
+
+			runningFrame.finishedExecution();
+
+			return null; // return your result
+		}
+
+		@Override
+		protected void succeeded(Object result) {
+			// Runs on the EDT. Update the GUI based on
+			// the result computed by doInBackground().
+			boolean done = models != null && models.length > 0;
+			if (done) {
+				try {
+					for (Model model : models) {
+						// throws ProtTestInternalException when Lk is not set
+						model.getLk();
+					}
+				} catch (ProtTestInternalException e) {
+					done = false;
+				}
+			}
+
+			mainFrame.computationDone(done, models);
+		}
+
+		@Override
+		protected void cancelled() {
+			mainFrame.computationDone(false, null);
+		}
+
+		@Override
+		protected void interrupted(InterruptedException ex) {
+			mainFrame.computationInterrupted();
+		}
+	}
+
+	@Action
+	public void showTree() {
+		TreeFacade treeFacade = new TreeFacadeImpl();
+
+		if (models != null) {
+			if (treeView == null) {
+				treeView = new TreeView(this, treeFacade, tree, models);
+
+			}
+			treeView.setVisible(true);
+
+		}
+	}
+
+	@Action
+	public void showConsensus() {
+		TreeFacade treeFacade = new TreeFacadeImpl();
+
+		if (models != null) {
+			if (consensusView == null) {
+				consensusView = new Consensus(this, treeFacade, models,
+						alignment);
+
+			}
+			consensusView.setVisible(true);
+
+		}
+	}
+
+	@Action
+	public void showErrorLog() {
+		if (errorLogView != null) {
+			errorLogView.setVisible(true);
+
+		}
+	}
+
+	@Action
+	public void editCopy() {
+		mainTextArea.copy();
+
+	}
+
+	@Action
+	public void editSelectAll() {
+		mainTextArea.selectAll();
+
+	}
+
+	@Action
+	public void showPreferences() {
+	}
+
+	@Action
+	public void showManual() {
+		try {
+			BrowserLauncher
+					.openURL("http://darwin.uvigo.es/download/prottest_manual.pdf");
+
+		} catch (IOException e) {
+			displayWriter.println("Cannot open URL : " + e.getMessage());
+
+		}
+	}
+
+	// Variables declaration - do not modify//GEN-BEGIN:variables
+	private JMenu fileMenu;
+	private JMenuItem exitMenuItem;
+	private JMenu analysisMenu;
+	private JMenuItem averagingMenuItem;
+	private JMenuItem computeMenuItem;
+	private JMenuItem editCopyMenuItem;
+	private JMenu editMenu;
+	private JMenuItem editSelectAllMenuItem;
+	private JMenuItem errorMenuItem;
+	private JLabel lblDataFileStatus;
+	private JLabel lblLikelihoodStatus;
+	private JLabel lblMoreInfo;
+	private JMenuItem loadAlignmentMenuItem;
+	private JPanel mainPanel;
+	private JTabbedPane mainTabbedPane;
+	private JScrollPane phymlScrollPane;
+	private JTextArea phymlTextArea;
+	private JScrollPane mainScrollPane;
+	private JTextArea mainTextArea;
+	private JMenuItem manualMenuItem;
+	private JMenuBar menuBar;
+	private JMenuItem preferencesMenuItem;
+	private JMenu resultsMenu;
+	private JMenuItem resultsMenuItem;
+	private JMenuItem showFrequenciesItem;
+	private JMenuItem showTreeMenuItem;
+	private JMenu helpMenu;
+	private JMenuItem aboutMenuItem;
+	private JPanel statusPanel;
+	// End of variables declaration//GEN-END:variables
+	private JMenuItem saveConsoleMenuItem;
+	private JMenuItem printConsoleMenuItem;
+	private JMenuItem creditsMenuItem = new JMenuItem();
+	private final Timer messageTimer;
+	private final Timer busyIconTimer;
+	private final Icon idleIcon;
+	private final Icon[] busyIcons = new Icon[15];
+	private int busyIconIndex = 0;
+	private JDialog aboutBox;
+	private JDialog creditsBox;
+
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/analysis/FrequenciesView.java b/src/main/java/es/uvigo/darwin/xprottest/analysis/FrequenciesView.java
new file mode 100755
index 0000000..d7aeda9
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/analysis/FrequenciesView.java
@@ -0,0 +1,128 @@
+/*
+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.xprottest.analysis;
+
+import es.uvigo.darwin.prottest.util.ProtTestAlignment;
+import es.uvigo.darwin.prottest.util.printer.ProtTestFormattedOutput;
+import pal.alignment.Alignment;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.RowSorter;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
+
+/**
+ * This frame shows the observed frequencies of every amino-acid on
+ * the selected alignment.
+ * 
+ * @author  Diego Darriba
+ */
+public class FrequenciesView extends javax.swing.JFrame {
+    
+    private int freqWidth = 5;
+    
+    /** Creates new form FrequenciesView */
+    public FrequenciesView(Alignment alignment) {
+        initComponents();
+        double[] frequencies = ProtTestAlignment.getFrequencies(alignment);
+        for (int i = 0; i < frequencies.length; i++) {
+            tableFrequencies.setValueAt(ProtTestAlignment.charOfIndex(i), i, 0);
+            tableFrequencies.setValueAt(
+                ProtTestFormattedOutput.getDecimalString(frequencies[i], freqWidth), i, 1);
+        }
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        jScrollPane1 = new javax.swing.JScrollPane();
+        tableFrequencies = new javax.swing.JTable();
+        lblTitle = new javax.swing.JLabel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setName("Form"); // NOI18N
+
+        jScrollPane1.setName("jScrollPane1"); // NOI18N
+
+        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class).getContext().getResourceMap(FrequenciesView.class);
+        tableFrequencies.setBackground(resourceMap.getColor("tableFrequencies.background")); // NOI18N
+        DefaultTableModel freqTableModel =
+        new javax.swing.table.DefaultTableModel() {
+            public Class getColumnClass(int column) {
+                if (column >= 0 && column <= getColumnCount()){
+                    try {
+                        return getValueAt(0, column).getClass();
+                    } catch (ArrayIndexOutOfBoundsException e) {
+                        return Object.class;
+                    }
+                }
+                else
+                return Object.class;
+            }
+            public boolean isCellEditable(int row, int col) { return false; }
+        };
+        freqTableModel.addColumn("AA", new String[20][1]);
+        freqTableModel.addColumn("Frequency", new Double[20][1]);
+        tableFrequencies.setModel(freqTableModel
+        );
+        RowSorter<TableModel> freqSorter = new TableRowSorter<TableModel>(freqTableModel);
+        tableFrequencies.setRowSorter(freqSorter);
+        tableFrequencies.setColumnSelectionAllowed(true);
+        tableFrequencies.setName("tableFrequencies"); // NOI18N
+        jScrollPane1.setViewportView(tableFrequencies);
+
+        lblTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("es/uvigo/darwin/xprottest/analysis/resources/FrequenciesView"); // NOI18N
+        lblTitle.setText(bundle.getString("msg-title")); // NOI18N
+        lblTitle.setName("lblTitle"); // NOI18N
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 217, Short.MAX_VALUE)
+                    .addComponent(lblTitle, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 217, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(lblTitle)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 343, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+    
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JScrollPane jScrollPane1;
+    private javax.swing.JLabel lblTitle;
+    private javax.swing.JTable tableFrequencies;
+    // End of variables declaration//GEN-END:variables
+    
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/analysis/TreeView.java b/src/main/java/es/uvigo/darwin/xprottest/analysis/TreeView.java
new file mode 100755
index 0000000..2c255d1
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/analysis/TreeView.java
@@ -0,0 +1,282 @@
+/*
+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.xprottest.analysis;
+
+import es.uvigo.darwin.prottest.facade.TreeFacade;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import es.uvigo.darwin.prottest.util.printer.ProtTestPrinter;
+import es.uvigo.darwin.xprottest.XProtTestView;
+import java.awt.Font;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import org.jdesktop.application.Action;
+import pal.tree.Tree;
+import es.uvigo.darwin.xprottest.util.TextAreaWriter;
+/**
+ *
+ * @author  diego
+ */
+public class TreeView extends javax.swing.JFrame {
+    
+    private Tree tree;
+    private List<Tree> trees;
+    private TreeFacade facade;
+    private PrintWriter displayWriter;
+    private XProtTestView mainFrame;
+    
+    /** Creates new form TreeView */
+    public TreeView(XProtTestView mainFrame, TreeFacade facade, Tree tree, Model[] models) {
+        this.mainFrame = mainFrame;
+        this.tree = tree;
+        this.facade = facade;
+        this.trees = new ArrayList<Tree>(models.length);
+        
+        initComponents();
+        displayWriter = new PrintWriter(new TextAreaWriter(displayArea));
+
+        Font f = new Font(Font.MONOSPACED, Font.PLAIN, 12);
+        displayArea.setFont(f);
+        
+        if (tree != null)
+            cmbTreeSelection.addItem(new TreeWrapper("Starting Topology", tree));
+        if (models != null) {
+            for (Model model : models) {
+                if (model.getTree() != null) {
+                    cmbTreeSelection.addItem(new TreeWrapper(model.getModelName(), model.getTree()));
+                    trees.add(model.getTree());
+                }
+            }
+        }
+        if (cmbTreeSelection.getItemCount() > 0)
+            cmbTreeSelection.setSelectedIndex(0);
+
+        treeFormatSelection();
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        treeDisplayTypeBtnGroup = new javax.swing.ButtonGroup();
+        displayScroll = new javax.swing.JScrollPane();
+        displayArea = new javax.swing.JTextArea();
+        optionsPanel = new javax.swing.JPanel();
+        cmbTreeSelection = new javax.swing.JComboBox();
+        cmbTreeFormatSelection = new javax.swing.JComboBox();
+        btnExport = new javax.swing.JButton();
+        jMenuBar1 = new javax.swing.JMenuBar();
+        windowMenu = new javax.swing.JMenu();
+        closeMenuItem = new javax.swing.JMenuItem();
+        editMenu = new javax.swing.JMenu();
+        editCopyMenuItem = new javax.swing.JMenuItem();
+        editSelectAllMenuItem = new javax.swing.JMenuItem();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("es/uvigo/darwin/xprottest/analysis/resources/TreeView"); // NOI18N
+        setTitle(bundle.getString("title")); // NOI18N
+        setName("Form"); // NOI18N
+        setResizable(false);
+
+        displayScroll.setName("displayScroll"); // NOI18N
+
+        displayArea.setColumns(20);
+        displayArea.setEditable(false);
+        displayArea.setRows(5);
+        displayArea.setName("displayArea"); // NOI18N
+        displayScroll.setViewportView(displayArea);
+
+        optionsPanel.setName("optionsPanel"); // NOI18N
+
+        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance().getContext().getActionMap(TreeView.class, this);
+        cmbTreeSelection.setAction(actionMap.get("treeFormatSelection")); // NOI18N
+        cmbTreeSelection.setName("cmbTreeSelection"); // NOI18N
+
+        cmbTreeFormatSelection.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Newick Format", "ASCII Format" }));
+        cmbTreeFormatSelection.setSelectedItem("ASCII Format");
+        cmbTreeFormatSelection.setAction(actionMap.get("treeFormatSelection")); // NOI18N
+        cmbTreeFormatSelection.setName("cmbTreeFormatSelection"); // NOI18N
+
+        btnExport.setAction(actionMap.get("exportData")); // NOI18N
+        btnExport.setText("Export to main console"); // NOI18N
+        btnExport.setName("btnExport"); // NOI18N
+
+        javax.swing.GroupLayout optionsPanelLayout = new javax.swing.GroupLayout(optionsPanel);
+        optionsPanel.setLayout(optionsPanelLayout);
+        optionsPanelLayout.setHorizontalGroup(
+            optionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(optionsPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(cmbTreeSelection, javax.swing.GroupLayout.PREFERRED_SIZE, 173, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 47, Short.MAX_VALUE)
+                .addComponent(cmbTreeFormatSelection, javax.swing.GroupLayout.PREFERRED_SIZE, 124, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(btnExport))
+        );
+        optionsPanelLayout.setVerticalGroup(
+            optionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(optionsPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(optionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(cmbTreeSelection, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(btnExport)
+                    .addComponent(cmbTreeFormatSelection, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        jMenuBar1.setName("jMenuBar1"); // NOI18N
+
+        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance().getContext().getResourceMap(TreeView.class);
+        windowMenu.setText(resourceMap.getString("windowMenu.text")); // NOI18N
+        windowMenu.setName("windowMenu"); // NOI18N
+
+        closeMenuItem.setAction(actionMap.get("close")); // NOI18N
+        closeMenuItem.setName("closeMenuItem"); // NOI18N
+        windowMenu.add(closeMenuItem);
+
+        jMenuBar1.add(windowMenu);
+
+        editMenu.setText(resourceMap.getString("editMenu.text")); // NOI18N
+        editMenu.setName("editMenu"); // NOI18N
+
+        editCopyMenuItem.setAction(actionMap.get("editCopy")); // NOI18N
+        editCopyMenuItem.setName("editCopyMenuItem"); // NOI18N
+        editMenu.add(editCopyMenuItem);
+
+        editSelectAllMenuItem.setAction(actionMap.get("editSelectAll")); // NOI18N
+        editSelectAllMenuItem.setName("editSelectAllMenuItem"); // NOI18N
+        editMenu.add(editSelectAllMenuItem);
+
+        jMenuBar1.add(editMenu);
+
+        setJMenuBar(jMenuBar1);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(displayScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 527, Short.MAX_VALUE)
+                    .addComponent(optionsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(optionsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(displayScroll, javax.swing.GroupLayout.DEFAULT_SIZE, 451, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void displayAsciiTree(Tree tree) {
+        displayArea.setText("");
+        displayArea.setLineWrap(false);
+        displayWriter.println(facade.toASCII(tree));
+        displayWriter.println(" ");
+        displayWriter.println(facade.branchInfo(tree));
+        displayWriter.println(" ");
+        displayWriter.println(facade.heightInfo(tree));
+    }
+
+    private void displayNewickTree(Tree tree) {
+        displayArea.setText("");
+        displayArea.setLineWrap(true);
+        String newickTree = facade.toNewick(tree, true, true, false);
+        displayWriter.println(newickTree);
+    }
+
+    
+    @Action
+    public void treeFormatSelection() {
+        Tree displayTree = ((TreeWrapper)cmbTreeSelection.getSelectedItem()).getTree();
+
+        if (cmbTreeFormatSelection.getSelectedItem()
+                .toString().toLowerCase().contains("newick"))
+            displayNewickTree(displayTree);
+        else if (cmbTreeFormatSelection.getSelectedItem()
+                .toString().toLowerCase().contains("ascii"))
+            displayAsciiTree(displayTree);
+    }
+
+    @Action
+    public void editCopy() {
+        displayArea.copy();
+    }
+
+    @Action
+    public void editSelectAll() {
+        displayArea.selectAll();
+    }
+
+    @Action
+    public void close() {
+        this.setVisible(false);
+    }
+
+    @Action
+    public void exportData() {
+        mainFrame.enableHandler();
+        ProtTestPrinter.printTreeHeader(((TreeWrapper)cmbTreeSelection.getSelectedItem()).toString());
+        ProtTestLogger.getDefaultLogger().infoln(displayArea.getText());
+        mainFrame.disableHandler();
+    }
+
+//    @Action
+//    public void buildConsensus() {
+//        double threshold = Double.parseDouble(txtThreshold.getText());
+//        
+//        if (consensusTrees.containsKey(threshold)) {
+//            cmbTreeSelection.setSelectedItem(consensusTrees.get(threshold));
+//        } else {
+//            Tree consensus = facade.createConsensusTree(trees, threshold);
+//            TreeWrapper consensusWrapper = new TreeWrapper("Consensus " + threshold, consensus);
+//            consensusTrees.put(threshold, consensusWrapper);
+//            cmbTreeSelection.addItem(consensusWrapper);
+//            cmbTreeSelection.setSelectedItem(consensusWrapper);
+//        }
+//    }
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton btnExport;
+    private javax.swing.JMenuItem closeMenuItem;
+    private javax.swing.JComboBox cmbTreeFormatSelection;
+    private javax.swing.JComboBox cmbTreeSelection;
+    private javax.swing.JTextArea displayArea;
+    private javax.swing.JScrollPane displayScroll;
+    private javax.swing.JMenuItem editCopyMenuItem;
+    private javax.swing.JMenu editMenu;
+    private javax.swing.JMenuItem editSelectAllMenuItem;
+    private javax.swing.JMenuBar jMenuBar1;
+    private javax.swing.JPanel optionsPanel;
+    private javax.swing.ButtonGroup treeDisplayTypeBtnGroup;
+    private javax.swing.JMenu windowMenu;
+    // End of variables declaration//GEN-END:variables
+    
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/analysis/TreeWrapper.java b/src/main/java/es/uvigo/darwin/xprottest/analysis/TreeWrapper.java
new file mode 100755
index 0000000..f4224c3
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/analysis/TreeWrapper.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.xprottest.analysis;
+
+import pal.tree.Tree;
+
+/**
+ *
+ * @author Diego Darriba
+ */
+public class TreeWrapper {
+
+    private String id;
+    private Tree tree;
+    
+    public Tree getTree() {
+        return tree;
+    }
+    
+    public TreeWrapper (String id, Tree tree) {
+        this.id = id;
+        this.tree = tree;
+    }
+    
+    @Override
+    public String toString() {
+        return id;
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/analysis/consensus/Consensus.java b/src/main/java/es/uvigo/darwin/xprottest/analysis/consensus/Consensus.java
new file mode 100755
index 0000000..6131d92
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/analysis/consensus/Consensus.java
@@ -0,0 +1,690 @@
+/*
+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.xprottest.analysis.consensus;
+
+import static es.uvigo.darwin.prottest.util.logging.ProtTestLogger.getDefaultLogger;
+import static es.uvigo.darwin.prottest.util.logging.ProtTestLogger.infoln;
+
+import java.awt.Font;
+import java.io.PrintWriter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+
+import org.jdesktop.application.Action;
+import org.jdesktop.application.Application;
+import org.jdesktop.application.ResourceMap;
+
+import pal.alignment.Alignment;
+import pal.misc.Identifier;
+import pal.tree.Tree;
+import es.uvigo.darwin.prottest.facade.TreeFacade;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.AIC;
+import es.uvigo.darwin.prottest.selection.AICc;
+import es.uvigo.darwin.prottest.selection.BIC;
+import es.uvigo.darwin.prottest.selection.DT;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.selection.LNL;
+import es.uvigo.darwin.prottest.util.collection.ModelCollection;
+import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogger;
+import es.uvigo.darwin.prottest.util.printer.ProtTestPrinter;
+import es.uvigo.darwin.xprottest.XProtTestView;
+import es.uvigo.darwin.xprottest.util.TextAreaWriter;
+
+/**
+ * 
+ * @author diego
+ */
+public class Consensus extends javax.swing.JFrame {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 7857819028765401188L;
+
+	private static final int AIC_SELECTION = 0;
+	private static final int BIC_SELECTION = 1;
+	private static final int AICC_SELECTION = 2;
+	private static final int LNL_SELECTION = 3;
+	private static final int DT_SELECTION = 4;
+	private static final int DISABLED_SELECTION = 5;
+	private static final String[] SELECTION = { "AIC", "BIC", "AICc", "LK",
+			"DT", "Disabled" };
+	private ResourceMap resourceMap;
+	private TreeFacade facade;
+	private ModelCollection models;
+	private Handler logHandler;
+	private PrintWriter displayWriter;
+	private XProtTestView mainFrame;
+
+	/** Creates new form Consensus */
+	public Consensus(XProtTestView mainFrame, TreeFacade facade,
+			Model[] models, Alignment alignment) {
+		initComponents();
+		this.mainFrame = mainFrame;
+		this.facade = facade;
+		this.models = new SingleModelCollection(models, alignment);
+		this.displayWriter = new PrintWriter(new TextAreaWriter(displayArea));
+		this.logHandler = getDefaultLogger().addHandler(displayWriter,
+				Level.OFF);
+
+		resourceMap = Application
+				.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class)
+				.getContext().getResourceMap(Consensus.class);
+
+		Font f = new Font(Font.MONOSPACED, Font.PLAIN, 12);
+		displayArea.setFont(f);
+	}
+
+	/**
+	 * This method is called from within the constructor to initialize the form.
+	 * WARNING: Do NOT modify this code. The content of this method is always
+	 * regenerated by the Form Editor.
+	 */
+	// <editor-fold defaultstate="collapsed"
+	// desc="Generated Code">//GEN-BEGIN:initComponents
+	private void initComponents() {
+
+		btnGrpCriterion = new javax.swing.ButtonGroup();
+		settingsPanel = new javax.swing.JPanel();
+		lblTitle = new javax.swing.JLabel();
+		lblCriterion = new javax.swing.JLabel();
+		radioAIC = new javax.swing.JRadioButton();
+		radioBIC = new javax.swing.JRadioButton();
+		radioAICC = new javax.swing.JRadioButton();
+		radioDT = new javax.swing.JRadioButton();
+		radioLK = new javax.swing.JRadioButton();
+		sliderConsType = new javax.swing.JSlider();
+		lblConsType = new javax.swing.JLabel();
+		btnBuild = new javax.swing.JButton();
+		lblMR = new javax.swing.JLabel();
+		lblStrict = new javax.swing.JLabel();
+		lblConfInt = new javax.swing.JLabel();
+		sliderConfidence = new javax.swing.JSlider();
+		lblConfidenceInterval = new javax.swing.JLabel();
+		lblConsensusType = new javax.swing.JLabel();
+		lblPercent = new javax.swing.JLabel();
+		btnExport = new javax.swing.JButton();
+		displayScroll = new javax.swing.JScrollPane();
+		displayArea = new javax.swing.JTextArea();
+		jMenuBar1 = new javax.swing.JMenuBar();
+		windowMenu = new javax.swing.JMenu();
+		closeMenuItem = new javax.swing.JMenuItem();
+		editMenu = new javax.swing.JMenu();
+		editCopyMenuItem = new javax.swing.JMenuItem();
+		selectAllMenuItem = new javax.swing.JMenuItem();
+
+		org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application
+				.getInstance().getContext().getResourceMap(Consensus.class);
+		setTitle(resourceMap.getString("Form.title")); // NOI18N
+		setName("Form"); // NOI18N
+
+		settingsPanel.setBorder(javax.swing.BorderFactory
+				.createBevelBorder(javax.swing.border.BevelBorder.RAISED));
+		settingsPanel.setName("settingsPanel"); // NOI18N
+
+		lblTitle.setBackground(resourceMap.getColor("lblTitle.background")); // NOI18N
+		lblTitle.setFont(resourceMap.getFont("lblTitle.font")); // NOI18N
+		lblTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+		lblTitle.setText(resourceMap.getString("title.text")); // NOI18N
+		lblTitle.setName("lblTitle"); // NOI18N
+
+		lblCriterion.setText(resourceMap.getString("lblCriterion.text")); // NOI18N
+		lblCriterion.setName("lblCriterion"); // NOI18N
+
+		javax.swing.ActionMap actionMap = org.jdesktop.application.Application
+				.getInstance().getContext().getActionMap(Consensus.class, this);
+		btnGrpCriterion.add(radioAIC);
+		radioAIC.setText(resourceMap.getString("radioAIC.text")); // NOI18N
+		radioAIC.setName("radioAIC"); // NOI18N
+
+		btnGrpCriterion.add(radioBIC);
+		radioBIC.setText(resourceMap.getString("radioBIC.text")); // NOI18N
+		radioBIC.setName("radioBIC"); // NOI18N
+
+		btnGrpCriterion.add(radioAICC);
+		radioAICC.setText(resourceMap.getString("radioAICC.text")); // NOI18N
+		radioAICC.setName("radioAICC"); // NOI18N
+
+		btnGrpCriterion.add(radioDT);
+		radioDT.setSelected(true);
+		radioDT.setText(resourceMap.getString("radioDT.text")); // NOI18N
+		radioDT.setName("radioDT"); // NOI18N
+
+		btnGrpCriterion.add(radioLK);
+		radioLK.setText(resourceMap.getString("radioLK.text")); // NOI18N
+		radioLK.setName("radioLK"); // NOI18N
+
+		sliderConsType.setMinimum(50);
+		sliderConsType.setToolTipText(resourceMap
+				.getString("sliderConsType.toolTipText")); // NOI18N
+		sliderConsType.setName("sliderConsType"); // NOI18N
+		sliderConsType
+				.addChangeListener(new javax.swing.event.ChangeListener() {
+					public void stateChanged(javax.swing.event.ChangeEvent evt) {
+						sliderConsTypeStateChanged(evt);
+					}
+				});
+
+		lblConsType.setText(resourceMap.getString("lblConsType.text")); // NOI18N
+		lblConsType.setName("lblConsType"); // NOI18N
+
+		btnBuild.setAction(actionMap.get("buildConsensus")); // NOI18N
+		btnBuild.setText(resourceMap.getString("btnBuild.text")); // NOI18N
+		btnBuild.setName("btnBuild"); // NOI18N
+
+		lblMR.setFont(resourceMap.getFont("lblMR.font")); // NOI18N
+		lblMR.setForeground(resourceMap.getColor("lblMR.foreground")); // NOI18N
+		lblMR.setText(resourceMap.getString("lblMR.text")); // NOI18N
+		lblMR.setName("lblMR"); // NOI18N
+
+		lblStrict.setFont(resourceMap.getFont("lblStrict.font")); // NOI18N
+		lblStrict.setForeground(resourceMap.getColor("lblStrict.foreground")); // NOI18N
+		lblStrict.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+		lblStrict.setText(resourceMap.getString("lblStrict.text")); // NOI18N
+		lblStrict.setName("lblStrict"); // NOI18N
+
+		lblConfInt.setText(resourceMap.getString("lblConfInt.text")); // NOI18N
+		lblConfInt.setToolTipText(resourceMap
+				.getString("lblConfInt.toolTipText")); // NOI18N
+		lblConfInt.setName("lblConfInt"); // NOI18N
+
+		sliderConfidence.setValue(100);
+		sliderConfidence.setName("sliderConfidence"); // NOI18N
+		sliderConfidence
+				.addChangeListener(new javax.swing.event.ChangeListener() {
+					public void stateChanged(javax.swing.event.ChangeEvent evt) {
+						sliderConfidenceStateChanged(evt);
+					}
+				});
+
+		lblConfidenceInterval.setText(resourceMap
+				.getString("default-confidence-interval")); // NOI18N
+		lblConfidenceInterval.setName("lblConfidenceInterval"); // NOI18N
+
+		lblConsensusType
+				.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+		lblConsensusType.setText(resourceMap
+				.getString("default-consensus-type")); // NOI18N
+		lblConsensusType.setName("lblConsensusType"); // NOI18N
+
+		lblPercent.setText(resourceMap.getString("percent-symbol")); // NOI18N
+		lblPercent.setName("lblPercent"); // NOI18N
+
+		btnExport.setAction(actionMap.get("exportData")); // NOI18N
+		btnExport.setText(resourceMap.getString("btnExport.text")); // NOI18N
+		btnExport.setEnabled(false);
+		btnExport.setName("btnExport"); // NOI18N
+
+		javax.swing.GroupLayout settingsPanelLayout = new javax.swing.GroupLayout(
+				settingsPanel);
+		settingsPanel.setLayout(settingsPanelLayout);
+		settingsPanelLayout
+				.setHorizontalGroup(settingsPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								settingsPanelLayout
+										.createSequentialGroup()
+										.addGroup(
+												settingsPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																settingsPanelLayout
+																		.createSequentialGroup()
+																		.addContainerGap()
+																		.addGroup(
+																				settingsPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING)
+																						.addComponent(
+																								lblCriterion,
+																								javax.swing.GroupLayout.PREFERRED_SIZE,
+																								161,
+																								javax.swing.GroupLayout.PREFERRED_SIZE)
+																						.addComponent(
+																								lblTitle,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								636,
+																								Short.MAX_VALUE)
+																						.addGroup(
+																								settingsPanelLayout
+																										.createSequentialGroup()
+																										.addGap(12,
+																												12,
+																												12)
+																										.addComponent(
+																												radioAIC)
+																										.addPreferredGap(
+																												javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+																										.addComponent(
+																												radioBIC)
+																										.addPreferredGap(
+																												javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+																										.addComponent(
+																												radioAICC)
+																										.addPreferredGap(
+																												javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+																										.addComponent(
+																												radioDT)
+																										.addPreferredGap(
+																												javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+																										.addComponent(
+																												radioLK))
+																						.addGroup(
+																								settingsPanelLayout
+																										.createSequentialGroup()
+																										.addComponent(
+																												lblConsType)
+																										.addPreferredGap(
+																												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																										.addComponent(
+																												lblConsensusType,
+																												javax.swing.GroupLayout.PREFERRED_SIZE,
+																												40,
+																												javax.swing.GroupLayout.PREFERRED_SIZE)
+																										.addPreferredGap(
+																												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																										.addComponent(
+																												lblPercent))
+																						.addComponent(
+																								sliderConsType,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								636,
+																								Short.MAX_VALUE)
+																						.addGroup(
+																								settingsPanelLayout
+																										.createSequentialGroup()
+																										.addComponent(
+																												lblMR,
+																												javax.swing.GroupLayout.PREFERRED_SIZE,
+																												76,
+																												javax.swing.GroupLayout.PREFERRED_SIZE)
+																										.addGap(129,
+																												129,
+																												129)
+																										.addComponent(
+																												btnBuild)
+																										.addPreferredGap(
+																												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																										.addComponent(
+																												btnExport)
+																										.addPreferredGap(
+																												javax.swing.LayoutStyle.ComponentPlacement.RELATED,
+																												182,
+																												Short.MAX_VALUE)
+																										.addComponent(
+																												lblStrict,
+																												javax.swing.GroupLayout.PREFERRED_SIZE,
+																												40,
+																												javax.swing.GroupLayout.PREFERRED_SIZE))
+																						.addComponent(
+																								sliderConfidence,
+																								javax.swing.GroupLayout.Alignment.TRAILING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								636,
+																								Short.MAX_VALUE)
+																						.addGroup(
+																								settingsPanelLayout
+																										.createSequentialGroup()
+																										.addComponent(
+																												lblConfInt)
+																										.addPreferredGap(
+																												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																										.addComponent(
+																												lblConfidenceInterval)))))
+										.addContainerGap()));
+		settingsPanelLayout
+				.setVerticalGroup(settingsPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								settingsPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addComponent(lblTitle)
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addComponent(lblCriterion)
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addGroup(
+												settingsPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.BASELINE)
+														.addComponent(radioAIC)
+														.addComponent(radioBIC)
+														.addComponent(radioAICC)
+														.addComponent(radioDT)
+														.addComponent(radioLK))
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+										.addGroup(
+												settingsPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.BASELINE)
+														.addComponent(
+																lblConfInt)
+														.addComponent(
+																lblConfidenceInterval))
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addComponent(
+												sliderConfidence,
+												javax.swing.GroupLayout.PREFERRED_SIZE,
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												javax.swing.GroupLayout.PREFERRED_SIZE)
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addGroup(
+												settingsPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.BASELINE)
+														.addComponent(
+																lblConsType)
+														.addComponent(
+																lblConsensusType)
+														.addComponent(
+																lblPercent))
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addComponent(
+												sliderConsType,
+												javax.swing.GroupLayout.PREFERRED_SIZE,
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												javax.swing.GroupLayout.PREFERRED_SIZE)
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addGroup(
+												settingsPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addComponent(lblMR)
+														.addComponent(lblStrict)
+														.addGroup(
+																settingsPanelLayout
+																		.createParallelGroup(
+																				javax.swing.GroupLayout.Alignment.BASELINE)
+																		.addComponent(
+																				btnBuild)
+																		.addComponent(
+																				btnExport)))
+										.addContainerGap()));
+
+		displayScroll.setName("displayScroll"); // NOI18N
+
+		displayArea.setColumns(20);
+		displayArea.setEditable(false);
+		displayArea.setLineWrap(true);
+		displayArea.setRows(5);
+		displayArea.setName("displayArea"); // NOI18N
+		displayScroll.setViewportView(displayArea);
+
+		jMenuBar1.setName("jMenuBar1"); // NOI18N
+
+		windowMenu.setName("windowMenu"); // NOI18N
+
+		closeMenuItem.setAction(actionMap.get("Close")); // NOI18N
+		closeMenuItem.setName("closeMenuItem"); // NOI18N
+		windowMenu.add(closeMenuItem);
+
+		jMenuBar1.add(windowMenu);
+
+		editMenu.setText(resourceMap.getString("editMenu.text")); // NOI18N
+		editMenu.setName("editMenu"); // NOI18N
+
+		editCopyMenuItem.setAction(actionMap.get("editCopy")); // NOI18N
+		editCopyMenuItem.setName("editCopyMenuItem"); // NOI18N
+		editMenu.add(editCopyMenuItem);
+
+		selectAllMenuItem.setAction(actionMap.get("editSelectAll")); // NOI18N
+		selectAllMenuItem.setText(resourceMap
+				.getString("selectAllMenuItem.text")); // NOI18N
+		selectAllMenuItem.setName("selectAllMenuItem"); // NOI18N
+		editMenu.add(selectAllMenuItem);
+
+		jMenuBar1.add(editMenu);
+
+		setJMenuBar(jMenuBar1);
+
+		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(
+				getContentPane());
+		getContentPane().setLayout(layout);
+		layout.setHorizontalGroup(layout
+				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+				.addGroup(
+						javax.swing.GroupLayout.Alignment.TRAILING,
+						layout.createSequentialGroup()
+								.addContainerGap()
+								.addGroup(
+										layout.createParallelGroup(
+												javax.swing.GroupLayout.Alignment.TRAILING)
+												.addComponent(
+														displayScroll,
+														javax.swing.GroupLayout.Alignment.LEADING,
+														javax.swing.GroupLayout.DEFAULT_SIZE,
+														664, Short.MAX_VALUE)
+												.addComponent(
+														settingsPanel,
+														javax.swing.GroupLayout.Alignment.LEADING,
+														javax.swing.GroupLayout.DEFAULT_SIZE,
+														javax.swing.GroupLayout.DEFAULT_SIZE,
+														Short.MAX_VALUE))
+								.addContainerGap()));
+		layout.setVerticalGroup(layout
+				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+				.addGroup(
+						layout.createSequentialGroup()
+								.addContainerGap()
+								.addComponent(settingsPanel,
+										javax.swing.GroupLayout.PREFERRED_SIZE,
+										javax.swing.GroupLayout.DEFAULT_SIZE,
+										javax.swing.GroupLayout.PREFERRED_SIZE)
+								.addPreferredGap(
+										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+								.addComponent(displayScroll,
+										javax.swing.GroupLayout.DEFAULT_SIZE,
+										362, Short.MAX_VALUE).addContainerGap()));
+
+		pack();
+	}// </editor-fold>//GEN-END:initComponents
+
+	private void sliderConfidenceStateChanged(javax.swing.event.ChangeEvent evt) {// GEN-FIRST:event_sliderConfidenceStateChanged
+		lblConfidenceInterval.setText(String.valueOf(Double
+				.valueOf(sliderConfidence.getValue()) / 100));
+	}// GEN-LAST:event_sliderConfidenceStateChanged
+
+	private void sliderConsTypeStateChanged(javax.swing.event.ChangeEvent evt) {// GEN-FIRST:event_sliderConsTypeStateChanged
+		lblConsensusType.setText(String.valueOf(Double.valueOf(sliderConsType
+				.getValue()) / 100));
+	}// GEN-LAST:event_sliderConsTypeStateChanged
+
+	@Action
+	public void buildConsensus() {
+		displayArea.setText("");
+		displayArea.setForeground(XProtTestView.NORMAL_COLOR);
+		double confidenceInterval = Double.valueOf(sliderConfidence.getValue()) / 100;
+		double supportThreshold = Double.valueOf(sliderConsType.getValue()) / 100;
+		InformationCriterion ic;
+		int selection;
+		if (radioAIC.isSelected()) {
+			ic = new AIC(models, confidenceInterval, models.getAlignment()
+					.getSiteCount());
+			selection = AIC_SELECTION;
+		} else if (radioBIC.isSelected()) {
+			ic = new BIC(models, confidenceInterval, models.getAlignment()
+					.getSiteCount());
+			selection = BIC_SELECTION;
+		} else if (radioAICC.isSelected()) {
+			ic = new AICc(models, confidenceInterval, models.getAlignment()
+					.getSiteCount());
+			selection = AICC_SELECTION;
+		} else if (radioLK.isSelected()) {
+			ic = new LNL(models, confidenceInterval, models.getAlignment()
+					.getSiteCount());
+			selection = LNL_SELECTION;
+		} else if (radioDT.isSelected()) {
+			ic = new DT(models, confidenceInterval, models.getAlignment()
+					.getSiteCount());
+			selection = DT_SELECTION;
+		} else {
+			ic = null;
+			selection = DISABLED_SELECTION;
+		}
+
+		logHandler.setLevel(Level.INFO);
+
+		if (ic == null || ic.getConfidenceModels().size() > 0) {
+			es.uvigo.darwin.prottest.consensus.Consensus consensus = null;
+			if (ic != null) {
+				consensus = facade.createConsensus(ic, supportThreshold);
+			} else {
+				throw new ProtTestInternalException(
+						"Consensus needs an Information Criterion");
+				// ArrayList<Tree> trees = new ArrayList<Tree>(models.size());
+				// for (Model model : models) {
+				// trees.add(model.getTree());
+				// }
+				// consensus = facade.createConsensus(trees, supportThreshold);
+			}
+			println("----------------------------------------");
+			println("Selection criterion: . . . . " + SELECTION[selection]);
+			println("Confidence interval: . . . . " + confidenceInterval);
+			println("Consensus support threshold: " + supportThreshold);
+			println("----------------------------------------");
+
+			// displayWriter.println("Computed models:");
+			// for (SelectionModel model : ic.getConfidenceModels()) {
+			// displayWriter.println(model.getModel().getModelName() + " (" +
+			// model.getWeightValue() + ")");
+			// }
+			// displayWriter.println("----------------------------------------");
+
+			println("");
+
+			println("# # # # # # # # # # # # # # # #");
+			println(" ");
+			println("Species in order:");
+			println(" ");
+
+			for (int i = 0; i < consensus.getIdGroup().getIdCount(); i++) {
+				Identifier id = consensus.getIdGroup().getIdentifier(i);
+				println("    " + (i + 1) + ". " + id.getName());
+			}
+			println(" ");
+			println("# # # # # # # # # # # # # # # #");
+			println(" ");
+			println("Sets included in the consensus tree");
+			println(" ");
+
+			println(consensus.getSetsIncluded());
+
+			println(" ");
+			println("Sets NOT included in consensus tree");
+			println(" ");
+
+			println(consensus.getSetsNotIncluded());
+
+			println(" ");
+			println("# # # # # # # # # # # # # # # #");
+			println(" ");
+
+			Tree consensusTree = consensus.getConsensusTree();
+			String newickTree = facade
+					.toNewick(consensusTree, true, true, true);
+			println(newickTree);
+
+			println(" ");
+			println("# # # # # # # # # # # # # # # #");
+			println(" ");
+
+			println(facade.toASCII(consensusTree));
+			println(" ");
+			println(facade.branchInfo(consensusTree));
+			println(" ");
+			println(facade.heightInfo(consensusTree));
+		} else {
+			displayArea.setForeground(XProtTestView.CRITIC_COLOR);
+			println(resourceMap.getString("msg-no-data"));
+		}
+		logHandler.setLevel(Level.OFF);
+		btnExport.setEnabled(!displayArea.getText().equals(""));
+	}
+
+	@Action
+	public void close() {
+		getDefaultLogger().removeHandler(logHandler);
+		this.setVisible(false);
+	}
+
+	@Action
+	public void editCopy() {
+		displayArea.copy();
+	}
+
+	@Action
+	public void editSelectAll() {
+		displayArea.selectAll();
+	}
+
+	private void println(String message) {
+		infoln(message, this.getClass());
+	}
+
+	@Action
+	public void exportData() {
+		mainFrame.enableHandler();
+		ProtTestPrinter.printTreeHeader("MODEL AVERAGED PHYLOGENY");
+		ProtTestLogger.getDefaultLogger().infoln(displayArea.getText());
+		mainFrame.disableHandler();
+	}
+
+	// Variables declaration - do not modify//GEN-BEGIN:variables
+	private javax.swing.JButton btnBuild;
+	private javax.swing.JButton btnExport;
+	private javax.swing.ButtonGroup btnGrpCriterion;
+	private javax.swing.JMenuItem closeMenuItem;
+	private javax.swing.JTextArea displayArea;
+	private javax.swing.JScrollPane displayScroll;
+	private javax.swing.JMenuItem editCopyMenuItem;
+	private javax.swing.JMenu editMenu;
+	private javax.swing.JMenuBar jMenuBar1;
+	private javax.swing.JLabel lblConfInt;
+	private javax.swing.JLabel lblConfidenceInterval;
+	private javax.swing.JLabel lblConsType;
+	private javax.swing.JLabel lblConsensusType;
+	private javax.swing.JLabel lblCriterion;
+	private javax.swing.JLabel lblMR;
+	private javax.swing.JLabel lblPercent;
+	private javax.swing.JLabel lblStrict;
+	private javax.swing.JLabel lblTitle;
+	private javax.swing.JRadioButton radioAIC;
+	private javax.swing.JRadioButton radioAICC;
+	private javax.swing.JRadioButton radioBIC;
+	private javax.swing.JRadioButton radioDT;
+	private javax.swing.JRadioButton radioLK;
+	private javax.swing.JMenuItem selectAllMenuItem;
+	private javax.swing.JPanel settingsPanel;
+	private javax.swing.JSlider sliderConfidence;
+	private javax.swing.JSlider sliderConsType;
+	private javax.swing.JMenu windowMenu;
+	// End of variables declaration//GEN-END:variables
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/analysis/consensus/resources/Consensus.properties b/src/main/java/es/uvigo/darwin/xprottest/analysis/consensus/resources/Consensus.properties
new file mode 100755
index 0000000..571796e
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/analysis/consensus/resources/Consensus.properties
@@ -0,0 +1,49 @@
+title.text=Phylogenetic Averaging
+#NOI18N
+lblTitle.background=153, 153, 153
+#NOI18N
+lblTitle.font=Dialog-Bold-12
+lblCriterion.text=Criterion for tree weights:
+radioAIC.text=AIC
+radioBIC.text=BIC
+radioAICC.text=AICc
+radioLK.text=-Lk
+lblConsType.text=Consensus Type:
+btnBuild.toolTip=Builds the consensus tree according to the settings above
+btnBuild.text=Build Consensus
+sliderConsType.toolTipText=Select the consensus threshold (%)
+lblMR.text=Majority Rule
+#NOI18N
+lblMR.foreground=102, 102, 102
+#NOI18N
+lblMR.font=Dialog-Italic-10
+lblStrict.text=Strict
+#NOI18N
+lblStrict.font=Dialog-Italic-10
+#NOI18N
+lblStrict.foreground=102, 102, 102
+lblConfInt.text=Confidence Interval:
+lblConfInt.toolTipText=
+buildConsensus.Action.text=
+buildConsensus.Action.shortDescription=
+msg-no-data=There are no trees in the selection criterion
+Form.title=Consensus Tree
+closeMenuItem.text=Item
+Close.Action.text=
+Close.Action.accelerator=ctrl pressed W
+Close.Action.shortDescription=
+editMenu.text=Edit
+editCopyMenuItem.text=Item
+editCopy.Action.text=Copy
+editCopy.Action.shortDescription=
+jMenuItem1.text=Item
+editSelectAll.Action.shortDescription=
+editSelectAll.Action.text=
+radioDT.text=DT
+default-confidence-interval=1.0
+default-consensus-type=50
+percent-symbol=%
+selectAllMenuItem.text=Select All
+btnExport.text=Export data
+exportData.Action.text=
+exportData.Action.shortDescription=
diff --git a/src/main/java/es/uvigo/darwin/xprottest/analysis/resources/FrequenciesView.properties b/src/main/java/es/uvigo/darwin/xprottest/analysis/resources/FrequenciesView.properties
new file mode 100755
index 0000000..7911318
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/analysis/resources/FrequenciesView.properties
@@ -0,0 +1,4 @@
+
+msg-title=Observed Amino-acid Frequencies
+#NOI18N
+tableFrequencies.background=238, 238, 238
diff --git a/src/main/java/es/uvigo/darwin/xprottest/analysis/resources/TreeView.properties b/src/main/java/es/uvigo/darwin/xprottest/analysis/resources/TreeView.properties
new file mode 100755
index 0000000..3f27113
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/analysis/resources/TreeView.properties
@@ -0,0 +1,28 @@
+
+lbl-newick-tree=Newick Format
+lbl-ascii-tree=ASCII Format
+displayAsciiTree.Action.text=
+displayAsciiTree.Action.shortDescription=
+displayNewickTree.Action.text=
+displayNewickTree.Action.shortDescription=
+title=Display Tree
+lbl-best-aic=Best AIC
+lbl-best-bic=Best BIC
+treeFormatSelection.Action.text=
+treeFormatSelection.Action.shortDescription=
+buildConsensus.Action.text=
+buildConsensus.Action.shortDescription=
+windowMenu.text=Window
+jMenuItem1.text=Select all
+editMenu.text=Edit
+closeMenuItem.text=Close
+editCopy.Action.text=
+editCopy.Action.shortDescription=
+editSelectAll.Action.text=
+editSelectAll.Action.shortDescription=
+close.Action.shortDescription=
+close.Action.text=
+treeFormatSelection.toolTipText=Select the tree display format
+treeSelection.toolTipText=Select the aminoacid substitution model
+exportData.Action.text=
+exportData.Action.shortDescription=
diff --git a/src/main/java/es/uvigo/darwin/xprottest/compute/OptionsView.java b/src/main/java/es/uvigo/darwin/xprottest/compute/OptionsView.java
new file mode 100755
index 0000000..cbc1af7
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/compute/OptionsView.java
@@ -0,0 +1,748 @@
+/*
+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.xprottest.compute;
+
+import es.uvigo.darwin.xprottest.*;
+import es.uvigo.darwin.xprottest.util.OptimizationStrategyWrapper;
+import es.uvigo.darwin.prottest.facade.util.ProtTestParameterVO;
+import static es.uvigo.darwin.prottest.global.AminoAcidApplicationGlobals.*;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.prottest.util.exception.AlignmentParseException;
+import es.uvigo.darwin.prottest.util.exception.ProtTestInternalException;
+import es.uvigo.darwin.prottest.util.exception.TreeFormatException;
+import java.awt.Color;
+import java.awt.FileDialog;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.ResourceBundle;
+import javax.swing.GroupLayout;
+import javax.swing.JCheckBox;
+import org.jdesktop.application.Action;
+import pal.tree.Tree;
+import pal.alignment.Alignment;
+import pal.misc.Identifier;
+
+/**
+ * The execution settings. The options chosen in this view will lead the
+ * execution of ProtTest-HPC likelihood computation.
+ * 
+ * @author  Diego Darriba
+ */
+public class OptionsView extends javax.swing.JFrame {
+    
+    private XProtTestView mainFrame;
+    
+    private ArrayList<JCheckBox> cbMatrices;
+    
+    private String alignmentFilePath;
+    
+    private String treeFilePath;
+    
+    private Alignment alignment;
+    
+    private Tree userTree;
+    
+    private boolean running;
+    
+    private ResourceBundle resource;
+    
+    /** Creates new form OptionsView */
+    public OptionsView(XProtTestView mainFrame, 
+            Alignment alignment, String alignmentFilePath) {
+
+        resource = java.util.ResourceBundle.getBundle("es/uvigo/darwin/xprottest/compute/resources/OptionsView");
+        this.alignment = alignment;
+        
+        this.mainFrame = mainFrame;
+        this.alignmentFilePath = alignmentFilePath;
+        this.running = false;
+        initComponents();
+        msgValidate.setVisible(false);
+        
+        GroupLayout jPanel1Layout = new GroupLayout(subMatricesPanel);
+        GroupLayout.ParallelGroup pg1 = jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING);
+        GroupLayout.ParallelGroup pg2 = jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING);
+        GroupLayout.SequentialGroup horizontalGroup = jPanel1Layout.createSequentialGroup()
+                .addContainerGap();
+
+        GroupLayout.ParallelGroup verticalGroup = jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING);
+        GroupLayout.SequentialGroup sg1 = jPanel1Layout.createSequentialGroup()
+                .addContainerGap();
+        GroupLayout.SequentialGroup sg2 = jPanel1Layout.createSequentialGroup()
+                .addContainerGap();
+        String[] matrices = ALL_MATRICES;
+        cbMatrices = new ArrayList<JCheckBox>(matrices.length);
+        int i = 0;
+        for (String matrix : matrices) {
+            JCheckBox cbMatrix = new JCheckBox();
+            cbMatrix.setText(matrix);
+            cbMatrix.setSelected(true);
+            cbMatrix.addActionListener(new java.awt.event.ActionListener() {
+                public void actionPerformed(java.awt.event.ActionEvent evt) {
+                    onChangeOptions(evt);
+                }
+            });
+            cbMatrices.add(cbMatrix);
+        
+            if (i < matrices.length/2) {
+                pg1.addComponent(cbMatrix);
+            sg1.addComponent(cbMatrix)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED);
+        }
+            else {
+                pg2.addComponent(cbMatrix);
+            sg2.addComponent(cbMatrix)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED);
+            }
+            i++;
+        }
+        
+        horizontalGroup.addGroup(pg1);
+        horizontalGroup.addGroup(pg2);
+        verticalGroup.addGroup(sg1);
+        verticalGroup.addGroup(sg2);
+        subMatricesPanel.setLayout(jPanel1Layout);
+        jPanel1Layout.setHorizontalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(jPanel1Layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(horizontalGroup)
+                .addContainerGap())
+        );
+        jPanel1Layout.setVerticalGroup(
+            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(verticalGroup)
+        );
+
+        lblNumModels.setText(String.valueOf(calculateNumberOfModels()));
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        subMatPanel = new javax.swing.JPanel();
+        subMatricesPanel = new javax.swing.JPanel();
+        distributionsPanel = new javax.swing.JPanel();
+        rateVarPanel = new javax.swing.JPanel();
+        lblNCat = new javax.swing.JLabel();
+        cbDistGroupCat = new javax.swing.JCheckBox();
+        cbDistInvariant = new javax.swing.JCheckBox();
+        txtNCat = new javax.swing.JTextField();
+        cbDistInvGC = new javax.swing.JCheckBox();
+        msgValidate = new javax.swing.JLabel();
+        empiricalFPanel = new javax.swing.JPanel();
+        cbEmpiricalF = new javax.swing.JCheckBox();
+        lblNumModelsLabel = new javax.swing.JLabel();
+        lblNumModels = new javax.swing.JLabel();
+        btnCompute = new javax.swing.JButton();
+        processorsPanel = new javax.swing.JPanel();
+        sliderProcessors = new javax.swing.JSlider();
+        lblNumProc = new javax.swing.JLabel();
+        btnSetDefault = new javax.swing.JButton();
+        btnCancel = new javax.swing.JButton();
+        startingTopologiesPanel = new javax.swing.JPanel();
+        lblStrategyMode = new javax.swing.JLabel();
+        cmbStrategyMode = new javax.swing.JComboBox();
+        lblUserTree = new javax.swing.JLabel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance().getContext().getResourceMap(OptionsView.class);
+        setTitle(resourceMap.getString("Form.title")); // NOI18N
+        setName("Form"); // NOI18N
+        addWindowListener(new java.awt.event.WindowAdapter() {
+            public void windowClosed(java.awt.event.WindowEvent evt) {
+                onClose(evt);
+            }
+        });
+
+        subMatPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, resourceMap.getString("subMatPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, XProtTestApp.FONT_PANEL_TITLE, resourceMap.getColor("subMatPanel.border.titleColor"))); // NOI18N
+        subMatPanel.setName("subMatPanel"); // NOI18N
+
+        subMatricesPanel.setToolTipText(resourceMap.getString("subMatricesPanel.toolTipText")); // NOI18N
+        subMatricesPanel.setName("subMatricesPanel"); // NOI18N
+
+        javax.swing.GroupLayout subMatricesPanelLayout = new javax.swing.GroupLayout(subMatricesPanel);
+        subMatricesPanel.setLayout(subMatricesPanelLayout);
+        subMatricesPanelLayout.setHorizontalGroup(
+            subMatricesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 172, Short.MAX_VALUE)
+        );
+        subMatricesPanelLayout.setVerticalGroup(
+            subMatricesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 283, Short.MAX_VALUE)
+        );
+
+        javax.swing.GroupLayout subMatPanelLayout = new javax.swing.GroupLayout(subMatPanel);
+        subMatPanel.setLayout(subMatPanelLayout);
+        subMatPanelLayout.setHorizontalGroup(
+            subMatPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(subMatPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(subMatricesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+        subMatPanelLayout.setVerticalGroup(
+            subMatPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(subMatPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(subMatricesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+
+        distributionsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, resourceMap.getString("distributionsPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, XProtTestApp.FONT_LABEL, resourceMap.getColor("distributionsPanel.border.titleColor"))); // NOI18N
+        distributionsPanel.setName("distributionsPanel"); // NOI18N
+
+        rateVarPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, resourceMap.getString("rateVarPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, XProtTestApp.FONT_PANEL_TITLE, resourceMap.getColor("rateVarPanel.border.titleColor"))); // NOI18N
+        rateVarPanel.setName("rateVarPanel"); // NOI18N
+
+        lblNCat.setFont(lblNCat.getFont());
+        lblNCat.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        lblNCat.setText(resourceMap.getString("lblNCat.text")); // NOI18N
+        lblNCat.setName("lblNCat"); // NOI18N
+
+        cbDistGroupCat.setFont(cbDistGroupCat.getFont());
+        cbDistGroupCat.setSelected(true);
+        cbDistGroupCat.setText(resourceMap.getString("cbDistGroupCat.text")); // NOI18N
+        cbDistGroupCat.setToolTipText(resourceMap.getString("cbDistGroupCat.toolTipText")); // NOI18N
+        cbDistGroupCat.setName("cbDistGroupCat"); // NOI18N
+        cbDistGroupCat.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                onChangeOptions(evt);
+            }
+        });
+
+        cbDistInvariant.setFont(cbDistInvariant.getFont());
+        cbDistInvariant.setSelected(true);
+        cbDistInvariant.setText(resourceMap.getString("cbDistInvariant.text")); // NOI18N
+        cbDistInvariant.setToolTipText(resourceMap.getString("cbDistInvariant.toolTipText")); // NOI18N
+        cbDistInvariant.setName("cbDistInvariant"); // NOI18N
+        cbDistInvariant.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                onChangeOptions(evt);
+            }
+        });
+
+        txtNCat.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
+        txtNCat.setText(String.valueOf(DEFAULT_NCAT));
+        java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("es/uvigo/darwin/xprottest/compute/resources/OptionsView"); // NOI18N
+        txtNCat.setToolTipText(bundle.getString("txtNCat.toolTip")); // NOI18N
+        txtNCat.setName("txtNCat"); // NOI18N
+
+        cbDistInvGC.setFont(cbDistInvGC.getFont());
+        cbDistInvGC.setSelected(true);
+        cbDistInvGC.setText(resourceMap.getString("cbDistInvGC.text")); // NOI18N
+        cbDistInvGC.setName("cbDistInvGC"); // NOI18N
+        cbDistInvGC.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                onChangeOptions(evt);
+            }
+        });
+
+        msgValidate.setFont(XProtTestApp.FONT_OPTION_LABEL);
+        msgValidate.setForeground(XProtTestView.CRITIC_COLOR);
+        msgValidate.setText(resourceMap.getString("msgValidate.text")); // NOI18N
+        msgValidate.setName("msgValidate"); // NOI18N
+
+        javax.swing.GroupLayout rateVarPanelLayout = new javax.swing.GroupLayout(rateVarPanel);
+        rateVarPanel.setLayout(rateVarPanelLayout);
+        rateVarPanelLayout.setHorizontalGroup(
+            rateVarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(rateVarPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(cbDistInvariant)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(cbDistGroupCat)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(cbDistInvGC)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(lblNCat)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(txtNCat, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addContainerGap())
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, rateVarPanelLayout.createSequentialGroup()
+                .addContainerGap(94, Short.MAX_VALUE)
+                .addComponent(msgValidate)
+                .addContainerGap())
+        );
+        rateVarPanelLayout.setVerticalGroup(
+            rateVarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(rateVarPanelLayout.createSequentialGroup()
+                .addComponent(msgValidate)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(rateVarPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(cbDistInvariant)
+                    .addComponent(cbDistGroupCat)
+                    .addComponent(cbDistInvGC)
+                    .addComponent(txtNCat, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(lblNCat))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        empiricalFPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, resourceMap.getString("empiricalFPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, XProtTestApp.FONT_PANEL_TITLE, resourceMap.getColor("empiricalFPanel.border.titleColor"))); // NOI18N
+        empiricalFPanel.setName("empiricalFPanel"); // NOI18N
+
+        cbEmpiricalF.setFont(cbEmpiricalF.getFont());
+        cbEmpiricalF.setSelected(true);
+        cbEmpiricalF.setText(bundle.getString("cbEmpiricalF.text")); // NOI18N
+        cbEmpiricalF.setToolTipText(resourceMap.getString("cbEmpiricalF.toolTipText")); // NOI18N
+        cbEmpiricalF.setName("cbEmpiricalF"); // NOI18N
+        cbEmpiricalF.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                onChangeOptions(evt);
+            }
+        });
+
+        javax.swing.GroupLayout empiricalFPanelLayout = new javax.swing.GroupLayout(empiricalFPanel);
+        empiricalFPanel.setLayout(empiricalFPanelLayout);
+        empiricalFPanelLayout.setHorizontalGroup(
+            empiricalFPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(empiricalFPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(cbEmpiricalF)
+                .addContainerGap(223, Short.MAX_VALUE))
+        );
+        empiricalFPanelLayout.setVerticalGroup(
+            empiricalFPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(empiricalFPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(cbEmpiricalF)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        lblNumModelsLabel.setFont(XProtTestApp.FONT_OPTION_LABEL);
+        lblNumModelsLabel.setForeground(resourceMap.getColor("lblNumModelsLabel.foreground")); // NOI18N
+        lblNumModelsLabel.setText(resourceMap.getString("lblNumModelsLabel.text")); // NOI18N
+        lblNumModelsLabel.setName("lblNumModelsLabel"); // NOI18N
+
+        lblNumModels.setFont(XProtTestApp.FONT_OPTION_LABEL);
+        lblNumModels.setForeground(resourceMap.getColor("lblNumModelsLabel.foreground")); // NOI18N
+        lblNumModels.setName("lblNumModels"); // NOI18N
+
+        javax.swing.GroupLayout distributionsPanelLayout = new javax.swing.GroupLayout(distributionsPanel);
+        distributionsPanel.setLayout(distributionsPanelLayout);
+        distributionsPanelLayout.setHorizontalGroup(
+            distributionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, distributionsPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(distributionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addComponent(rateVarPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addComponent(empiricalFPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addGroup(distributionsPanelLayout.createSequentialGroup()
+                        .addComponent(lblNumModelsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 248, Short.MAX_VALUE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                        .addComponent(lblNumModels, javax.swing.GroupLayout.PREFERRED_SIZE, 69, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                .addContainerGap())
+        );
+        distributionsPanelLayout.setVerticalGroup(
+            distributionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(distributionsPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(rateVarPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(empiricalFPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(distributionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(lblNumModels, javax.swing.GroupLayout.PREFERRED_SIZE, 13, javax.swing.GroupLayout.PREFERRED_SIZE)
+                    .addComponent(lblNumModelsLabel))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance().getContext().getActionMap(OptionsView.class, this);
+        btnCompute.setAction(actionMap.get("computeLikelihood")); // NOI18N
+        btnCompute.setText(resourceMap.getString("btnCompute.text")); // NOI18N
+        btnCompute.setName("btnCompute"); // NOI18N
+
+        processorsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, resourceMap.getString("processorsPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, XProtTestApp.FONT_PANEL_TITLE, resourceMap.getColor("processorsPanel.border.titleColor"))); // NOI18N
+        processorsPanel.setName("processorsPanel"); // NOI18N
+
+        sliderProcessors.setMinimum(1);
+        sliderProcessors.setMaximum(
+            Runtime.getRuntime().availableProcessors()
+        );
+        sliderProcessors.setValue(
+            mainFrame.getFacade().getNumberOfThreads()
+        );
+        sliderProcessors.setPaintLabels(true);
+        sliderProcessors.setPaintTicks(true);
+        sliderProcessors.setSnapToTicks(true);
+        sliderProcessors.setToolTipText(resourceMap.getString("sliderProcessors.toolTipText")); // NOI18N
+        sliderProcessors.setName("sliderProcessors"); // NOI18N
+        sliderProcessors.addChangeListener(new javax.swing.event.ChangeListener() {
+            public void stateChanged(javax.swing.event.ChangeEvent evt) {
+                sliderProcessorsStateChanged(evt);
+            }
+        });
+
+        lblNumProc.setFont(lblNumProc.getFont());
+        lblNumProc.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
+        lblNumProc.setText(String.valueOf(sliderProcessors.getValue()));
+        lblNumProc.setName("lblNumProc"); // NOI18N
+
+        javax.swing.GroupLayout processorsPanelLayout = new javax.swing.GroupLayout(processorsPanel);
+        processorsPanel.setLayout(processorsPanelLayout);
+        processorsPanelLayout.setHorizontalGroup(
+            processorsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(processorsPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(lblNumProc)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(sliderProcessors, javax.swing.GroupLayout.DEFAULT_SIZE, 442, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+        processorsPanelLayout.setVerticalGroup(
+            processorsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(processorsPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(processorsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(sliderProcessors, javax.swing.GroupLayout.DEFAULT_SIZE, 47, Short.MAX_VALUE)
+                    .addComponent(lblNumProc))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        btnSetDefault.setAction(actionMap.get("restoreDefault")); // NOI18N
+        btnSetDefault.setText(resourceMap.getString("btnSetDefault.text")); // NOI18N
+        btnSetDefault.setToolTipText(resourceMap.getString("btnSetDefault.toolTipText")); // NOI18N
+        btnSetDefault.setName("btnSetDefault"); // NOI18N
+
+        btnCancel.setAction(actionMap.get("close")); // NOI18N
+        btnCancel.setText(resourceMap.getString("btnCancel.text")); // NOI18N
+        btnCancel.setToolTipText(resourceMap.getString("btnCancel.toolTipText")); // NOI18N
+        btnCancel.setName("btnCancel"); // NOI18N
+
+        startingTopologiesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(null, resourceMap.getString("startingTopologiesPanel.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, XProtTestApp.FONT_PANEL_TITLE, resourceMap.getColor("startingTopologiesPanel.border.titleColor"))); // NOI18N
+        startingTopologiesPanel.setName("startingTopologiesPanel"); // NOI18N
+
+        lblStrategyMode.setFont(lblStrategyMode.getFont());
+        lblStrategyMode.setText(bundle.getString("lbl-strategy-mode")); // NOI18N
+        lblStrategyMode.setName("lblStrategyMode"); // NOI18N
+
+        cmbStrategyMode.setAction(actionMap.get("setStrategyMode")); // NOI18N
+        cmbStrategyMode.setName("cmbStrategyMode"); // NOI18N
+
+        lblUserTree.setFont(XProtTestApp.FONT_OPTION_LABEL);
+        lblUserTree.setForeground(resourceMap.getColor("lblUserTree.foreground")); // NOI18N
+        lblUserTree.setText(bundle.getString("msg-no-user-tree-loaded")); // NOI18N
+        lblUserTree.setName("lblUserTree"); // NOI18N
+
+        javax.swing.GroupLayout startingTopologiesPanelLayout = new javax.swing.GroupLayout(startingTopologiesPanel);
+        startingTopologiesPanel.setLayout(startingTopologiesPanelLayout);
+        startingTopologiesPanelLayout.setHorizontalGroup(
+            startingTopologiesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(startingTopologiesPanelLayout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(startingTopologiesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(cmbStrategyMode, 0, 329, Short.MAX_VALUE)
+                    .addComponent(lblStrategyMode, javax.swing.GroupLayout.DEFAULT_SIZE, 329, Short.MAX_VALUE)
+                    .addComponent(lblUserTree, javax.swing.GroupLayout.DEFAULT_SIZE, 329, Short.MAX_VALUE))
+                .addContainerGap())
+        );
+        startingTopologiesPanelLayout.setVerticalGroup(
+            startingTopologiesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(startingTopologiesPanelLayout.createSequentialGroup()
+                .addComponent(lblStrategyMode)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(cmbStrategyMode, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(lblUserTree)
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        for (int optimizeValue : OPTIMIZE_VALUES) {
+            OptimizationStrategyWrapper optimizeItem = new OptimizationStrategyWrapper(OPTIMIZE_NAMES[optimizeValue], optimizeValue);
+            cmbStrategyMode.addItem(optimizeItem);
+        }
+        cmbStrategyMode.setSelectedIndex(DEFAULT_STRATEGY_MODE);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                    .addComponent(processorsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                    .addGroup(layout.createSequentialGroup()
+                        .addComponent(subMatPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+                            .addComponent(distributionsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+                            .addComponent(startingTopologiesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                        .addComponent(btnCompute)
+                        .addGap(18, 18, 18)
+                        .addComponent(btnSetDefault)
+                        .addGap(18, 18, 18)
+                        .addComponent(btnCancel)))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addComponent(processorsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+                    .addGroup(layout.createSequentialGroup()
+                        .addComponent(distributionsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(startingTopologiesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+                    .addComponent(subMatPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(btnCancel)
+                    .addComponent(btnSetDefault)
+                    .addComponent(btnCompute))
+                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void onClose(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_onClose
+        mainFrame.unloadOptionsView(running);
+    }//GEN-LAST:event_onClose
+
+    private void onChangeOptions(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onChangeOptions
+        
+        lblNumModels.setText(String.valueOf(calculateNumberOfModels()));
+        txtNCat.setEnabled(cbDistGroupCat.isSelected() || cbDistInvGC.isSelected());
+    }//GEN-LAST:event_onChangeOptions
+
+    private void sliderProcessorsStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sliderProcessorsStateChanged
+        lblNumProc.setText(String.valueOf(sliderProcessors.getValue()));
+    }//GEN-LAST:event_sliderProcessorsStateChanged
+    
+    private int calculateNumberOfModels() {
+        int numberOfModels = 0;
+        for (JCheckBox cbMatrix : cbMatrices ) {
+            if (cbMatrix.isSelected())
+                numberOfModels++;
+        }
+        int numberOfMatrices = numberOfModels;
+        if (cbDistInvariant.isSelected())
+            numberOfModels += numberOfMatrices;
+        if (cbDistGroupCat.isSelected())
+            numberOfModels += numberOfMatrices;
+        if (cbDistInvGC.isSelected())
+            numberOfModels += numberOfMatrices;
+        if (cbEmpiricalF.isSelected())
+            numberOfModels *= 2;
+        return numberOfModels;
+    }
+
+    @Action
+    public void computeLikelihood() {
+        boolean validate = true;
+        msgValidate.setVisible(false);
+        Collection<String> matrices = new ArrayList<String>();
+        Collection<String> distributions = new ArrayList<String>();
+        int ncat = 0;
+        boolean plusF;
+        int strategyMode;
+        for (JCheckBox cbMatrix : cbMatrices)
+            if (cbMatrix.isSelected()) {
+                matrices.add(cbMatrix.getText());
+            }
+        distributions.add("Uniform");
+        if (cbDistGroupCat.isSelected())
+            distributions.add("+G");
+        if (cbDistInvariant.isSelected())
+            distributions.add("+I");
+        if (cbDistInvGC.isSelected())
+            distributions.add("+I+G");
+        if (cbDistGroupCat.isSelected() || cbDistInvGC.isSelected()) {
+            try {
+                ncat = Integer.parseInt(txtNCat.getText());
+                if (ncat <= 0) {
+                    msgValidate.setVisible(true);
+                    validate = false;
+                }
+            } catch (NumberFormatException e) {
+                msgValidate.setVisible(true);
+                validate = false;
+            }
+        }
+        plusF = cbEmpiricalF.isSelected();
+        strategyMode = cmbStrategyMode.getSelectedIndex();
+        if (validate) {
+            try {
+                mainFrame.getFacade().setNumberOfThreads(sliderProcessors.getValue());
+                ProtTestParameterVO parameters = new ProtTestParameterVO(
+                        alignmentFilePath, alignment, treeFilePath, matrices, distributions, plusF, ncat,
+                        strategyMode);
+                ApplicationOptions options = mainFrame.getFacade().configure(parameters);
+                mainFrame.computeLikelihood(calculateNumberOfModels(), options);
+                running = true;
+            } catch (IOException e) {
+                mainFrame.getDisplayWriter().println(e.getMessage());
+            } catch (AlignmentParseException e) {
+                mainFrame.getDisplayWriter().println(e.getMessage());
+            } catch (ProtTestInternalException e) {
+                mainFrame.getDisplayWriter().println(e.getMessage());
+            }
+            this.dispose();
+        }
+    }
+
+    @Action
+    public void setStrategyMode() {
+        org.jdesktop.application.ResourceMap resourceMap 
+                    = org.jdesktop.application.Application.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class)
+                    .getContext().getResourceMap(OptionsView.class);
+        File f = null;
+        if (((OptimizationStrategyWrapper)cmbStrategyMode.getSelectedItem()).getValue()
+                == OPTIMIZE_USER) {
+            
+            FileDialog fc = new FileDialog(this, "Load DNA alignment", FileDialog.LOAD);
+	fc.setDirectory(System.getProperty("user.dir"));
+	fc.setVisible(true);
+		
+	String dataFileName = fc.getFile();
+        
+//            JFileChooser fc = XProtTestApp.createFileChooser(resourceMap.getString(
+//            "loadTree.dialogTitle"));
+//            int option = fc.showOpenDialog(this);
+//
+//            if (JFileChooser.APPROVE_OPTION == option) {
+        if (dataFileName != null) {
+                try {
+                    f = new File(fc.getDirectory() + dataFileName);
+
+                    Tree tree = mainFrame.getFacade().readTree(
+                            mainFrame.getDisplayWriter(), f.getAbsolutePath(), true);
+                    this.treeFilePath = f.getAbsolutePath();
+                    
+                    // check tree consistency
+                    boolean consistent = true;
+                    if (alignment.getIdCount() == tree.getIdCount()) {
+                        for (int id = 0; id < alignment.getIdCount(); id++) {
+                            Identifier identifier = alignment.getIdentifier(id);
+                            if (tree.whichIdNumber(identifier.getName()) == -1) {
+                                consistent = false;
+                                break;
+                            }
+                        }
+                    } else
+                        consistent = false;
+                    if (consistent)
+                        setUserTree(tree);
+                    else {
+                        mainFrame.getDisplayWriter().println("User topology is not consistent with current alignment");
+                        setUserTree(null);
+                        cmbStrategyMode.setSelectedIndex(0);
+                    }
+                } catch (TreeFormatException ex) {
+                    mainFrame.getDisplayWriter().println(ex.getMessage());
+                    setUserTree(null);
+                    cmbStrategyMode.setSelectedIndex(0);
+                } catch (FileNotFoundException ex) {
+                    mainFrame.getDisplayWriter().println(ex.getMessage());
+                    setUserTree(null);
+                    cmbStrategyMode.setSelectedIndex(0);
+                } catch (IOException ex) {
+                    mainFrame.getDisplayWriter().println(ex.getMessage());
+                    setUserTree(null);
+                    cmbStrategyMode.setSelectedIndex(0);
+                }
+                mainFrame.getDisplayWriter().println("");
+                mainFrame.getFrame().toFront();
+                mainFrame.getFrame().transferFocus();
+            }
+            
+        } else {
+            
+            if (userTree != null)
+                setUserTree(null);
+            
+        }
+    }
+    
+    private void setUserTree(Tree tree) {
+        this.userTree = tree;
+        org.jdesktop.application.ResourceMap resourceMap 
+                    = org.jdesktop.application.Application.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class)
+                    .getContext().getResourceMap(OptionsView.class);
+        if (tree == null) {
+            lblUserTree.setText(resourceMap.getString("msg-no-user-tree-loaded"));
+            lblUserTree.setForeground(Color.GRAY);
+            this.treeFilePath = null;
+        }
+        else {
+            lblUserTree.setText(resourceMap.getString("msg-user-tree-loaded"));
+            lblUserTree.setForeground(XProtTestView.DONE_COLOR);
+        }
+    }
+
+    @Action
+    public void restoreDefault() {
+        for (JCheckBox matrix : cbMatrices) {
+            matrix.setSelected(true);
+        }
+        cbDistGroupCat.setSelected(true);
+        cbDistInvGC.setSelected(true);
+        cbDistInvariant.setSelected(true);
+        cbEmpiricalF.setSelected(true);
+        txtNCat.setText(String.valueOf(DEFAULT_NCAT));
+        sliderProcessors.setValue(sliderProcessors.getMaximum());
+        cmbStrategyMode.setSelectedIndex(DEFAULT_STRATEGY_MODE);
+        onChangeOptions(null);
+        sliderProcessorsStateChanged(null);
+        setUserTree(null);
+    }
+
+    @Action
+    public void close() {
+        this.dispose();
+    }
+    
+    
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton btnCancel;
+    private javax.swing.JButton btnCompute;
+    private javax.swing.JButton btnSetDefault;
+    private javax.swing.JCheckBox cbDistGroupCat;
+    private javax.swing.JCheckBox cbDistInvGC;
+    private javax.swing.JCheckBox cbDistInvariant;
+    private javax.swing.JCheckBox cbEmpiricalF;
+    private javax.swing.JComboBox cmbStrategyMode;
+    private javax.swing.JPanel distributionsPanel;
+    private javax.swing.JPanel empiricalFPanel;
+    private javax.swing.JLabel lblNCat;
+    private javax.swing.JLabel lblNumModels;
+    private javax.swing.JLabel lblNumModelsLabel;
+    private javax.swing.JLabel lblNumProc;
+    private javax.swing.JLabel lblStrategyMode;
+    private javax.swing.JLabel lblUserTree;
+    private javax.swing.JLabel msgValidate;
+    private javax.swing.JPanel processorsPanel;
+    private javax.swing.JPanel rateVarPanel;
+    private javax.swing.JSlider sliderProcessors;
+    private javax.swing.JPanel startingTopologiesPanel;
+    private javax.swing.JPanel subMatPanel;
+    private javax.swing.JPanel subMatricesPanel;
+    private javax.swing.JTextField txtNCat;
+    // End of variables declaration//GEN-END:variables
+    
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/compute/RunningFrame.java b/src/main/java/es/uvigo/darwin/xprottest/compute/RunningFrame.java
new file mode 100755
index 0000000..46661f7
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/compute/RunningFrame.java
@@ -0,0 +1,261 @@
+/*
+ * RunningFrame.java
+ *
+ * Created on 1 de octubre de 2009, 19:43
+ */
+package es.uvigo.darwin.xprottest.compute;
+
+import es.uvigo.darwin.prottest.exe.ExternalExecutionManager;
+import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
+import es.uvigo.darwin.xprottest.*;
+import org.jdesktop.application.Action;
+import org.jdesktop.application.Task;
+import es.uvigo.darwin.xprottest.util.TextAreaAppender;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.observer.ModelUpdaterObserver;
+import es.uvigo.darwin.prottest.observer.ObservableModelUpdater;
+import es.uvigo.darwin.prottest.util.Utilities;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import javax.swing.Timer;
+
+/**
+ *
+ * @author  diego
+ */
+public class RunningFrame extends javax.swing.JFrame
+        implements ModelUpdaterObserver {
+
+    private static final int TIMER_UPDATE_FREQUENCY = 1000;
+    private XProtTestView mainFrame;
+    private Task task;
+    private int computedModels;
+    private int numModels;
+    private PrintWriter displayWriter;
+    /** Timer for calculate the elapsed time **/
+    private Calendar startTime;
+    /** Timer for display the elapsed time **/
+    Timer timer;
+    private HashMap<String, Long> partialTimestamps;
+    private ArrayList<String> runningModels;
+    // var used to discard concurrent messages during
+    // proccess cancel
+    private boolean running;
+
+    /** Creates new form RunningFrame */
+    public RunningFrame(XProtTestView mainFrame, int numModels) {
+        initComponents();
+        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
+
+        this.startTime = Calendar.getInstance();
+        this.mainFrame = mainFrame;
+        this.numModels = numModels;
+        this.displayWriter = new PrintWriter(new TextAreaAppender(computedTextArea));
+        this.running = true;
+        this.partialTimestamps = new HashMap<String, Long>();
+        this.runningModels = new ArrayList<String>();
+
+        lblNumModels.setText(String.valueOf(numModels));
+        lblExecutedModels.setText(String.valueOf(computedModels));
+        runningProgress.setMaximum(numModels);
+        runningProgress.setMinimum(0);
+        runningProgress.setValue(computedModels);
+
+        timer = new Timer(TIMER_UPDATE_FREQUENCY, new ActionListener() {
+
+            public void actionPerformed(ActionEvent e) {
+                lblElapsedTime.setText(Utilities.calculateRuntime(
+                        startTime.getTimeInMillis(),
+                        Calendar.getInstance().getTimeInMillis()));
+                updateHeader();
+            }
+        });
+
+        timer.start();
+    }
+
+    public void setTask(Task task) {
+        this.task = task;
+    }
+
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        lblRunning = new javax.swing.JLabel();
+        runningProgress = new javax.swing.JProgressBar();
+        cancelButton = new javax.swing.JButton();
+        lblNumModels = new javax.swing.JLabel();
+        lblExecutedModels = new javax.swing.JLabel();
+        lblSeparator = new javax.swing.JLabel();
+        computedScrollArea = new javax.swing.JScrollPane();
+        computedTextArea = new javax.swing.JTextArea();
+        lblElapsedTime = new javax.swing.JLabel();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
+        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance().getContext().getResourceMap(RunningFrame.class);
+        setTitle(resourceMap.getString("Form.title")); // NOI18N
+        setName("Form"); // NOI18N
+
+        lblRunning.setText(resourceMap.getString("lblRunning.text")); // NOI18N
+        lblRunning.setName("lblRunning"); // NOI18N
+
+        runningProgress.setName("runningProgress"); // NOI18N
+
+        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance().getContext().getActionMap(RunningFrame.class, this);
+        cancelButton.setAction(actionMap.get("cancelExecution")); // NOI18N
+        cancelButton.setText(resourceMap.getString("cancelButton.text")); // NOI18N
+        cancelButton.setName("cancelButton"); // NOI18N
+
+        lblNumModels.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
+        lblNumModels.setText(resourceMap.getString("lblNumModels.text")); // NOI18N
+        lblNumModels.setName("lblNumModels"); // NOI18N
+
+        lblExecutedModels.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+        lblExecutedModels.setText(resourceMap.getString("lblExecutedModels.text")); // NOI18N
+        lblExecutedModels.setName("lblExecutedModels"); // NOI18N
+
+        lblSeparator.setText(resourceMap.getString("lblSeparator.text")); // NOI18N
+        lblSeparator.setName("lblSeparator"); // NOI18N
+
+        computedScrollArea.setName("computedScrollArea"); // NOI18N
+
+        computedTextArea.setBackground(resourceMap.getColor("computedTextArea.background")); // NOI18N
+        computedTextArea.setColumns(20);
+        computedTextArea.setEditable(false);
+        computedTextArea.setRows(15);
+        computedTextArea.setName("computedTextArea"); // NOI18N
+        computedScrollArea.setViewportView(computedTextArea);
+
+        lblElapsedTime.setText(resourceMap.getString("lblElapsedTime.text")); // NOI18N
+        lblElapsedTime.setName("lblElapsedTime"); // NOI18N
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+                .addContainerGap()
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+                    .addComponent(computedScrollArea, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 329, Short.MAX_VALUE)
+                    .addComponent(runningProgress, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 329, Short.MAX_VALUE)
+                    .addComponent(lblRunning, javax.swing.GroupLayout.Alignment.LEADING)
+                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
+                        .addComponent(cancelButton)
+                        .addGap(18, 18, 18)
+                        .addComponent(lblElapsedTime)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 135, Short.MAX_VALUE)
+                        .addComponent(lblExecutedModels)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(lblSeparator)
+                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(lblNumModels, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)))
+                .addContainerGap())
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGroup(layout.createSequentialGroup()
+                .addContainerGap()
+                .addComponent(lblRunning)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addComponent(runningProgress, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+                    .addComponent(cancelButton)
+                    .addComponent(lblNumModels)
+                    .addComponent(lblSeparator)
+                    .addComponent(lblExecutedModels)
+                    .addComponent(lblElapsedTime))
+                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+                .addComponent(computedScrollArea, javax.swing.GroupLayout.DEFAULT_SIZE, 315, Short.MAX_VALUE)
+                .addContainerGap())
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    @Action
+    public void cancelExecution() {
+        ExternalExecutionManager.getInstance().killProcesses();
+        task.cancel(true);
+        unload();
+    }
+
+    public void finishedExecution() {
+        unload();
+    }
+
+    private void unload() {
+        mainFrame.unloadRunningView(this);
+    }
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JButton cancelButton;
+    private javax.swing.JScrollPane computedScrollArea;
+    private javax.swing.JTextArea computedTextArea;
+    private javax.swing.JLabel lblElapsedTime;
+    private javax.swing.JLabel lblExecutedModels;
+    private javax.swing.JLabel lblNumModels;
+    private javax.swing.JLabel lblRunning;
+    private javax.swing.JLabel lblSeparator;
+    private javax.swing.JProgressBar runningProgress;
+    // End of variables declaration//GEN-END:variables
+
+    public void updateHeader() {
+        StringBuffer models = new StringBuffer();
+        Iterator it = runningModels.iterator();
+        while (it.hasNext()) {
+            models.append(it.next());
+            if (it.hasNext()) {
+                models.append(", ");
+            }
+        }
+        lblRunning.setText("Computing: " + models);
+    }
+
+    public void update(ObservableModelUpdater o, Model model, ApplicationOptions options) {
+        if (running) {
+            if (options == null) {
+//                displayWriter.println("Computing " + model.getModelName() + "...");
+                runningModels.add(model.getModelName());
+                partialTimestamps.put(model.getModelName(), Calendar.getInstance().getTimeInMillis());
+            } else {
+                computedModels++;
+                runningProgress.setValue(computedModels);
+                lblExecutedModels.setText(String.valueOf(computedModels));
+                runningModels.remove(model.getModelName());
+                if (model.isComputed()) {
+                    StringBuffer partialTime = new StringBuffer("");
+                    displayWriter.println("Computed " + model.getModelName() + "(" + model.getLk() + ")");
+                    long currentTimestamp = Calendar.getInstance().getTimeInMillis();
+                    long partialTimestamp = partialTimestamps.get(model.getModelName());
+                    displayWriter.println("    " + Utilities.calculateRuntime(partialTimestamp, currentTimestamp) +
+                            "     Elapsed time: " + Utilities.calculateRuntime(startTime.getTimeInMillis(), currentTimestamp));
+                } else {
+//                    if (options != null) {
+                    // Follow error behavior
+                    if (mainFrame.getErrorBehavior() == XProtTestApp.ERROR_BEHAVIOR_CONTINUE) {
+                        displayWriter.println("There were errors computing " + model.getModelName());
+                    } else if (mainFrame.getErrorBehavior() == XProtTestApp.ERROR_BEHAVIOR_STOP) {
+                        running = false;
+                        mainFrame.computationInterrupted();
+                        cancelExecution();
+                    } else {
+                        running = false;
+                        cancelExecution();
+                        throw new RuntimeException("Unsupported error behavior : " + mainFrame.getErrorBehavior());
+                    }
+//                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/compute/resources/OptionsView.properties b/src/main/java/es/uvigo/darwin/xprottest/compute/resources/OptionsView.properties
new file mode 100755
index 0000000..36c1b89
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/compute/resources/OptionsView.properties
@@ -0,0 +1,62 @@
+# display
+
+distributionsPanel.border.titleColor=102, 102, 153
+empiricalFPanel.border.titleColor=102, 102, 153
+lblNumModelsLabel.foreground=128, 128, 128
+lblUserTree.foreground=128, 128, 128
+processorsPanel.border.titleColor=102, 102, 153
+rateVarPanel.border.titleColor=102, 102, 153
+startingTopologiesPanel.border.titleColor=102, 102, 153
+subMatPanel.border.titleColor=102, 102, 153
+
+# messages
+
+msg-user-tree-loaded=Loaded user topology
+msg-no-user-tree-loaded=No user topology loaded
+
+# labels
+
+Form.title=XProtTest HPC Lk Computation Options
+distributionsPanel.border.title=Distributions
+empiricalFPanel.border.title=Amino-acid frequencies
+processorsPanel.border.title=Number of processors requested
+rateVarPanel.border.title=Rate variation
+startingTopologiesPanel.border.title=Starting topology
+subMatPanel.border.title=Substitution model matrices
+
+btnCancel.text=Cancel
+btnCompute.text=Compute
+btnSetDefault.text=Restore
+cbDistInvariant.text=+I
+cbDistInvGC.text=+I+G
+cbDistGroupCat.text=+G
+cbEmpiricalF.text=Empirical
+close.Action.text=Close
+lblNCat.text=Categories
+lblNumModelsLabel.text=Total number of models
+lbl-amino-acid-frequencies=Amino-acid Frequencies
+lbl-base-frequencies=Base Frequencies
+lbl-strategy-mode=Base tree for likelihood calculations:
+loadTree.dialogTitle=Load User Topology
+msgValidate.text=Invalid number of rate categories
+number-of-processors=Number of processors
+restoreDefault.Action.text=Restore default values
+
+# tooltip texts
+
+btnCancel.toolTipText=Cancel
+btnSetDefault.toolTipText=Restore default settings
+cbDistInvariant.toolTipText=Consider a proportion of invariable sites
+cbDistGroupCat.toolTipText=Consider rate variation among sites with a number of rate categories
+cbEmpiricalF.toolTipText=Use empirical frequencies distribution
+cmbStrategyMode.toolTipText=Select strategy mode to compute likelihood scores
+sliderProcessors.toolTipText=Select the number of processors to compute
+subMatricesPanel.toolTipText=Select substitution model matrixes to compute
+txtNCatToolTip=Number of rate categories
+txtNCat.toolTip=Number of categories
+
+# other
+
+restoreDefault.Action.shortDescription=Restore default values
+close.Action.shortDescription=Close window
+
diff --git a/src/main/java/es/uvigo/darwin/xprottest/compute/resources/RunningFrame.properties b/src/main/java/es/uvigo/darwin/xprottest/compute/resources/RunningFrame.properties
new file mode 100755
index 0000000..b275993
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/compute/resources/RunningFrame.properties
@@ -0,0 +1,12 @@
+cancelButton.text=Cancel
+lblSeparator.text=/
+lblExecutedModels.text=000
+lblNumModels.text=000
+lblRunning.text=Running...
+cancelExecution.Action.text=Cancel
+cancelExecution.Action.accelerator=shift pressed C
+cancelExecution.Action.shortDescription=Cancel Likelihood Computation
+#NOI18N
+computedTextArea.background=238, 238, 238
+Form.title=Running status
+lblElapsedTime.text=00:00:00
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/CreditsBox.properties b/src/main/java/es/uvigo/darwin/xprottest/resources/CreditsBox.properties
new file mode 100755
index 0000000..6384dfa
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/resources/CreditsBox.properties
@@ -0,0 +1,16 @@
+title = About: ${Application.title} ${Application.version} 
+
+closeAboutBox.Action.text = &Close
+
+appDescLabel.text=<html>Selection of best-fit models of protein evolution
+
+versionLabel.text=Product Version\:
+
+homepageLabel.text=Homepage\:
+#NOI18N
+imageLabel.icon=prottestlogo.gif
+lblDisclaimer.text=Use of ProtTest's logo kindly allowed by IconBAZAAR
+#NOI18N
+lblDisclaimer.font=DejaVu Sans-Plain-10
+#NOI18N
+lblDisclaimer.foreground=106, 106, 106
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/PreferencesView.properties b/src/main/java/es/uvigo/darwin/xprottest/resources/PreferencesView.properties
new file mode 100755
index 0000000..ff1909d
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/resources/PreferencesView.properties
@@ -0,0 +1,24 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+Form.title=XProtTest Preferences
+lblErrorBehavior.text=Behavior when errors:
+Accept.Action.text=
+Accept.Action.shortDescription=
+btnCancel.text=jButton1
+Cancel.Action.text=
+Cancel.Action.shortDescription=
+lblContinue.text=Continue:
+error-continue-desc=Continue execution even with errors\nand compute partial results
+#NOI18N
+lblContinue.foreground=102, 102, 102
+error-stop-desc=Cancel execution when an error is\ndetected
+lblStop.text=Stop:
+#NOI18N
+lblStop.foreground=102, 102, 102
+#NOI18N
+txtStopDesc.foreground=102, 102, 102
+#NOI18N
+txtStopDesc.background=238, 238, 238
+#NOI18N
+txtContinueDesc.foreground=102, 102, 102
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/XProtTestAboutBox.properties b/src/main/java/es/uvigo/darwin/xprottest/resources/XProtTestAboutBox.properties
new file mode 100755
index 0000000..25aa449
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/resources/XProtTestAboutBox.properties
@@ -0,0 +1,19 @@
+title = About: ${Application.title} ${Application.version} 
+
+closeAboutBox.Action.text = &Close
+
+appDescLabel.text=<html>Selection of best-fit models of protein evolution
+
+versionLabel.text=Product Version\:
+
+homepageLabel.text=Homepage\:
+
+citationLabel.text=Citation\:
+
+#NOI18N
+imageLabel.icon=prottestlogo.gif
+lblDisclaimer.text=Use of ProtTest's logo kindly allowed by IconBAZAAR
+#NOI18N
+lblDisclaimer.font=DejaVu Sans-Plain-10
+#NOI18N
+lblDisclaimer.foreground=106, 106, 106
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/XProtTestApp.properties b/src/main/java/es/uvigo/darwin/xprottest/resources/XProtTestApp.properties
new file mode 100755
index 0000000..2503ae5
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/resources/XProtTestApp.properties
@@ -0,0 +1,38 @@
+# Application global resources
+
+Application.name = XProtTest
+Application.title = XProtTest
+Application.version = 3.3
+Application.vendor = Phylogenomics
+Application.homepage = http://code.google.com/p/prottest3
+Application.citation1 = Darriba D, Taboada GL, Doallo R, Posada D. ProtTest 3: fast selection
+Application.citation2 = of best-fit models of protein evolution. Bioinformatics, 27:1164-1165, 2011
+Application.description = A user graphical interface for ProtTest 3 for amino-acid model selection
+Application.vendorId = Darwin
+Application.id = XProtTest
+Application.lookAndFeel = system
+computeLikelihood.Action.text=Compute
+computeLikelihood.Action.shortDescription=Compute Likelihood Scores
+models-not-complete=Warning! The model set computation is not complete
+menu-edit=Edit
+menu-copy=Copy
+menu-selectAll=Select all
+menu-window=Window
+menu-close=Close
+menu-preferences=Preferences
+quit.Action.text=Exit
+quit.Action.accelerator=ctrl pressed Q
+quit.Action.shortDescription=Exit the application
+
+# --------------------
+# Default error behavior
+# 0 = Continue
+# 1 = Stop
+# --------------------
+default-error-behavior=0
+button-accept=Accept
+button-cancel=Cancel
+Form.background=238, 238, 238
+menu-manual=ProtTest Manual
+export-to-console=Export to main console
+txtNCat.defaultText=4
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/XProtTestView.properties b/src/main/java/es/uvigo/darwin/xprottest/resources/XProtTestView.properties
new file mode 100755
index 0000000..dc84b6f
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/resources/XProtTestView.properties
@@ -0,0 +1,91 @@
+
+# status bar resources
+
+StatusBar.messageTimeout = 5000
+StatusBar.busyAnimationRate = 30
+StatusBar.idleIcon = busyicons/idle-icon.png
+StatusBar.busyIcons[0]  = busyicons/busy-icon0.png
+StatusBar.busyIcons[1]  = busyicons/busy-icon1.png
+StatusBar.busyIcons[2]  = busyicons/busy-icon2.png
+StatusBar.busyIcons[3]  = busyicons/busy-icon3.png
+StatusBar.busyIcons[4]  = busyicons/busy-icon4.png
+StatusBar.busyIcons[5]  = busyicons/busy-icon5.png
+StatusBar.busyIcons[6]  = busyicons/busy-icon6.png
+StatusBar.busyIcons[7]  = busyicons/busy-icon7.png
+StatusBar.busyIcons[8]  = busyicons/busy-icon8.png
+StatusBar.busyIcons[9]  = busyicons/busy-icon9.png
+StatusBar.busyIcons[10] = busyicons/busy-icon10.png
+StatusBar.busyIcons[11] = busyicons/busy-icon11.png
+StatusBar.busyIcons[12] = busyicons/busy-icon12.png
+StatusBar.busyIcons[13] = busyicons/busy-icon13.png
+StatusBar.busyIcons[14] = busyicons/busy-icon14.png
+
+# appearance
+
+lblDataFileStatus.foreground=255, 0, 0
+lblLikelihoodStatus.foreground=255, 0, 0
+mainPanel.background=238, 238, 238
+menuFileExit.icon=${null}
+lblMoreInfo.foreground=255, 0, 0
+statusPanel.foreground=0, 0, 255
+statusPanel.border.shadowColor=89, 89, 89
+statusPanel.border.highlightColor=182, 182, 182
+statusPanel.background=220, 220, 220
+
+aa-frequencies=Observed Amino-Acid Frequencies
+msg-no-data=No data file loaded
+msg-data-loaded=Alignment:
+msg-no-tree=No tree file loaded
+msg-tree-loaded=Tree:
+msg-no-lnl-calculated=Likelihood scores not available
+msg-lnl-calculated=Likelihood scores available!
+msg-lnl-error=There was an error computing likelihood scores!
+loadAlignment.dialogTitle=Load Alignment
+
+# menu items
+
+editSelectAllMenuItem.text=Item
+errorMenuItem.text=Show error log
+item-show-frequencies=Show observed amino-acid frequencies
+item-compute-likelihood=Compute likelihood scores
+item-file=File
+item-load-alignment=Load Alignment
+item-analysis=Analysis
+item-exit=Exit
+item-results=Selection
+item-results-sub=Results
+item-edit=Edit
+item-help=Help
+item-about=About
+item-credits=Credits
+item-about-window=About...
+item-credits-window=Credits
+item-load-tree=Load Tree File
+item-print-console=Print Console
+item-save-console=Save Console
+item-show-tree=Show Trees
+averagingMenuItem.text=Phylogenetic averaging
+manualMenuItem.text=Item
+preferencesMenuItem.text=Item
+showAboutBox.Action.text = &About...
+showCreditsBox.Action.text = &Credits
+
+# tooltip texts
+
+averagingMenuItem.toolTipText=Build consensus tree
+computeMenuItem.toolTipText=Optimize the model set
+editCopyMenuItem.toolTipText=Copy selected data
+editPreferencesMenuItem.toolTipText=Set the application preferences
+editSelectAllMenuItem.toolTipText=Select all text in the main console
+errorMenuItem.toolTipText=Display error console
+resultsMenuItem.toolTipText=Show model selection results
+showAboutBox.Action.shortDescription = Show the application's information dialog
+showAboutBox.Action.shortDescription = Show the application's credits
+showFrequenciesItem.toolTipText=Show empirical amino-acid frequencies from the input alignment
+showTreeMenuItem.toolTipText=Show inferred phylogenies from each model
+
+# labels
+
+lblMoreInfo.text=Press Ctrl+Shift+E to open Error Log
+models-not-complete=The model set computation is not complete
+msg-see-error-log=Please see error log for details.
\ No newline at end of file
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/about.png b/src/main/java/es/uvigo/darwin/xprottest/resources/about.png
new file mode 100755
index 0000000..c6dfe0a
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/about.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon0.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon0.png
new file mode 100755
index 0000000..242c0c8
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon0.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon1.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon1.png
new file mode 100755
index 0000000..9f6f634
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon1.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon10.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon10.png
new file mode 100755
index 0000000..c4ef4a1
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon10.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon11.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon11.png
new file mode 100755
index 0000000..6eca1f5
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon11.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon12.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon12.png
new file mode 100755
index 0000000..e447ee8
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon12.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon13.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon13.png
new file mode 100755
index 0000000..848a6f1
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon13.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon14.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon14.png
new file mode 100755
index 0000000..7b3561d
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon14.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon2.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon2.png
new file mode 100755
index 0000000..c866e62
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon2.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon3.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon3.png
new file mode 100755
index 0000000..9be22fa
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon3.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon4.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon4.png
new file mode 100755
index 0000000..f07c20d
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon4.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon5.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon5.png
new file mode 100755
index 0000000..653fc9c
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon5.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon6.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon6.png
new file mode 100755
index 0000000..7035572
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon6.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon7.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon7.png
new file mode 100755
index 0000000..49fbc6e
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon7.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon8.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon8.png
new file mode 100755
index 0000000..e1a5a40
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon8.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon9.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon9.png
new file mode 100755
index 0000000..8278012
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/busy-icon9.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/idle-icon.png b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/idle-icon.png
new file mode 100755
index 0000000..50312f8
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/busyicons/idle-icon.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/prottestlogo.gif b/src/main/java/es/uvigo/darwin/xprottest/resources/prottestlogo.gif
new file mode 100755
index 0000000..eaaf955
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/prottestlogo.gif differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/resources/splash.png b/src/main/java/es/uvigo/darwin/xprottest/resources/splash.png
new file mode 100755
index 0000000..a1fbdc1
Binary files /dev/null and b/src/main/java/es/uvigo/darwin/xprottest/resources/splash.png differ
diff --git a/src/main/java/es/uvigo/darwin/xprottest/results/Bundle.properties b/src/main/java/es/uvigo/darwin/xprottest/results/Bundle.properties
new file mode 100755
index 0000000..1ebdc43
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/results/Bundle.properties
@@ -0,0 +1,19 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+lbl-overall-alpha=Alpha
+lbl-overall-alpha-inv=Alpha-Inv
+lbl-overall-inv-alpha=Inv-Alpha
+lbl-overall-inv=Inv
+lbl-overall=Model-averaged estimates
+lbl-overall_1=Model-averaged estimates
+lbl-overall_2=Model-averaged estimates
+lbl-overall-alpha_1=Alpha
+lbl-overall-alpha-inv_1=Alpha-Inv
+lbl-overall-inv-alpha_1=Inv-Alpha
+lbl-overall-inv_1=Inv
+lbl-overall-alpha_2=Alpha
+lbl-overall-alpha-inv_2=Alpha-Inv
+lbl-overall-inv-alpha_2=Inv-Alpha
+lbl-overall-inv_2=Inv
+btnExport.text=Export to main console
diff --git a/src/main/java/es/uvigo/darwin/xprottest/results/ErrorLogView.java b/src/main/java/es/uvigo/darwin/xprottest/results/ErrorLogView.java
new file mode 100755
index 0000000..c661541
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/results/ErrorLogView.java
@@ -0,0 +1,101 @@
+/*
+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.xprottest.results;
+
+import es.uvigo.darwin.prottest.util.WriterOutputStream;
+import es.uvigo.darwin.prottest.util.logging.ProtTestLogFormatter;
+import java.io.PrintWriter;
+import es.uvigo.darwin.xprottest.util.TextAreaAppender;
+import java.util.logging.Filter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.StreamHandler;
+
+/**
+ *
+ * @author  Diego Darriba
+ */
+public class ErrorLogView extends javax.swing.JFrame {
+
+    private PrintWriter errorWriter;
+    private Handler logHandler;
+    
+    public Handler getLogHandler() {
+        return logHandler;
+    }
+    
+    /** Creates new form ErrorLogView */
+    public ErrorLogView() {
+        initComponents();
+        errorWriter = new PrintWriter(new TextAreaAppender(errorTextArea));
+        logHandler = new StreamHandler(new WriterOutputStream(errorWriter),
+                new ProtTestLogFormatter());
+        logHandler.setFilter(new Filter(){
+
+            public boolean isLoggable(LogRecord lr) {
+                return lr.getLevel().equals(Level.SEVERE);
+            }
+            
+        });
+    }
+    
+    /** This method is called from within the constructor to
+     * initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is
+     * always regenerated by the Form Editor.
+     */
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+
+        errorScrollPane = new javax.swing.JScrollPane();
+        errorTextArea = new javax.swing.JTextArea();
+
+        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(es.uvigo.darwin.xprottest.XProtTestApp.class).getContext().getResourceMap(ErrorLogView.class);
+        setTitle(resourceMap.getString("Form.title")); // NOI18N
+        setName("Form"); // NOI18N
+
+        errorScrollPane.setName("errorScrollPane"); // NOI18N
+
+        errorTextArea.setColumns(15);
+        errorTextArea.setEditable(false);
+        errorTextArea.setFont(resourceMap.getFont("errorTextArea.font")); // NOI18N
+        errorTextArea.setRows(30);
+        errorTextArea.setName("errorTextArea"); // NOI18N
+        errorScrollPane.setViewportView(errorTextArea);
+
+        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+        getContentPane().setLayout(layout);
+        layout.setHorizontalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(errorScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 601, Short.MAX_VALUE)
+        );
+        layout.setVerticalGroup(
+            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addComponent(errorScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 426, Short.MAX_VALUE)
+        );
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+    
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JScrollPane errorScrollPane;
+    private javax.swing.JTextArea errorTextArea;
+    // End of variables declaration//GEN-END:variables
+    
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/results/ResultsView.java b/src/main/java/es/uvigo/darwin/xprottest/results/ResultsView.java
new file mode 100755
index 0000000..45c7934
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/results/ResultsView.java
@@ -0,0 +1,2483 @@
+/*
+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.xprottest.results;
+
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.CRITERION_NAMES;
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.CRITERION_PRECISSION;
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.PARAMETER_F;
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.PARAMETER_G;
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.PARAMETER_I;
+import static es.uvigo.darwin.prottest.global.ProtTestConstants.PARAMETER_IG;
+import static es.uvigo.darwin.prottest.selection.printer.PrintFramework.getDisplayValue;
+
+import java.util.Collection;
+
+import javax.swing.JTable;
+import javax.swing.RowSorter;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
+
+import org.jdesktop.application.Action;
+
+import pal.alignment.Alignment;
+import es.uvigo.darwin.prottest.facade.util.SelectionChunk;
+import es.uvigo.darwin.prottest.model.Model;
+import es.uvigo.darwin.prottest.selection.InformationCriterion;
+import es.uvigo.darwin.prottest.selection.model.SelectionModel;
+import es.uvigo.darwin.prottest.util.printer.ProtTestFormattedOutput;
+import es.uvigo.darwin.prottest.util.printer.ProtTestPrinter;
+import es.uvigo.darwin.xprottest.XProtTestView;
+
+/**
+ * The view of the model selection results. It includes a selection under all
+ * supported information criterions.
+ * 
+ * @author Diego Darriba
+ */
+public class ResultsView extends javax.swing.JFrame {
+
+	private static final int AIC_TAB = 0;
+	private static final int BIC_TAB = 1;
+	private static final int AICC_TAB = 2;
+	private static final int DT_TAB = 3;
+	private int rows;
+	javax.swing.table.DefaultTableModel aicTableModel, bicTableModel,
+			aiccTableModel, dtTableModel;
+	private Model[] models;
+	private Alignment alignment;
+	private XProtTestView mainFrame;
+	private SelectionChunk aicResults, bicResults, aiccResults, dtResults;
+
+	// private boolean existInvModels = false,
+	// existGammaModels = false,
+	// existGammaInvModels = false,
+	// existFModels = false;
+
+	private void loadCache(double confidenceInterval) {
+		// criterion cache
+		aicResults = mainFrame.getFacade().computeInformationCriterion(
+				alignment, models, SelectionChunk.AIC, confidenceInterval);
+		bicResults = mainFrame.getFacade().computeInformationCriterion(
+				alignment, models, SelectionChunk.BIC, confidenceInterval);
+		aiccResults = mainFrame.getFacade().computeInformationCriterion(
+				alignment, models, SelectionChunk.AICC, confidenceInterval);
+		dtResults = mainFrame.getFacade().computeInformationCriterion(
+				alignment, models, SelectionChunk.DT, confidenceInterval);
+	}
+
+	/** Creates new form ResultsView */
+	public ResultsView(XProtTestView mainFrame, Alignment alignment,
+			Model[] models, boolean correctDone) {
+		this.mainFrame = mainFrame;
+		this.alignment = alignment;
+		this.rows = models.length;
+		this.models = models;
+
+		// for (Model model : models) {
+		// if (!existInvModels && model.isInv() && !model.isGamma()) {
+		// existInvModels = true;
+		// } else if (!existGammaModels && !model.isInv() && model.isGamma()) {
+		// existGammaModels = true;
+		// } else if (!existGammaInvModels && model.isInv() && model.isGamma())
+		// {
+		// existGammaInvModels = true;
+		// } else if (!existFModels && model.isPlusF()) {
+		// existFModels = true;
+		// }
+		// }
+
+		initComponents();
+		loadCache(Double.parseDouble(sliderConfidenceInterval.getValue() + "") / 100);
+		fillInResults();
+
+		lblNotComplete.setVisible(!correctDone);
+	}
+
+	/**
+	 * This method is called from within the constructor to initialize the form.
+	 * WARNING: Do NOT modify this code. The content of this method is always
+	 * regenerated by the Form Editor.
+	 */
+	@SuppressWarnings("unchecked")
+	// <editor-fold defaultstate="collapsed"
+	// desc="Generated Code">//GEN-BEGIN:initComponents
+	private void initComponents() {
+
+		resultsTabbedPane = new javax.swing.JTabbedPane();
+		aicPanel = new javax.swing.JPanel();
+		aicScrollPanel = new javax.swing.JScrollPane();
+		aicTable = new javax.swing.JTable();
+		aicDataPanel = new javax.swing.JPanel();
+		lblAICOverall = new javax.swing.JLabel();
+		lblAICOverallAlpha = new javax.swing.JLabel();
+		lblAICOverallAlphaInv = new javax.swing.JLabel();
+		lblAICOverallInvAlpha = new javax.swing.JLabel();
+		lblAICOverallInv = new javax.swing.JLabel();
+		displayAICoAlpha = new javax.swing.JLabel();
+		displayAICoAlphaInv = new javax.swing.JLabel();
+		displayAICoInvAlpha = new javax.swing.JLabel();
+		displayAICoInv = new javax.swing.JLabel();
+		lblAICPI = new javax.swing.JLabel();
+		lblAICImpInv = new javax.swing.JLabel();
+		lblAICImpAlpha = new javax.swing.JLabel();
+		lblAICImpF = new javax.swing.JLabel();
+		lblAICImpAlphaInv = new javax.swing.JLabel();
+		displayAICImpInv = new javax.swing.JLabel();
+		displayAICImpAlpha = new javax.swing.JLabel();
+		displayAICImpAlphaInv = new javax.swing.JLabel();
+		displayAICImpF = new javax.swing.JLabel();
+		bicPanel = new javax.swing.JPanel();
+		bicScrollPanel = new javax.swing.JScrollPane();
+		bicTable = new javax.swing.JTable();
+		bicDataPanel = new javax.swing.JPanel();
+		lblBICOverall = new javax.swing.JLabel();
+		lblBICOverallAlpha = new javax.swing.JLabel();
+		lblBICOverallAlphaInv = new javax.swing.JLabel();
+		lblBICOverallInvAlpha = new javax.swing.JLabel();
+		lblBICOverallInv = new javax.swing.JLabel();
+		displayBICoAlpha = new javax.swing.JLabel();
+		displayBICoAlphaInv = new javax.swing.JLabel();
+		displayBICoInvAlpha = new javax.swing.JLabel();
+		displayBICoInv = new javax.swing.JLabel();
+		lblBICImpInv = new javax.swing.JLabel();
+		lblBICImpAlpha = new javax.swing.JLabel();
+		lblBICImpF = new javax.swing.JLabel();
+		lblBICImpAlphaInv = new javax.swing.JLabel();
+		displayBICImpInv = new javax.swing.JLabel();
+		displayBICImpAlpha = new javax.swing.JLabel();
+		displayBICImpAlphaInv = new javax.swing.JLabel();
+		displayBICImpF = new javax.swing.JLabel();
+		lblBICPI = new javax.swing.JLabel();
+		aiccPanel = new javax.swing.JPanel();
+		aiccScrollPanel = new javax.swing.JScrollPane();
+		aiccTable = new javax.swing.JTable();
+		aiccDataPanel = new javax.swing.JPanel();
+		lblAICcOverall = new javax.swing.JLabel();
+		lblAICcOverallAlpha = new javax.swing.JLabel();
+		lblAICcOverallAlphaInv = new javax.swing.JLabel();
+		lblAICcOverallInvAlpha = new javax.swing.JLabel();
+		lblAICcOverallInv = new javax.swing.JLabel();
+		displayAICcoAlpha = new javax.swing.JLabel();
+		displayAICcoAlphaInv = new javax.swing.JLabel();
+		displayAICcoInvAlpha = new javax.swing.JLabel();
+		displayAICcoInv = new javax.swing.JLabel();
+		lblAICcPI = new javax.swing.JLabel();
+		lblAICcImpInv = new javax.swing.JLabel();
+		lblAICcImpAlpha = new javax.swing.JLabel();
+		lblAICcImpF = new javax.swing.JLabel();
+		lblAICcImpAlphaInv = new javax.swing.JLabel();
+		displayAICcImpInv = new javax.swing.JLabel();
+		displayAICcImpAlpha = new javax.swing.JLabel();
+		displayAICcImpAlphaInv = new javax.swing.JLabel();
+		displayAICcImpF = new javax.swing.JLabel();
+		dtPanel = new javax.swing.JPanel();
+		dtScrollPanel = new javax.swing.JScrollPane();
+		dtTable = new javax.swing.JTable();
+		dtDataPanel = new javax.swing.JPanel();
+		lblDTOverall = new javax.swing.JLabel();
+		lblDTOverallAlpha = new javax.swing.JLabel();
+		lblDTOverallAlphaInv = new javax.swing.JLabel();
+		lblDTOverallInvAlpha = new javax.swing.JLabel();
+		lblDTOverallInv = new javax.swing.JLabel();
+		displayDToAlpha = new javax.swing.JLabel();
+		displayDToAlphaInv = new javax.swing.JLabel();
+		displayDToInvAlpha = new javax.swing.JLabel();
+		displayDToInv = new javax.swing.JLabel();
+		lblDTPI = new javax.swing.JLabel();
+		lblDTImpInv = new javax.swing.JLabel();
+		lblDTImpAlpha = new javax.swing.JLabel();
+		lblDTImpF = new javax.swing.JLabel();
+		lblDTImpAlphaInv = new javax.swing.JLabel();
+		displayDTImpInv = new javax.swing.JLabel();
+		displayDTImpAlpha = new javax.swing.JLabel();
+		displayDTImpAlphaInv = new javax.swing.JLabel();
+		displayDTImpF = new javax.swing.JLabel();
+		sliderConfidenceInterval = new javax.swing.JSlider();
+		lblConfInt = new javax.swing.JLabel();
+		jScrollPane1 = new javax.swing.JScrollPane();
+		lblCommandLine = new javax.swing.JTextArea();
+		lblComandLineLabel = new javax.swing.JLabel();
+		lblSelectedModelLabel = new javax.swing.JLabel();
+		lblSelectedModel = new javax.swing.JLabel();
+		lblNotComplete = new javax.swing.JLabel();
+		lblConfidence = new javax.swing.JLabel();
+		btnExport = new javax.swing.JButton();
+
+		setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+		org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application
+				.getInstance().getContext().getResourceMap(ResultsView.class);
+		setTitle(resourceMap.getString("Form.title")); // NOI18N
+		setName("Form"); // NOI18N
+		setResizable(false);
+
+		resultsTabbedPane
+				.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT);
+		resultsTabbedPane.setName("resultsTabbedPane"); // NOI18N
+
+		aicPanel.setName("aicPanel"); // NOI18N
+
+		aicScrollPanel.setName("aicScrollPanel"); // NOI18N
+
+		aicTableModel = new javax.swing.table.DefaultTableModel() {
+			public Class getColumnClass(int column) {
+				if (column == 0)
+					return String.class;
+				if (column >= 1 && column <= getColumnCount()) {
+					try {
+						return getValueAt(0, column).getClass();
+					} catch (ArrayIndexOutOfBoundsException e) {
+						return Object.class;
+					}
+				} else
+					return Object.class;
+			}
+
+			public boolean isCellEditable(int row, int col) {
+				return false;
+			}
+		};
+		aicTableModel.addColumn("Model", new String[rows][1]);
+		aicTableModel.addColumn("-LnL", new Double[rows][1]);
+		aicTableModel.addColumn("AIC", new Double[rows][1]);
+		aicTableModel.addColumn("deltaAIC", new Double[rows][1]);
+		aicTableModel.addColumn("AIC weight", new Double[rows][1]);
+		aicTable.setModel(aicTableModel);
+		aicTable.setCellSelectionEnabled(true);
+		aicTable.setName("aicTable"); // NOI18N
+		RowSorter<TableModel> aicSorter = new TableRowSorter<TableModel>(
+				aicTableModel);
+		aicTable.setRowSorter(aicSorter);
+
+		SelectionListener listener = new SelectionListener(aicTable);
+		aicTable.getSelectionModel().addListSelectionListener(listener);
+		aicTable.getColumnModel().getSelectionModel()
+				.addListSelectionListener(listener);
+		aicScrollPanel.setViewportView(aicTable);
+
+		aicDataPanel.setBorder(javax.swing.BorderFactory
+				.createLineBorder(new java.awt.Color(0, 0, 0)));
+		aicDataPanel.setName("aicDataPanel"); // NOI18N
+
+		java.util.ResourceBundle bundle = java.util.ResourceBundle
+				.getBundle("es/uvigo/darwin/xprottest/results/resources/ResultsView"); // NOI18N
+		lblAICOverall.setText(bundle.getString("lbl-overall")); // NOI18N
+		lblAICOverall.setName("lblAICOverall"); // NOI18N
+
+		lblAICOverallAlpha.setText(bundle.getString("lbl-overall-alpha")); // NOI18N
+		lblAICOverallAlpha.setName("lblAICOverallAlpha"); // NOI18N
+
+		lblAICOverallAlphaInv
+				.setText(bundle.getString("lbl-overall-alpha-inv")); // NOI18N
+		lblAICOverallAlphaInv.setName("lblAICOverallAlphaInv"); // NOI18N
+
+		lblAICOverallInvAlpha
+				.setText(bundle.getString("lbl-overall-inv-alpha")); // NOI18N
+		lblAICOverallInvAlpha.setName("lblAICOverallInvAlpha"); // NOI18N
+
+		lblAICOverallInv.setText(bundle.getString("lbl-overall-inv")); // NOI18N
+		lblAICOverallInv.setName("lblAICOverallInv"); // NOI18N
+
+		displayAICoAlpha
+				.setText(resourceMap.getString("displayAICoAlpha.text")); // NOI18N
+		displayAICoAlpha.setName("displayAICoAlpha"); // NOI18N
+
+		displayAICoAlphaInv.setText(resourceMap
+				.getString("displayAICoAlphaInv.text")); // NOI18N
+		displayAICoAlphaInv.setName("displayAICoAlphaInv"); // NOI18N
+
+		displayAICoInvAlpha.setText(resourceMap
+				.getString("displayAICoInvAlpha.text")); // NOI18N
+		displayAICoInvAlpha.setName("displayAICoInvAlpha"); // NOI18N
+
+		displayAICoInv.setText(resourceMap.getString("displayAICoInv.text")); // NOI18N
+		displayAICoInv.setName("displayAICoInv"); // NOI18N
+
+		lblAICPI.setText(resourceMap.getString("lblAICPI.text")); // NOI18N
+		lblAICPI.setName("lblAICPI"); // NOI18N
+
+		lblAICImpInv.setText(resourceMap.getString("lblAICImpInv.text")); // NOI18N
+		lblAICImpInv.setName("lblAICImpInv"); // NOI18N
+
+		lblAICImpAlpha.setText(resourceMap.getString("lblAICImpAlpha.text")); // NOI18N
+		lblAICImpAlpha.setName("lblAICImpAlpha"); // NOI18N
+
+		lblAICImpF.setText(resourceMap.getString("lblAICImpF.text")); // NOI18N
+		lblAICImpF.setName("lblAICImpF"); // NOI18N
+
+		lblAICImpAlphaInv.setText(resourceMap
+				.getString("lblAICImpAlphaInv.text")); // NOI18N
+		lblAICImpAlphaInv.setName("lblAICImpAlphaInv"); // NOI18N
+
+		displayAICImpInv
+				.setText(resourceMap.getString("displayAICImpInv.text")); // NOI18N
+		displayAICImpInv.setName("displayAICImpInv"); // NOI18N
+
+		displayAICImpAlpha.setText(resourceMap
+				.getString("displayAICImpAlpha.text")); // NOI18N
+		displayAICImpAlpha.setName("displayAICImpAlpha"); // NOI18N
+
+		displayAICImpAlphaInv.setText(resourceMap
+				.getString("displayAICImpAlphaInv.text")); // NOI18N
+		displayAICImpAlphaInv.setName("displayAICImpAlphaInv"); // NOI18N
+
+		displayAICImpF.setText(resourceMap.getString("displayAICImpF.text")); // NOI18N
+		displayAICImpF.setName("displayAICImpF"); // NOI18N
+
+		javax.swing.GroupLayout aicDataPanelLayout = new javax.swing.GroupLayout(
+				aicDataPanel);
+		aicDataPanel.setLayout(aicDataPanelLayout);
+		aicDataPanelLayout
+				.setHorizontalGroup(aicDataPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								aicDataPanelLayout
+										.createSequentialGroup()
+										.addGroup(
+												aicDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																aicDataPanelLayout
+																		.createSequentialGroup()
+																		.addGap(44,
+																				44,
+																				44)
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								false)
+																						.addComponent(
+																								lblAICOverallAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICOverallAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICOverallInvAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICOverallInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE))
+																		.addGap(18,
+																				18,
+																				18)
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING)
+																						.addComponent(
+																								displayAICoInv)
+																						.addComponent(
+																								displayAICoInvAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayAICoAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayAICoAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE))
+																		.addGap(40,
+																				40,
+																				40))
+														.addGroup(
+																aicDataPanelLayout
+																		.createSequentialGroup()
+																		.addContainerGap()
+																		.addComponent(
+																				lblAICOverall,
+																				javax.swing.GroupLayout.DEFAULT_SIZE,
+																				366,
+																				Short.MAX_VALUE)
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)))
+										.addGroup(
+												aicDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																aicDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.TRAILING,
+																								false)
+																						.addComponent(
+																								lblAICImpAlpha,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICImpInv,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICImpF,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICImpAlphaInv,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.PREFERRED_SIZE,
+																								59,
+																								javax.swing.GroupLayout.PREFERRED_SIZE))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								false)
+																						.addComponent(
+																								displayAICImpInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								83,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayAICImpAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayAICImpAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayAICImpF,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)))
+														.addComponent(
+																lblAICPI,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																237,
+																Short.MAX_VALUE))
+										.addContainerGap()));
+		aicDataPanelLayout
+				.setVerticalGroup(aicDataPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								aicDataPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addGroup(
+												aicDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.BASELINE)
+														.addComponent(
+																lblAICOverall)
+														.addComponent(lblAICPI))
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addGroup(
+												aicDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																aicDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICOverallAlpha)
+																						.addComponent(
+																								displayAICoAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICOverallAlphaInv)
+																						.addComponent(
+																								displayAICoAlphaInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICOverallInvAlpha)
+																						.addComponent(
+																								displayAICoInvAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICOverallInv)
+																						.addComponent(
+																								displayAICoInv)))
+														.addGroup(
+																aicDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICImpInv)
+																						.addComponent(
+																								displayAICImpInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICImpAlpha)
+																						.addComponent(
+																								displayAICImpAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICImpAlphaInv)
+																						.addComponent(
+																								displayAICImpAlphaInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICImpF)
+																						.addComponent(
+																								displayAICImpF))))
+										.addContainerGap(
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												Short.MAX_VALUE)));
+
+		javax.swing.GroupLayout aicPanelLayout = new javax.swing.GroupLayout(
+				aicPanel);
+		aicPanel.setLayout(aicPanelLayout);
+		aicPanelLayout
+				.setHorizontalGroup(aicPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								aicPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addGroup(
+												aicPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addComponent(
+																aicScrollPanel,
+																javax.swing.GroupLayout.Alignment.TRAILING,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																635,
+																Short.MAX_VALUE)
+														.addComponent(
+																aicDataPanel,
+																javax.swing.GroupLayout.Alignment.TRAILING,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																Short.MAX_VALUE))
+										.addContainerGap()));
+		aicPanelLayout
+				.setVerticalGroup(aicPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								javax.swing.GroupLayout.Alignment.TRAILING,
+								aicPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addComponent(
+												aicScrollPanel,
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												300, Short.MAX_VALUE)
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addComponent(
+												aicDataPanel,
+												javax.swing.GroupLayout.PREFERRED_SIZE,
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												javax.swing.GroupLayout.PREFERRED_SIZE)
+										.addContainerGap()));
+
+		resultsTabbedPane.addTab(
+				resourceMap.getString("aicPanel.TabConstraints.tabTitle"),
+				aicPanel); // NOI18N
+
+		bicPanel.setName("bicPanel"); // NOI18N
+
+		bicScrollPanel.setName("bicScrollPanel"); // NOI18N
+
+		bicTableModel = new javax.swing.table.DefaultTableModel() {
+			public Class getColumnClass(int column) {
+				if (column >= 0 && column <= getColumnCount()) {
+					try {
+						return getValueAt(0, column).getClass();
+					} catch (ArrayIndexOutOfBoundsException e) {
+						return Object.class;
+					}
+				} else
+					return Object.class;
+			}
+
+			public boolean isCellEditable(int row, int col) {
+				return false;
+			}
+		};
+		bicTableModel.addColumn("Model", new String[rows][1]);
+		bicTableModel.addColumn("-LnL", new Double[rows][1]);
+		bicTableModel.addColumn("BIC", new Double[rows][1]);
+		bicTableModel.addColumn("deltaBIC", new Double[rows][1]);
+		bicTableModel.addColumn("BIC weight", new Double[rows][1]);
+		bicTable.setModel(bicTableModel);
+		bicTable.setCellSelectionEnabled(true);
+		bicTable.setName("bicTable"); // NOI18N
+		RowSorter<TableModel> bicSorter = new TableRowSorter<TableModel>(
+				bicTableModel);
+		bicTable.setRowSorter(bicSorter);
+
+		SelectionListener bicListener = new SelectionListener(bicTable);
+		bicTable.getSelectionModel().addListSelectionListener(bicListener);
+		bicTable.getColumnModel().getSelectionModel()
+				.addListSelectionListener(bicListener);
+		bicScrollPanel.setViewportView(bicTable);
+
+		bicDataPanel.setBorder(javax.swing.BorderFactory
+				.createLineBorder(new java.awt.Color(0, 0, 0)));
+		bicDataPanel.setName("bicDataPanel"); // NOI18N
+
+		java.util.ResourceBundle bundle1 = java.util.ResourceBundle
+				.getBundle("es/uvigo/darwin/xprottest/results/Bundle"); // NOI18N
+		lblBICOverall.setText(bundle1.getString("lbl-overall")); // NOI18N
+		lblBICOverall.setName("lblBICOverall"); // NOI18N
+
+		lblBICOverallAlpha.setText(bundle1.getString("lbl-overall-alpha")); // NOI18N
+		lblBICOverallAlpha.setName("lblBICOverallAlpha"); // NOI18N
+
+		lblBICOverallAlphaInv.setText(bundle1
+				.getString("lbl-overall-alpha-inv")); // NOI18N
+		lblBICOverallAlphaInv.setName("lblBICOverallAlphaInv"); // NOI18N
+
+		lblBICOverallInvAlpha.setText(bundle1
+				.getString("lbl-overall-inv-alpha")); // NOI18N
+		lblBICOverallInvAlpha.setName("lblBICOverallInvAlpha"); // NOI18N
+
+		lblBICOverallInv.setText(bundle1.getString("lbl-overall-inv")); // NOI18N
+		lblBICOverallInv.setName("lblBICOverallInv"); // NOI18N
+
+		displayBICoAlpha
+				.setText(resourceMap.getString("displayBICoAlpha.text")); // NOI18N
+		displayBICoAlpha.setName("displayBICoAlpha"); // NOI18N
+
+		displayBICoAlphaInv.setText(resourceMap
+				.getString("displayBICoAlphaInv.text")); // NOI18N
+		displayBICoAlphaInv.setName("displayBICoAlphaInv"); // NOI18N
+
+		displayBICoInvAlpha.setText(resourceMap
+				.getString("displayBICoInvAlpha.text")); // NOI18N
+		displayBICoInvAlpha.setName("displayBICoInvAlpha"); // NOI18N
+
+		displayBICoInv.setText(resourceMap.getString("displayBICoInv.text")); // NOI18N
+		displayBICoInv.setName("displayBICoInv"); // NOI18N
+
+		lblBICImpInv.setText(resourceMap.getString("lblBICImpInv.text")); // NOI18N
+		lblBICImpInv.setName("lblBICImpInv"); // NOI18N
+
+		lblBICImpAlpha.setText(resourceMap.getString("lblBICImpAlpha.text")); // NOI18N
+		lblBICImpAlpha.setName("lblBICImpAlpha"); // NOI18N
+
+		lblBICImpF.setText(resourceMap.getString("lblBICImpF.text")); // NOI18N
+		lblBICImpF.setName("lblBICImpF"); // NOI18N
+
+		lblBICImpAlphaInv.setText(resourceMap
+				.getString("lblBICImpAlphaInv.text")); // NOI18N
+		lblBICImpAlphaInv.setName("lblBICImpAlphaInv"); // NOI18N
+
+		displayBICImpInv
+				.setText(resourceMap.getString("displayBICImpInv.text")); // NOI18N
+		displayBICImpInv.setName("displayBICImpInv"); // NOI18N
+
+		displayBICImpAlpha.setText(resourceMap
+				.getString("displayBICImpAlpha.text")); // NOI18N
+		displayBICImpAlpha.setName("displayBICImpAlpha"); // NOI18N
+
+		displayBICImpAlphaInv.setText(resourceMap
+				.getString("displayBICImpAlphaInv.text")); // NOI18N
+		displayBICImpAlphaInv.setName("displayBICImpAlphaInv"); // NOI18N
+
+		displayBICImpF.setText(resourceMap.getString("displayBICImpF.text")); // NOI18N
+		displayBICImpF.setName("displayBICImpF"); // NOI18N
+
+		lblBICPI.setText(resourceMap.getString("lblBICPI.text")); // NOI18N
+		lblBICPI.setName("lblBICPI"); // NOI18N
+
+		javax.swing.GroupLayout bicDataPanelLayout = new javax.swing.GroupLayout(
+				bicDataPanel);
+		bicDataPanel.setLayout(bicDataPanelLayout);
+		bicDataPanelLayout
+				.setHorizontalGroup(bicDataPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								bicDataPanelLayout
+										.createSequentialGroup()
+										.addGroup(
+												bicDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																bicDataPanelLayout
+																		.createSequentialGroup()
+																		.addGap(44,
+																				44,
+																				44)
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								false)
+																						.addComponent(
+																								lblBICOverallAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblBICOverallAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblBICOverallInvAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblBICOverallInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE))
+																		.addGap(18,
+																				18,
+																				18)
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING)
+																						.addComponent(
+																								displayBICoInv)
+																						.addComponent(
+																								displayBICoInvAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayBICoAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayBICoAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE))
+																		.addGap(40,
+																				40,
+																				40))
+														.addGroup(
+																bicDataPanelLayout
+																		.createSequentialGroup()
+																		.addContainerGap()
+																		.addComponent(
+																				lblBICOverall,
+																				javax.swing.GroupLayout.DEFAULT_SIZE,
+																				366,
+																				Short.MAX_VALUE)
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)))
+										.addGroup(
+												bicDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.TRAILING)
+														.addGroup(
+																javax.swing.GroupLayout.Alignment.LEADING,
+																bicDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.TRAILING,
+																								false)
+																						.addComponent(
+																								lblBICImpAlpha,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblBICImpInv,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblBICImpF,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblBICImpAlphaInv,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.PREFERRED_SIZE,
+																								59,
+																								javax.swing.GroupLayout.PREFERRED_SIZE))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								false)
+																						.addComponent(
+																								displayBICImpInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								83,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayBICImpAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayBICImpAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayBICImpF,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)))
+														.addGroup(
+																bicDataPanelLayout
+																		.createSequentialGroup()
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addComponent(
+																				lblBICPI,
+																				javax.swing.GroupLayout.DEFAULT_SIZE,
+																				237,
+																				Short.MAX_VALUE)))
+										.addContainerGap()));
+		bicDataPanelLayout
+				.setVerticalGroup(bicDataPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								bicDataPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addGroup(
+												bicDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.BASELINE)
+														.addComponent(
+																lblBICOverall)
+														.addComponent(lblBICPI))
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addGroup(
+												bicDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																bicDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblBICOverallAlpha)
+																						.addComponent(
+																								displayBICoAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblBICOverallAlphaInv)
+																						.addComponent(
+																								displayBICoAlphaInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblBICOverallInvAlpha)
+																						.addComponent(
+																								displayBICoInvAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblBICOverallInv)
+																						.addComponent(
+																								displayBICoInv)))
+														.addGroup(
+																bicDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblBICImpInv)
+																						.addComponent(
+																								displayBICImpInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblBICImpAlpha)
+																						.addComponent(
+																								displayBICImpAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblBICImpAlphaInv)
+																						.addComponent(
+																								displayBICImpAlphaInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				bicDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblBICImpF)
+																						.addComponent(
+																								displayBICImpF))))
+										.addContainerGap(
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												Short.MAX_VALUE)));
+
+		javax.swing.GroupLayout bicPanelLayout = new javax.swing.GroupLayout(
+				bicPanel);
+		bicPanel.setLayout(bicPanelLayout);
+		bicPanelLayout
+				.setHorizontalGroup(bicPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								bicPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addGroup(
+												bicPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addComponent(
+																bicScrollPanel,
+																javax.swing.GroupLayout.Alignment.TRAILING,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																635,
+																Short.MAX_VALUE)
+														.addComponent(
+																bicDataPanel,
+																javax.swing.GroupLayout.Alignment.TRAILING,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																Short.MAX_VALUE))
+										.addContainerGap()));
+		bicPanelLayout
+				.setVerticalGroup(bicPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								javax.swing.GroupLayout.Alignment.TRAILING,
+								bicPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addComponent(
+												bicScrollPanel,
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												300, Short.MAX_VALUE)
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addComponent(
+												bicDataPanel,
+												javax.swing.GroupLayout.PREFERRED_SIZE,
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												javax.swing.GroupLayout.PREFERRED_SIZE)
+										.addContainerGap()));
+
+		resultsTabbedPane.addTab(
+				resourceMap.getString("bicPanel.TabConstraints.tabTitle"),
+				bicPanel); // NOI18N
+
+		aiccPanel.setName("aiccPanel"); // NOI18N
+
+		aiccScrollPanel.setName("aiccScrollPanel"); // NOI18N
+
+		aiccTableModel = new javax.swing.table.DefaultTableModel() {
+			public Class getColumnClass(int column) {
+				if (column >= 0 && column <= getColumnCount()) {
+					try {
+						return getValueAt(0, column).getClass();
+					} catch (ArrayIndexOutOfBoundsException e) {
+						return Object.class;
+					}
+				} else
+					return Object.class;
+			}
+
+			public boolean isCellEditable(int row, int col) {
+				return false;
+			}
+		};
+		aiccTableModel.addColumn("Model", new String[rows][1]);
+		aiccTableModel.addColumn("-LnL", new Double[rows][1]);
+		aiccTableModel.addColumn("AICc", new Double[rows][1]);
+		aiccTableModel.addColumn("deltaAICc", new Double[rows][1]);
+		aiccTableModel.addColumn("AICc weight", new Double[rows][1]);
+		aiccTable.setModel(aiccTableModel);
+		aiccTable.setCellSelectionEnabled(true);
+		aiccTable.setName("aiccTable"); // NOI18N
+		RowSorter<TableModel> aiccSorter = new TableRowSorter<TableModel>(
+				aiccTableModel);
+		aiccTable.setRowSorter(aiccSorter);
+
+		SelectionListener aiccListener = new SelectionListener(aiccTable);
+		aiccTable.getSelectionModel().addListSelectionListener(aiccListener);
+		aiccTable.getColumnModel().getSelectionModel()
+				.addListSelectionListener(aiccListener);
+		aiccScrollPanel.setViewportView(aiccTable);
+
+		aiccDataPanel.setBorder(javax.swing.BorderFactory
+				.createLineBorder(new java.awt.Color(0, 0, 0)));
+		aiccDataPanel.setName("aiccDataPanel"); // NOI18N
+
+		lblAICcOverall.setText(bundle1.getString("lbl-overall_1")); // NOI18N
+		lblAICcOverall.setName("lblAICcOverall"); // NOI18N
+
+		lblAICcOverallAlpha.setText(bundle1.getString("lbl-overall-alpha_1")); // NOI18N
+		lblAICcOverallAlpha.setName("lblAICcOverallAlpha"); // NOI18N
+
+		lblAICcOverallAlphaInv.setText(bundle1
+				.getString("lbl-overall-alpha-inv_1")); // NOI18N
+		lblAICcOverallAlphaInv.setName("lblAICcOverallAlphaInv"); // NOI18N
+
+		lblAICcOverallInvAlpha.setText(bundle1
+				.getString("lbl-overall-inv-alpha_1")); // NOI18N
+		lblAICcOverallInvAlpha.setName("lblAICcOverallInvAlpha"); // NOI18N
+
+		lblAICcOverallInv.setText(bundle1.getString("lbl-overall-inv_1")); // NOI18N
+		lblAICcOverallInv.setName("lblAICcOverallInv"); // NOI18N
+
+		displayAICcoAlpha.setText(resourceMap
+				.getString("displayAICcoAlpha.text")); // NOI18N
+		displayAICcoAlpha.setName("displayAICcoAlpha"); // NOI18N
+
+		displayAICcoAlphaInv.setText(resourceMap
+				.getString("displayAICcoAlphaInv.text")); // NOI18N
+		displayAICcoAlphaInv.setName("displayAICcoAlphaInv"); // NOI18N
+
+		displayAICcoInvAlpha.setText(resourceMap
+				.getString("displayAICcoInvAlpha.text")); // NOI18N
+		displayAICcoInvAlpha.setName("displayAICcoInvAlpha"); // NOI18N
+
+		displayAICcoInv.setText(resourceMap.getString("displayAICcoInv.text")); // NOI18N
+		displayAICcoInv.setName("displayAICcoInv"); // NOI18N
+
+		lblAICcPI.setText(resourceMap.getString("lblAICcPI.text")); // NOI18N
+		lblAICcPI.setName("lblAICcPI"); // NOI18N
+
+		lblAICcImpInv.setText(resourceMap.getString("lblAICcImpInv.text")); // NOI18N
+		lblAICcImpInv.setName("lblAICcImpInv"); // NOI18N
+
+		lblAICcImpAlpha.setText(resourceMap.getString("lblAICcImpAlpha.text")); // NOI18N
+		lblAICcImpAlpha.setName("lblAICcImpAlpha"); // NOI18N
+
+		lblAICcImpF.setText(resourceMap.getString("lblAICcImpF.text")); // NOI18N
+		lblAICcImpF.setName("lblAICcImpF"); // NOI18N
+
+		lblAICcImpAlphaInv.setText(resourceMap
+				.getString("lblAICcImpAlphaInv.text")); // NOI18N
+		lblAICcImpAlphaInv.setName("lblAICcImpAlphaInv"); // NOI18N
+
+		displayAICcImpInv.setText(resourceMap
+				.getString("displayAICcImpInv.text")); // NOI18N
+		displayAICcImpInv.setName("displayAICcImpInv"); // NOI18N
+
+		displayAICcImpAlpha.setText(resourceMap
+				.getString("displayAICcImpAlpha.text")); // NOI18N
+		displayAICcImpAlpha.setName("displayAICcImpAlpha"); // NOI18N
+
+		displayAICcImpAlphaInv.setText(resourceMap
+				.getString("displayAICcImpAlphaInv.text")); // NOI18N
+		displayAICcImpAlphaInv.setName("displayAICcImpAlphaInv"); // NOI18N
+
+		displayAICcImpF.setText(resourceMap.getString("displayAICcImpF.text")); // NOI18N
+		displayAICcImpF.setName("displayAICcImpF"); // NOI18N
+
+		javax.swing.GroupLayout aiccDataPanelLayout = new javax.swing.GroupLayout(
+				aiccDataPanel);
+		aiccDataPanel.setLayout(aiccDataPanelLayout);
+		aiccDataPanelLayout
+				.setHorizontalGroup(aiccDataPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								aiccDataPanelLayout
+										.createSequentialGroup()
+										.addGroup(
+												aiccDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																aiccDataPanelLayout
+																		.createSequentialGroup()
+																		.addGap(44,
+																				44,
+																				44)
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								false)
+																						.addComponent(
+																								lblAICcOverallAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICcOverallAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICcOverallInvAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICcOverallInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE))
+																		.addGap(18,
+																				18,
+																				18)
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING)
+																						.addComponent(
+																								displayAICcoInv)
+																						.addComponent(
+																								displayAICcoInvAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayAICcoAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayAICcoAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE))
+																		.addGap(40,
+																				40,
+																				40))
+														.addGroup(
+																aiccDataPanelLayout
+																		.createSequentialGroup()
+																		.addContainerGap()
+																		.addComponent(
+																				lblAICcOverall,
+																				javax.swing.GroupLayout.DEFAULT_SIZE,
+																				366,
+																				Short.MAX_VALUE)
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)))
+										.addGroup(
+												aiccDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																aiccDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.TRAILING,
+																								false)
+																						.addComponent(
+																								lblAICcImpAlpha,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICcImpInv,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICcImpF,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblAICcImpAlphaInv,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.PREFERRED_SIZE,
+																								59,
+																								javax.swing.GroupLayout.PREFERRED_SIZE))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								false)
+																						.addComponent(
+																								displayAICcImpInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								83,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayAICcImpAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayAICcImpAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayAICcImpF,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)))
+														.addComponent(
+																lblAICcPI,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																237,
+																Short.MAX_VALUE))
+										.addContainerGap()));
+		aiccDataPanelLayout
+				.setVerticalGroup(aiccDataPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								aiccDataPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addGroup(
+												aiccDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.BASELINE)
+														.addComponent(
+																lblAICcOverall)
+														.addComponent(lblAICcPI))
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addGroup(
+												aiccDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																aiccDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICcOverallAlpha)
+																						.addComponent(
+																								displayAICcoAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICcOverallAlphaInv)
+																						.addComponent(
+																								displayAICcoAlphaInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICcOverallInvAlpha)
+																						.addComponent(
+																								displayAICcoInvAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICcOverallInv)
+																						.addComponent(
+																								displayAICcoInv)))
+														.addGroup(
+																aiccDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICcImpInv)
+																						.addComponent(
+																								displayAICcImpInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICcImpAlpha)
+																						.addComponent(
+																								displayAICcImpAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICcImpAlphaInv)
+																						.addComponent(
+																								displayAICcImpAlphaInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				aiccDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblAICcImpF)
+																						.addComponent(
+																								displayAICcImpF))))
+										.addContainerGap(
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												Short.MAX_VALUE)));
+
+		javax.swing.GroupLayout aiccPanelLayout = new javax.swing.GroupLayout(
+				aiccPanel);
+		aiccPanel.setLayout(aiccPanelLayout);
+		aiccPanelLayout
+				.setHorizontalGroup(aiccPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								javax.swing.GroupLayout.Alignment.TRAILING,
+								aiccPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addGroup(
+												aiccPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.TRAILING)
+														.addComponent(
+																aiccScrollPanel,
+																javax.swing.GroupLayout.Alignment.LEADING,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																635,
+																Short.MAX_VALUE)
+														.addComponent(
+																aiccDataPanel,
+																javax.swing.GroupLayout.Alignment.LEADING,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																Short.MAX_VALUE))
+										.addContainerGap()));
+		aiccPanelLayout
+				.setVerticalGroup(aiccPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								javax.swing.GroupLayout.Alignment.TRAILING,
+								aiccPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addComponent(
+												aiccScrollPanel,
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												300, Short.MAX_VALUE)
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addComponent(
+												aiccDataPanel,
+												javax.swing.GroupLayout.PREFERRED_SIZE,
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												javax.swing.GroupLayout.PREFERRED_SIZE)
+										.addContainerGap()));
+
+		resultsTabbedPane.addTab(
+				resourceMap.getString("aiccPanel.TabConstraints.tabTitle"),
+				aiccPanel); // NOI18N
+
+		dtPanel.setName("dtPanel"); // NOI18N
+
+		dtScrollPanel.setName("dtScrollPanel"); // NOI18N
+
+		dtTableModel = new javax.swing.table.DefaultTableModel() {
+			public Class getColumnClass(int column) {
+				if (column >= 0 && column <= getColumnCount()) {
+					try {
+						return getValueAt(0, column).getClass();
+					} catch (ArrayIndexOutOfBoundsException e) {
+						return Object.class;
+					}
+				} else
+					return Object.class;
+			}
+
+			public boolean isCellEditable(int row, int col) {
+				return false;
+			}
+		};
+		dtTableModel.addColumn("Model", new String[rows][1]);
+		dtTableModel.addColumn("-LnL", new Double[rows][1]);
+		dtTableModel.addColumn("DT", new Double[rows][1]);
+		dtTableModel.addColumn("deltaDT", new Double[rows][1]);
+		dtTableModel.addColumn("DT weight", new Double[rows][1]);
+		dtTable.setModel(dtTableModel);
+		dtTable.setCellSelectionEnabled(true);
+		dtTable.setName("dtTable"); // NOI18N
+		RowSorter<TableModel> dtSorter = new TableRowSorter<TableModel>(
+				dtTableModel);
+		dtTable.setRowSorter(dtSorter);
+
+		SelectionListener dtListener = new SelectionListener(dtTable);
+		dtTable.getSelectionModel().addListSelectionListener(dtListener);
+		dtTable.getColumnModel().getSelectionModel()
+				.addListSelectionListener(dtListener);
+		dtScrollPanel.setViewportView(dtTable);
+
+		dtDataPanel.setBorder(javax.swing.BorderFactory
+				.createLineBorder(new java.awt.Color(0, 0, 0)));
+		dtDataPanel.setName("dtDataPanel"); // NOI18N
+
+		lblDTOverall.setText(bundle1.getString("lbl-overall_2")); // NOI18N
+		lblDTOverall.setName("lblDTOverall"); // NOI18N
+
+		lblDTOverallAlpha.setText(bundle1.getString("lbl-overall-alpha_2")); // NOI18N
+		lblDTOverallAlpha.setName("lblDTOverallAlpha"); // NOI18N
+
+		lblDTOverallAlphaInv.setText(bundle1
+				.getString("lbl-overall-alpha-inv_2")); // NOI18N
+		lblDTOverallAlphaInv.setName("lblDTOverallAlphaInv"); // NOI18N
+
+		lblDTOverallInvAlpha.setText(bundle1
+				.getString("lbl-overall-inv-alpha_2")); // NOI18N
+		lblDTOverallInvAlpha.setName("lblDTOverallInvAlpha"); // NOI18N
+
+		lblDTOverallInv.setText(bundle1.getString("lbl-overall-inv_2")); // NOI18N
+		lblDTOverallInv.setName("lblDTOverallInv"); // NOI18N
+
+		displayDToAlpha.setText(resourceMap.getString("displayDToAlpha.text")); // NOI18N
+		displayDToAlpha.setName("displayDToAlpha"); // NOI18N
+
+		displayDToAlphaInv.setText(resourceMap
+				.getString("displayDToAlphaInv.text")); // NOI18N
+		displayDToAlphaInv.setName("displayDToAlphaInv"); // NOI18N
+
+		displayDToInvAlpha.setText(resourceMap
+				.getString("displayDToInvAlpha.text")); // NOI18N
+		displayDToInvAlpha.setName("displayDToInvAlpha"); // NOI18N
+
+		displayDToInv.setText(resourceMap.getString("displayDToInv.text")); // NOI18N
+		displayDToInv.setName("displayDToInv"); // NOI18N
+
+		lblDTPI.setText(resourceMap.getString("lblDTPI.text")); // NOI18N
+		lblDTPI.setName("lblDTPI"); // NOI18N
+
+		lblDTImpInv.setText(resourceMap.getString("lblDTImpInv.text")); // NOI18N
+		lblDTImpInv.setName("lblDTImpInv"); // NOI18N
+
+		lblDTImpAlpha.setText(resourceMap.getString("lblDTImpAlpha.text")); // NOI18N
+		lblDTImpAlpha.setName("lblDTImpAlpha"); // NOI18N
+
+		lblDTImpF.setText(resourceMap.getString("lblDTImpF.text")); // NOI18N
+		lblDTImpF.setName("lblDTImpF"); // NOI18N
+
+		lblDTImpAlphaInv
+				.setText(resourceMap.getString("lblDTImpAlphaInv.text")); // NOI18N
+		lblDTImpAlphaInv.setName("lblDTImpAlphaInv"); // NOI18N
+
+		displayDTImpInv.setText(resourceMap.getString("displayDTImpInv.text")); // NOI18N
+		displayDTImpInv.setName("displayDTImpInv"); // NOI18N
+
+		displayDTImpAlpha.setText(resourceMap
+				.getString("displayDTImpAlpha.text")); // NOI18N
+		displayDTImpAlpha.setName("displayDTImpAlpha"); // NOI18N
+
+		displayDTImpAlphaInv.setText(resourceMap
+				.getString("displayDTImpAlphaInv.text")); // NOI18N
+		displayDTImpAlphaInv.setName("displayDTImpAlphaInv"); // NOI18N
+
+		displayDTImpF.setText(resourceMap.getString("displayDTImpF.text")); // NOI18N
+		displayDTImpF.setName("displayDTImpF"); // NOI18N
+
+		javax.swing.GroupLayout dtDataPanelLayout = new javax.swing.GroupLayout(
+				dtDataPanel);
+		dtDataPanel.setLayout(dtDataPanelLayout);
+		dtDataPanelLayout
+				.setHorizontalGroup(dtDataPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								dtDataPanelLayout
+										.createSequentialGroup()
+										.addGroup(
+												dtDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																dtDataPanelLayout
+																		.createSequentialGroup()
+																		.addGap(44,
+																				44,
+																				44)
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								false)
+																						.addComponent(
+																								lblDTOverallAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblDTOverallAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblDTOverallInvAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblDTOverallInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE))
+																		.addGap(18,
+																				18,
+																				18)
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING)
+																						.addComponent(
+																								displayDToInv)
+																						.addComponent(
+																								displayDToInvAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayDToAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayDToAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								223,
+																								Short.MAX_VALUE))
+																		.addGap(40,
+																				40,
+																				40))
+														.addGroup(
+																dtDataPanelLayout
+																		.createSequentialGroup()
+																		.addContainerGap()
+																		.addComponent(
+																				lblDTOverall,
+																				javax.swing.GroupLayout.DEFAULT_SIZE,
+																				366,
+																				Short.MAX_VALUE)
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)))
+										.addGroup(
+												dtDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																dtDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.TRAILING,
+																								false)
+																						.addComponent(
+																								lblDTImpAlpha,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblDTImpInv,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblDTImpF,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								lblDTImpAlphaInv,
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								javax.swing.GroupLayout.PREFERRED_SIZE,
+																								59,
+																								javax.swing.GroupLayout.PREFERRED_SIZE))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.LEADING,
+																								false)
+																						.addComponent(
+																								displayDTImpInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								83,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayDTImpAlpha,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayDTImpAlphaInv,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)
+																						.addComponent(
+																								displayDTImpF,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								javax.swing.GroupLayout.DEFAULT_SIZE,
+																								Short.MAX_VALUE)))
+														.addComponent(
+																lblDTPI,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																237,
+																Short.MAX_VALUE))
+										.addContainerGap()));
+		dtDataPanelLayout
+				.setVerticalGroup(dtDataPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								dtDataPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addGroup(
+												dtDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.BASELINE)
+														.addComponent(
+																lblDTOverall)
+														.addComponent(lblDTPI))
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addGroup(
+												dtDataPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.LEADING)
+														.addGroup(
+																dtDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblDTOverallAlpha)
+																						.addComponent(
+																								displayDToAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblDTOverallAlphaInv)
+																						.addComponent(
+																								displayDToAlphaInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblDTOverallInvAlpha)
+																						.addComponent(
+																								displayDToInvAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblDTOverallInv)
+																						.addComponent(
+																								displayDToInv)))
+														.addGroup(
+																dtDataPanelLayout
+																		.createSequentialGroup()
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblDTImpInv)
+																						.addComponent(
+																								displayDTImpInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblDTImpAlpha)
+																						.addComponent(
+																								displayDTImpAlpha))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblDTImpAlphaInv)
+																						.addComponent(
+																								displayDTImpAlphaInv))
+																		.addPreferredGap(
+																				javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																		.addGroup(
+																				dtDataPanelLayout
+																						.createParallelGroup(
+																								javax.swing.GroupLayout.Alignment.BASELINE)
+																						.addComponent(
+																								lblDTImpF)
+																						.addComponent(
+																								displayDTImpF))))
+										.addContainerGap(
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												Short.MAX_VALUE)));
+
+		javax.swing.GroupLayout dtPanelLayout = new javax.swing.GroupLayout(
+				dtPanel);
+		dtPanel.setLayout(dtPanelLayout);
+		dtPanelLayout
+				.setHorizontalGroup(dtPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								javax.swing.GroupLayout.Alignment.TRAILING,
+								dtPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addGroup(
+												dtPanelLayout
+														.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.TRAILING)
+														.addComponent(
+																dtScrollPanel,
+																javax.swing.GroupLayout.Alignment.LEADING,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																635,
+																Short.MAX_VALUE)
+														.addComponent(
+																dtDataPanel,
+																javax.swing.GroupLayout.Alignment.LEADING,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																javax.swing.GroupLayout.DEFAULT_SIZE,
+																Short.MAX_VALUE))
+										.addContainerGap()));
+		dtPanelLayout
+				.setVerticalGroup(dtPanelLayout
+						.createParallelGroup(
+								javax.swing.GroupLayout.Alignment.LEADING)
+						.addGroup(
+								javax.swing.GroupLayout.Alignment.TRAILING,
+								dtPanelLayout
+										.createSequentialGroup()
+										.addContainerGap()
+										.addComponent(
+												dtScrollPanel,
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												300, Short.MAX_VALUE)
+										.addPreferredGap(
+												javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+										.addComponent(
+												dtDataPanel,
+												javax.swing.GroupLayout.PREFERRED_SIZE,
+												javax.swing.GroupLayout.DEFAULT_SIZE,
+												javax.swing.GroupLayout.PREFERRED_SIZE)
+										.addContainerGap()));
+
+		resultsTabbedPane.addTab(
+				resourceMap.getString("dtPanel.TabConstraints.tabTitle"),
+				dtPanel); // NOI18N
+
+		javax.swing.ActionMap actionMap = org.jdesktop.application.Application
+				.getInstance().getContext()
+				.getActionMap(ResultsView.class, this);
+
+		sliderConfidenceInterval.setValue(100);
+		sliderConfidenceInterval.setMinimum(1);
+		sliderConfidenceInterval.setName("sliderConfidenceInterval"); // NOI18N
+		sliderConfidenceInterval
+				.addMouseListener(new java.awt.event.MouseAdapter() {
+					public void mouseReleased(java.awt.event.MouseEvent evt) {
+						sliderConfidenceIntervalMouseReleased(evt);
+					}
+				});
+		sliderConfidenceInterval
+				.addChangeListener(new javax.swing.event.ChangeListener() {
+					public void stateChanged(javax.swing.event.ChangeEvent evt) {
+						sliderConfidenceIntervalStateChanged(evt);
+					}
+				});
+
+		lblConfInt.setText(resourceMap.getString("lblConfInt.text")); // NOI18N
+		lblConfInt.setName("lblConfInt"); // NOI18N
+
+		jScrollPane1.setName("jScrollPane1"); // NOI18N
+
+		lblCommandLine.setBackground(resourceMap
+				.getColor("lblCommandLine.background")); // NOI18N
+		lblCommandLine.setColumns(20);
+		lblCommandLine.setEditable(false);
+		lblCommandLine.setRows(1);
+		lblCommandLine.setBorder(null);
+		lblCommandLine.setName("lblCommandLine"); // NOI18N
+		jScrollPane1.setViewportView(lblCommandLine);
+
+		lblComandLineLabel.setText(resourceMap
+				.getString("lblComandLineLabel.text")); // NOI18N
+		lblComandLineLabel.setName("lblComandLineLabel"); // NOI18N
+
+		lblSelectedModelLabel.setText(resourceMap
+				.getString("lblSelectedModelLabel.text")); // NOI18N
+		lblSelectedModelLabel.setName("lblSelectedModelLabel"); // NOI18N
+
+		lblSelectedModel
+				.setText(resourceMap.getString("lblSelectedModel.text")); // NOI18N
+		lblSelectedModel.setName("lblSelectedModel"); // NOI18N
+
+		lblNotComplete.setBackground(resourceMap
+				.getColor("lblNotComplete.background")); // NOI18N
+		lblNotComplete.setFont(resourceMap.getFont("lblNotComplete.font")); // NOI18N
+		lblNotComplete.setForeground(resourceMap
+				.getColor("lblNotComplete.foreground")); // NOI18N
+		lblNotComplete
+				.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+		java.util.ResourceBundle bundle2 = java.util.ResourceBundle
+				.getBundle("es/uvigo/darwin/xprottest/resources/XProtTestView"); // NOI18N
+		lblNotComplete.setText(bundle2.getString("models-not-complete")); // NOI18N
+		lblNotComplete.setName("lblNotComplete"); // NOI18N
+		lblNotComplete.setOpaque(true);
+
+		lblConfidence.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT);
+		lblConfidence.setText(resourceMap.getString("lblConfidence.text")); // NOI18N
+		lblConfidence.setName("lblConfidence"); // NOI18N
+
+		btnExport.setAction(actionMap.get("exportData")); // NOI18N
+		btnExport.setName("btnExport"); // NOI18N
+
+		javax.swing.GroupLayout layout = new javax.swing.GroupLayout(
+				getContentPane());
+		getContentPane().setLayout(layout);
+		layout.setHorizontalGroup(layout
+				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+				.addGroup(
+						layout.createSequentialGroup()
+								.addContainerGap()
+								.addGroup(
+										layout.createParallelGroup(
+												javax.swing.GroupLayout.Alignment.LEADING)
+												.addComponent(
+														resultsTabbedPane,
+														javax.swing.GroupLayout.DEFAULT_SIZE,
+														671, Short.MAX_VALUE)
+												.addGroup(
+														layout.createSequentialGroup()
+																.addGroup(
+																		layout.createParallelGroup(
+																				javax.swing.GroupLayout.Alignment.LEADING)
+																				.addComponent(
+																						lblConfInt))
+																.addPreferredGap(
+																		javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																.addGroup(
+																		layout.createParallelGroup(
+																				javax.swing.GroupLayout.Alignment.TRAILING)
+																				.addGroup(
+																						javax.swing.GroupLayout.Alignment.LEADING,
+																						layout.createSequentialGroup()
+																								.addComponent(
+																										lblConfidence,
+																										javax.swing.GroupLayout.PREFERRED_SIZE,
+																										32,
+																										javax.swing.GroupLayout.PREFERRED_SIZE)
+																								.addPreferredGap(
+																										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																								.addComponent(
+																										sliderConfidenceInterval,
+																										javax.swing.GroupLayout.DEFAULT_SIZE,
+																										489,
+																										Short.MAX_VALUE))))
+
+												.addComponent(
+														lblNotComplete,
+														javax.swing.GroupLayout.Alignment.TRAILING,
+														javax.swing.GroupLayout.DEFAULT_SIZE,
+														671, Short.MAX_VALUE)
+												.addGroup(
+														layout.createSequentialGroup()
+																.addGroup(
+																		layout.createParallelGroup(
+																				javax.swing.GroupLayout.Alignment.LEADING)
+																				.addComponent(
+																						lblComandLineLabel)
+																				.addComponent(
+																						lblSelectedModelLabel))
+																.addPreferredGap(
+																		javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																.addGroup(
+																		layout.createParallelGroup(
+																				javax.swing.GroupLayout.Alignment.LEADING)
+																				.addGroup(
+																						layout.createSequentialGroup()
+																								.addComponent(
+																										lblSelectedModel,
+																										javax.swing.GroupLayout.DEFAULT_SIZE,
+																										386,
+																										Short.MAX_VALUE)
+																								.addPreferredGap(
+																										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																								.addComponent(
+																										btnExport))
+																				.addComponent(
+																						jScrollPane1,
+																						javax.swing.GroupLayout.DEFAULT_SIZE,
+																						557,
+																						Short.MAX_VALUE))))
+								.addContainerGap()));
+		layout.setVerticalGroup(layout
+				.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+				.addGroup(
+						layout.createSequentialGroup()
+								.addContainerGap()
+								.addPreferredGap(
+										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+								.addPreferredGap(
+										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+								.addPreferredGap(
+										javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+								.addGroup(
+										layout.createParallelGroup(
+												javax.swing.GroupLayout.Alignment.LEADING)
+												.addGroup(
+														layout.createParallelGroup(
+																javax.swing.GroupLayout.Alignment.BASELINE)
+																.addComponent(
+																		lblConfInt)
+																.addComponent(
+																		lblConfidence))
+												.addComponent(
+														sliderConfidenceInterval,
+														javax.swing.GroupLayout.PREFERRED_SIZE,
+														javax.swing.GroupLayout.DEFAULT_SIZE,
+														javax.swing.GroupLayout.PREFERRED_SIZE))
+								.addPreferredGap(
+										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+								.addComponent(lblNotComplete)
+								.addPreferredGap(
+										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+								.addComponent(resultsTabbedPane,
+										javax.swing.GroupLayout.DEFAULT_SIZE,
+										496, Short.MAX_VALUE)
+								.addPreferredGap(
+										javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+								.addGroup(
+										layout.createParallelGroup(
+												javax.swing.GroupLayout.Alignment.BASELINE)
+												.addComponent(
+														lblSelectedModelLabel)
+												.addComponent(lblSelectedModel)
+												.addComponent(btnExport))
+								.addGroup(
+										layout.createParallelGroup(
+												javax.swing.GroupLayout.Alignment.LEADING)
+												.addGroup(
+														layout.createSequentialGroup()
+																.addGap(11, 11,
+																		11)
+																.addComponent(
+																		lblComandLineLabel))
+												.addGroup(
+														layout.createSequentialGroup()
+																.addPreferredGap(
+																		javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+																.addComponent(
+																		jScrollPane1,
+																		javax.swing.GroupLayout.PREFERRED_SIZE,
+																		42,
+																		javax.swing.GroupLayout.PREFERRED_SIZE)))
+								.addContainerGap()));
+
+		pack();
+	}// </editor-fold>//GEN-END:initComponents
+
+	private void sliderConfidenceIntervalStateChanged(
+			javax.swing.event.ChangeEvent evt) {// GEN-FIRST:event_sliderConfidenceIntervalStateChanged
+		double confidenceInterval = Double.parseDouble(sliderConfidenceInterval
+				.getValue() + "") / 100;
+		lblConfidence.setText(String.valueOf(confidenceInterval));
+	}// GEN-LAST:event_sliderConfidenceIntervalStateChanged
+
+	private void sliderConfidenceIntervalMouseReleased(
+			java.awt.event.MouseEvent evt) {// GEN-FIRST:event_sliderConfidenceIntervalMouseReleased
+		double confidenceInterval = Double.parseDouble(sliderConfidenceInterval
+				.getValue() + "") / 100;
+		loadCache(confidenceInterval);
+		fillInResults();
+	}// GEN-LAST:event_sliderConfidenceIntervalMouseReleased
+		// Variables declaration - do not modify//GEN-BEGIN:variables
+
+	private javax.swing.JPanel aicDataPanel;
+	private javax.swing.JPanel aicPanel;
+	private javax.swing.JScrollPane aicScrollPanel;
+	private javax.swing.JTable aicTable;
+	private javax.swing.JPanel aiccDataPanel;
+	private javax.swing.JPanel aiccPanel;
+	private javax.swing.JScrollPane aiccScrollPanel;
+	private javax.swing.JTable aiccTable;
+	private javax.swing.JPanel bicDataPanel;
+	private javax.swing.JPanel bicPanel;
+	private javax.swing.JScrollPane bicScrollPanel;
+	private javax.swing.JTable bicTable;
+	private javax.swing.JButton btnExport;
+	private javax.swing.JLabel displayAICImpAlpha;
+	private javax.swing.JLabel displayAICImpAlphaInv;
+	private javax.swing.JLabel displayAICImpF;
+	private javax.swing.JLabel displayAICImpInv;
+	private javax.swing.JLabel displayAICcImpAlpha;
+	private javax.swing.JLabel displayAICcImpAlphaInv;
+	private javax.swing.JLabel displayAICcImpF;
+	private javax.swing.JLabel displayAICcImpInv;
+	private javax.swing.JLabel displayAICcoAlpha;
+	private javax.swing.JLabel displayAICcoAlphaInv;
+	private javax.swing.JLabel displayAICcoInv;
+	private javax.swing.JLabel displayAICcoInvAlpha;
+	private javax.swing.JLabel displayAICoAlpha;
+	private javax.swing.JLabel displayAICoAlphaInv;
+	private javax.swing.JLabel displayAICoInv;
+	private javax.swing.JLabel displayAICoInvAlpha;
+	private javax.swing.JLabel displayBICImpAlpha;
+	private javax.swing.JLabel displayBICImpAlphaInv;
+	private javax.swing.JLabel displayBICImpF;
+	private javax.swing.JLabel displayBICImpInv;
+	private javax.swing.JLabel displayBICoAlpha;
+	private javax.swing.JLabel displayBICoAlphaInv;
+	private javax.swing.JLabel displayBICoInv;
+	private javax.swing.JLabel displayBICoInvAlpha;
+	private javax.swing.JLabel displayDTImpAlpha;
+	private javax.swing.JLabel displayDTImpAlphaInv;
+	private javax.swing.JLabel displayDTImpF;
+	private javax.swing.JLabel displayDTImpInv;
+	private javax.swing.JLabel displayDToAlpha;
+	private javax.swing.JLabel displayDToAlphaInv;
+	private javax.swing.JLabel displayDToInv;
+	private javax.swing.JLabel displayDToInvAlpha;
+	private javax.swing.JPanel dtDataPanel;
+	private javax.swing.JPanel dtPanel;
+	private javax.swing.JScrollPane dtScrollPanel;
+	private javax.swing.JTable dtTable;
+	private javax.swing.JScrollPane jScrollPane1;
+	private javax.swing.JLabel lblAICImpAlpha;
+	private javax.swing.JLabel lblAICImpAlphaInv;
+	private javax.swing.JLabel lblAICImpF;
+	private javax.swing.JLabel lblAICImpInv;
+	private javax.swing.JLabel lblAICOverall;
+	private javax.swing.JLabel lblAICOverallAlpha;
+	private javax.swing.JLabel lblAICOverallAlphaInv;
+	private javax.swing.JLabel lblAICOverallInv;
+	private javax.swing.JLabel lblAICOverallInvAlpha;
+	private javax.swing.JLabel lblAICPI;
+	private javax.swing.JLabel lblAICcImpAlpha;
+	private javax.swing.JLabel lblAICcImpAlphaInv;
+	private javax.swing.JLabel lblAICcImpF;
+	private javax.swing.JLabel lblAICcImpInv;
+	private javax.swing.JLabel lblAICcOverall;
+	private javax.swing.JLabel lblAICcOverallAlpha;
+	private javax.swing.JLabel lblAICcOverallAlphaInv;
+	private javax.swing.JLabel lblAICcOverallInv;
+	private javax.swing.JLabel lblAICcOverallInvAlpha;
+	private javax.swing.JLabel lblAICcPI;
+	private javax.swing.JLabel lblBICImpAlpha;
+	private javax.swing.JLabel lblBICImpAlphaInv;
+	private javax.swing.JLabel lblBICImpF;
+	private javax.swing.JLabel lblBICImpInv;
+	private javax.swing.JLabel lblBICOverall;
+	private javax.swing.JLabel lblBICOverallAlpha;
+	private javax.swing.JLabel lblBICOverallAlphaInv;
+	private javax.swing.JLabel lblBICOverallInv;
+	private javax.swing.JLabel lblBICOverallInvAlpha;
+	private javax.swing.JLabel lblBICPI;
+	private javax.swing.JLabel lblComandLineLabel;
+	private javax.swing.JTextArea lblCommandLine;
+	private javax.swing.JLabel lblConfInt;
+	private javax.swing.JLabel lblConfidence;
+	private javax.swing.JLabel lblDTImpAlpha;
+	private javax.swing.JLabel lblDTImpAlphaInv;
+	private javax.swing.JLabel lblDTImpF;
+	private javax.swing.JLabel lblDTImpInv;
+	private javax.swing.JLabel lblDTOverall;
+	private javax.swing.JLabel lblDTOverallAlpha;
+	private javax.swing.JLabel lblDTOverallAlphaInv;
+	private javax.swing.JLabel lblDTOverallInv;
+	private javax.swing.JLabel lblDTOverallInvAlpha;
+	private javax.swing.JLabel lblDTPI;
+	private javax.swing.JLabel lblNotComplete;
+	private javax.swing.JLabel lblSelectedModel;
+	private javax.swing.JLabel lblSelectedModelLabel;
+	private javax.swing.JTabbedPane resultsTabbedPane;
+	private javax.swing.JSlider sliderConfidenceInterval;
+
+	// End of variables declaration//GEN-END:variables
+
+	private void fillInResults() {
+
+		Collection<SelectionModel> aicIt = aicResults.getConfidenceModels();
+		Collection<SelectionModel> bicIt = bicResults.getConfidenceModels();
+		Collection<SelectionModel> aiccIt = aiccResults.getConfidenceModels();
+		Collection<SelectionModel> dtIt = dtResults.getConfidenceModels();
+
+		aicTableModel.setRowCount(aicIt.size());
+		fillTable(aicIt, aicTable);
+
+		displayAICoAlpha.setText(getDisplayValue(aicResults.getOverallAlpha(),
+				PARAMETER_G, aicResults.existGammaModels()));
+		displayAICoAlphaInv.setText(getDisplayValue(
+				aicResults.getOverallAlphaInv(), PARAMETER_IG,
+				aicResults.existGammaInvModels()));
+		displayAICoInvAlpha.setText(getDisplayValue(
+				aicResults.getOverallInvAlpha(), PARAMETER_IG,
+				aicResults.existGammaInvModels()));
+		displayAICoInv.setText(getDisplayValue(aicResults.getOverallInv(),
+				PARAMETER_I, aicResults.existInvModels()));
+		displayAICImpAlpha.setText(getDisplayValue(
+				aicResults.getAlphaImportance(), PARAMETER_G,
+				aicResults.existGammaModels()));
+		displayAICImpInv.setText(getDisplayValue(aicResults.getInvImportance(),
+				PARAMETER_I, aicResults.existInvModels()));
+		displayAICImpAlphaInv.setText(getDisplayValue(
+				aicResults.getAlphaInvImportance(), PARAMETER_IG,
+				aicResults.existGammaInvModels()));
+		displayAICImpF.setText(getDisplayValue(aicResults.getFImportance(),
+				PARAMETER_F, aicResults.existFModels()));
+
+		bicTableModel.setRowCount(bicIt.size());
+		fillTable(bicIt, bicTable);
+
+		displayBICoAlpha.setText(getDisplayValue(bicResults.getOverallAlpha(),
+				PARAMETER_G, bicResults.existGammaModels()));
+		displayBICoAlphaInv.setText(getDisplayValue(
+				bicResults.getOverallAlphaInv(), PARAMETER_IG,
+				bicResults.existGammaInvModels()));
+		displayBICoInvAlpha.setText(getDisplayValue(
+				bicResults.getOverallInvAlpha(), PARAMETER_IG,
+				bicResults.existGammaInvModels()));
+		displayBICoInv.setText(getDisplayValue(bicResults.getOverallInv(),
+				PARAMETER_I, bicResults.existInvModels()));
+		displayBICImpAlpha.setText(getDisplayValue(
+				bicResults.getAlphaImportance(), PARAMETER_G,
+				bicResults.existGammaModels()));
+		displayBICImpInv.setText(getDisplayValue(bicResults.getInvImportance(),
+				PARAMETER_I, bicResults.existInvModels()));
+		displayBICImpAlphaInv.setText(getDisplayValue(
+				bicResults.getAlphaInvImportance(), PARAMETER_IG,
+				bicResults.existGammaInvModels()));
+		displayBICImpF.setText(getDisplayValue(bicResults.getFImportance(),
+				PARAMETER_F, bicResults.existFModels()));
+
+		aiccTableModel.setRowCount(aiccIt.size());
+		fillTable(aiccIt, aiccTable);
+
+		displayAICcoAlpha.setText(getDisplayValue(
+				aiccResults.getOverallAlpha(), PARAMETER_G,
+				aiccResults.existGammaModels()));
+		displayAICcoAlphaInv.setText(getDisplayValue(
+				aiccResults.getOverallAlphaInv(), PARAMETER_IG,
+				aiccResults.existGammaInvModels()));
+		displayAICcoInvAlpha.setText(getDisplayValue(
+				aiccResults.getOverallInvAlpha(), PARAMETER_IG,
+				aiccResults.existGammaInvModels()));
+		displayAICcoInv.setText(getDisplayValue(aiccResults.getOverallInv(),
+				PARAMETER_I, aiccResults.existInvModels()));
+		displayAICcImpAlpha.setText(getDisplayValue(
+				aiccResults.getAlphaImportance(), PARAMETER_G,
+				aiccResults.existGammaModels()));
+		displayAICcImpInv.setText(getDisplayValue(
+				aiccResults.getInvImportance(), PARAMETER_I,
+				aiccResults.existInvModels()));
+		displayAICcImpAlphaInv.setText(getDisplayValue(
+				aiccResults.getAlphaInvImportance(), PARAMETER_IG,
+				aiccResults.existGammaInvModels()));
+		displayAICcImpF.setText(getDisplayValue(aiccResults.getFImportance(),
+				PARAMETER_F, aiccResults.existFModels()));
+
+		dtTableModel.setRowCount(dtIt.size());
+		fillTable(dtIt, dtTable);
+
+		displayDToAlpha.setText(getDisplayValue(dtResults.getOverallAlpha(),
+				PARAMETER_G, dtResults.existGammaModels()));
+		displayDToAlphaInv.setText(getDisplayValue(
+				dtResults.getOverallAlphaInv(), PARAMETER_IG,
+				dtResults.existGammaInvModels()));
+		displayDToInvAlpha.setText(getDisplayValue(
+				dtResults.getOverallInvAlpha(), PARAMETER_IG,
+				dtResults.existGammaInvModels()));
+		displayDToInv.setText(getDisplayValue(dtResults.getOverallInv(),
+				PARAMETER_I, dtResults.existInvModels()));
+		displayDTImpAlpha.setText(getDisplayValue(
+				dtResults.getAlphaImportance(), PARAMETER_G,
+				dtResults.existGammaModels()));
+		displayDTImpInv.setText(getDisplayValue(dtResults.getInvImportance(),
+				PARAMETER_I, dtResults.existInvModels()));
+		displayDTImpAlphaInv.setText(getDisplayValue(
+				dtResults.getAlphaInvImportance(), PARAMETER_IG,
+				dtResults.existGammaInvModels()));
+		displayDTImpF.setText(getDisplayValue(dtResults.getFImportance(),
+				PARAMETER_F, dtResults.existFModels()));
+	}
+
+	private void fillTable(Collection<SelectionModel> iterator, JTable table) {
+		int row = 0;
+		for (SelectionModel model : iterator) {
+			table.setValueAt(model.getModel().getModelName(), row, 0);
+			table.setValueAt(model.getModel().getLk(), row, 1);
+			try {
+				table.setValueAt(
+						new Double(ProtTestFormattedOutput.getDecimalString(
+								model.getValue(), CRITERION_PRECISSION)), row,
+						2);
+				table.setValueAt(
+						new Double(ProtTestFormattedOutput.getDecimalString(
+								model.getDeltaValue(), CRITERION_PRECISSION)),
+						row, 3);
+				table.setValueAt(
+						new Double(ProtTestFormattedOutput.getDecimalString(
+								model.getWeightValue(), CRITERION_PRECISSION)),
+						row, 4);
+			} catch (NumberFormatException e) {
+				table.setValueAt(Double.NaN, row, 2);
+				table.setValueAt(Double.NaN, row, 3);
+				table.setValueAt(Double.NaN, row, 4);
+			}
+			row++;
+		}
+	}
+
+	private void showCommandLine(String modelName) {
+		for (Model model : models) {
+			if (model.getModelName().equals(modelName)) {
+				lblSelectedModel.setText(modelName);
+				StringBuilder command = new StringBuilder();
+				for (int i = 1; i < model.getCommandLine().length; i++) {
+					command.append(model.getCommandLine()[i]).append(" ");
+				}
+				lblCommandLine.setText(command.toString());
+				break;
+			}
+		}
+	}
+
+	class SelectionListener implements ListSelectionListener {
+
+		JTable table;
+
+		// It is necessary to keep the table since it is not possible
+		// to determine the table from the event's source
+		SelectionListener(JTable table) {
+			this.table = table;
+		}
+
+		public void valueChanged(ListSelectionEvent e) {
+			// If cell selection is enabled, both row and column change events
+			// are fired
+			int first = 0, last = 0;
+			if (e.getSource() == table.getSelectionModel()
+					&& table.getRowSelectionAllowed()) {
+				// Column selection changed
+				first = e.getFirstIndex();
+				last = e.getLastIndex();
+			} else if (e.getSource() == table.getColumnModel()
+					.getSelectionModel() && table.getColumnSelectionAllowed()) {
+				// Row selection changed
+				first = e.getFirstIndex();
+				last = e.getLastIndex();
+			}
+
+			if (e.getValueIsAdjusting()) {
+				// The mouse button has not yet been released
+			} else {
+				try {
+					showCommandLine(table.getValueAt(table.getSelectedRow(), 0)
+							.toString());
+				} catch (IndexOutOfBoundsException ex) {
+					// Clear
+					lblCommandLine.setText("");
+					lblSelectedModel.setText("");
+				}
+			}
+		}
+	}
+
+	// private String getDisplayValue(double value, String parameter) {
+	// String toDisplay;
+	// boolean existModels = false;
+	// if (parameter.equals(PARAMETER_I)) {
+	// existModels = existInvModels;
+	// } else if (parameter.equals(PARAMETER_G)) {
+	// existModels = existGammaModels;
+	// } else if (parameter.equals(PARAMETER_IG)) {
+	// existModels = existGammaInvModels;
+	// } else if (parameter.equals(PARAMETER_F)) {
+	// existModels = existFModels;
+	// }
+	//
+	// if (existModels) {
+	// toDisplay = ProtTestFormattedOutput.getDecimalString(value,
+	// IMPORTANCE_PRECISSION);
+	// } else {
+	// toDisplay = "No " + parameter + " models";
+	// }
+	// return toDisplay;
+	// }
+
+	@Action
+	public void exportData() {
+		InformationCriterion ic = null;
+		switch (resultsTabbedPane.getSelectedIndex()) {
+		case AIC_TAB:
+			ic = aicResults.getInformationCriterion();
+			break;
+		case BIC_TAB:
+			ic = bicResults.getInformationCriterion();
+			break;
+		case AICC_TAB:
+			ic = aiccResults.getInformationCriterion();
+			break;
+		case DT_TAB:
+			ic = dtResults.getInformationCriterion();
+			break;
+		}
+		if (ic != null) {
+			mainFrame.enableHandler();
+			ProtTestPrinter
+					.printSelectionHeader(CRITERION_NAMES[resultsTabbedPane
+							.getSelectedIndex()]);
+			mainFrame.getFacade().printModelsSorted(ic);
+			mainFrame.disableHandler();
+		}
+	}
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/results/resources/ErrorLogView.properties b/src/main/java/es/uvigo/darwin/xprottest/results/resources/ErrorLogView.properties
new file mode 100755
index 0000000..234ec39
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/results/resources/ErrorLogView.properties
@@ -0,0 +1,6 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+#NOI18N
+errorTextArea.font=Dialog 12 12 Plain
+Form.title=Error Log
diff --git a/src/main/java/es/uvigo/darwin/xprottest/results/resources/ResultsView.properties b/src/main/java/es/uvigo/darwin/xprottest/results/resources/ResultsView.properties
new file mode 100755
index 0000000..2977391
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/results/resources/ResultsView.properties
@@ -0,0 +1,78 @@
+aiccPanel.TabConstraints.tabTitle=AICc
+aiccScrollPanel.TabConstraints.tabTitle=AICc
+aicPanel.TabConstraints.tabTitle=AIC
+aicScrollPanel.TabConstraints.tabTitle=AIC
+bicPanel.TabConstraints.tabTitle=BIC
+bicScrollPanel.TabConstraints.tabTitle=BIC
+btnExport=Export to main console
+displayAICcImpAlphaInv.text=+I+G Imp
+displayAICcImpAlpha.text=+G Imp
+displayAICcImpF.text=+F Imp
+displayAICcImpInv.text=+I Imp
+displayAICcoAlphaInv.text=AICc-AI
+displayAICcoAlpha.text=AICc-Alpha
+displayAICcoInvAlpha.text=AICc-IA
+displayAICcoInv.text=AICc-Inv
+displayAICImpAlphaInv.text=+I+G Imp
+displayAICImpAlpha.text=+G Imp
+displayAICImpF.text=+F Imp
+displayAICImpInv.text=+I Imp
+displayAICoAlphaInv.text=AIC-AI
+displayAICoAlpha.text=AIC-Alpha
+displayAICoInvAlpha.text=AIC-IA
+displayAICoInv.text=AIC-Inv
+displayBICImpAlphaInv.text=+I+G Imp
+displayBICImpAlpha.text=+G Imp
+displayBICImpF.text=+F Imp
+displayBICImpInv.text=+I Imp
+displayBICoAlphaInv.text=BIC-AI
+displayBICoAlpha.text=BIC-Alpha
+displayBICoInvAlpha.text=BIC-IA
+displayBICoInv.text=BIC-Inv
+displayDTImpAlphaInv.text=+I+G Imp
+displayDTImpAlpha.text=+G Imp
+displayDTImpF.text=+F Imp
+displayDTImpInv.text=+I Imp
+displayDToAlphaInv.text=DT-AI
+displayDToAlpha.text=DT-Alpha
+displayDToInvAlpha.text=DT-IA
+displayDToInv.text=DT-Inv
+dtPanel.TabConstraints.tabTitle=DT
+exportData.Action.shortDescription=Export to main console
+exportData.Action.text=Export to main console
+export-data=Export to main console
+Form.title=Results
+lblAICcImpAlphaInv.text=+I+G
+lblAICcImpAlpha.text=+G
+lblAICcImpF.text=+F
+lblAICcImpInv.text=+I
+lblAICcPI.text=Parameter Importance
+lblAICImpAlphaInv.text=+I+G
+lblAICImpAlpha.text=+G
+lblAICImpF.text=+F
+lblAICImpInv.text=+I
+lblAICPI.text=Parameter Importance
+lblBICImpAlphaInv.text=+I+G
+lblBICImpAlpha.text=+G
+lblBICImpF.text=+F
+lblBICImpInv.text=+I
+lblBICPI.text=Parameter Importance
+lblComandLineLabel.text=Command Line:
+lblCommandLine.background=235, 237, 237
+lblConfidence.text=1.0
+lblConfInt.text=Confidence Interval:
+lblDTImpAlphaInv.text=+I+G
+lblDTImpAlpha.text=+G
+lblDTImpF.text=+F
+lblDTImpInv.text=+I
+lblDTPI.text=Parameter Importance
+lblNotComplete.background=255, 0, 51
+lblNotComplete.font=Dialog-Plain-12
+lblNotComplete.foreground=0, 0, 0
+lbl-overall-alpha=Alpha
+lbl-overall-alpha-inv=Alpha-Inv
+lbl-overall-inv-alpha=Inv-Alpha
+lbl-overall-inv=Inv
+lbl-overall=Model-averaged estimates
+lblSelectedModelLabel.text=Selected Model:
+lblSelectedModel.text=
diff --git a/src/main/java/es/uvigo/darwin/xprottest/util/BrowserLauncher.java b/src/main/java/es/uvigo/darwin/xprottest/util/BrowserLauncher.java
new file mode 100755
index 0000000..1ee8533
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/util/BrowserLauncher.java
@@ -0,0 +1,583 @@
+package es.uvigo.darwin.xprottest.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * BrowserLauncher is a class that provides one static method, openURL, which opens the default
+ * web browser for the current user of the system to the given URL.  It may support other
+ * protocols depending on the system -- mailto, ftp, etc. -- but that has not been rigorously
+ * tested and is not guaranteed to work.
+ * <p>
+ * Yes, this is platform-specific code, and yes, it may rely on classes on certain platforms
+ * that are not part of the standard JDK.  What we're trying to do, though, is to take something
+ * that's frequently desirable but inherently platform-specific -- opening a default browser --
+ * and allow programmers (you, for example) to do so without worrying about dropping into native
+ * code or doing anything else similarly evil.
+ * <p>
+ * Anyway, this code is completely in Java and will run on all JDK 1.1-compliant systems without
+ * modification or a need for additional libraries.  All classes that are required on certain
+ * platforms to allow this to run are dynamically loaded at runtime via reflection and, if not
+ * found, will not cause this to do anything other than returning an error when opening the
+ * browser.
+ * <p>
+ * There are certain system requirements for this class, as it's running through Runtime.exec(),
+ * which is Java's way of making a native system call.  Currently, this requires that a Macintosh
+ * have a Finder which supports the GURL event, which is true for Mac OS 8.0 and 8.1 systems that
+ * have the Internet Scripting AppleScript dictionary installed in the Scripting Additions folder
+ * in the Extensions folder (which is installed by default as far as I know under Mac OS 8.0 and
+ * 8.1), and for all Mac OS 8.5 and later systems.  On Windows, it only runs under Win32 systems
+ * (Windows 95, 98, and NT 4.0, as well as later versions of all).  On other systems, this drops
+ * back from the inherently platform-sensitive concept of a default browser and simply attempts
+ * to launch Netscape via a shell command.
+ * <p>
+ * This code is Copyright 1999-2001 by Eric Albert (ejalbert at cs.stanford.edu) and may be
+ * redistributed or modified in any form without restrictions as long as the portion of this
+ * comment from this paragraph through the end of the comment is not removed.  The author
+ * requests that he be notified of any application, applet, or other binary that makes use of
+ * this code, but that's more out of curiosity than anything and is not required.  This software
+ * includes no warranty.  The author is not repsonsible for any loss of data or functionality
+ * or any adverse or unexpected effects of using this software.
+ * <p>
+ * Credits:
+ * <br>Steven Spencer, JavaWorld magazine (<a href="http://www.javaworld.com/javaworld/javatips/jw-javatip66.html">Java Tip 66</a>)
+ * <br>Thanks also to Ron B. Yeh, Eric Shapiro, Ben Engber, Paul Teitlebaum, Andrea Cantatore,
+ * Larry Barowski, Trevor Bedzek, Frank Miedrich, and Ron Rabakukk
+ *
+ * @author Eric Albert (<a href="mailto:ejalbert at cs.stanford.edu">ejalbert at cs.stanford.edu</a>)
+ * @version 1.4b1 (Released June 20, 2001)
+ */
+public class BrowserLauncher {
+
+	/**
+	 * The Java virtual machine that we are running on.  Actually, in most cases we only care
+	 * about the operating system, but some operating systems require us to switch on the VM. */
+	private static int jvm;
+
+	/** The browser for the system */
+	private static Object browser;
+
+	/**
+	 * Caches whether any classes, methods, and fields that are not part of the JDK and need to
+	 * be dynamically loaded at runtime loaded successfully.
+	 * <p>
+	 * Note that if this is <code>false</code>, <code>openURL()</code> will always return an
+	 * IOException.
+	 */
+	private static boolean loadedWithoutErrors;
+
+	/** The com.apple.mrj.MRJFileUtils class */
+	private static Class mrjFileUtilsClass;
+
+	/** The com.apple.mrj.MRJOSType class */
+	private static Class mrjOSTypeClass;
+
+	/** The com.apple.MacOS.AEDesc class */
+	private static Class aeDescClass;
+
+	/** The <init>(int) method of com.apple.MacOS.AETarget */
+	private static Constructor aeTargetConstructor;
+
+	/** The <init>(int, int, int) method of com.apple.MacOS.AppleEvent */
+	private static Constructor appleEventConstructor;
+
+	/** The <init>(String) method of com.apple.MacOS.AEDesc */
+	private static Constructor aeDescConstructor;
+
+	/** The findFolder method of com.apple.mrj.MRJFileUtils */
+	private static Method findFolder;
+
+	/** The getFileCreator method of com.apple.mrj.MRJFileUtils */
+	private static Method getFileCreator;
+
+	/** The getFileType method of com.apple.mrj.MRJFileUtils */
+	private static Method getFileType;
+
+	/** The openURL method of com.apple.mrj.MRJFileUtils */
+	private static Method openURL;
+
+	/** The makeOSType method of com.apple.MacOS.OSUtils */
+	private static Method makeOSType;
+
+	/** The putParameter method of com.apple.MacOS.AppleEvent */
+	private static Method putParameter;
+
+	/** The sendNoReply method of com.apple.MacOS.AppleEvent */
+	private static Method sendNoReply;
+
+	/** Actually an MRJOSType pointing to the System Folder on a Macintosh */
+	private static Object kSystemFolderType;
+
+	/** The keyDirectObject AppleEvent parameter type */
+	private static Integer keyDirectObject;
+
+	/** The kAutoGenerateReturnID AppleEvent code */
+	private static Integer kAutoGenerateReturnID;
+
+	/** The kAnyTransactionID AppleEvent code */
+	private static Integer kAnyTransactionID;
+
+	/** The linkage object required for JDirect 3 on Mac OS X. */
+	private static Object linkage;
+
+	/** The framework to reference on Mac OS X */
+	private static final String JDirect_MacOSX = "/System/Library/Frameworks/Carbon.framework/Frameworks/HIToolbox.framework/HIToolbox";
+
+	/** JVM constant for MRJ 2.0 */
+	private static final int MRJ_2_0 = 0;
+
+	/** JVM constant for MRJ 2.1 or later */
+	private static final int MRJ_2_1 = 1;
+
+	/** JVM constant for Java on Mac OS X 10.0 (MRJ 3.0) */
+	private static final int MRJ_3_0 = 3;
+
+	/** JVM constant for MRJ 3.1 */
+	private static final int MRJ_3_1 = 4;
+
+	/** JVM constant for any Windows NT JVM */
+	private static final int WINDOWS_NT = 5;
+
+	/** JVM constant for any Windows 9x JVM */
+	private static final int WINDOWS_9x = 6;
+
+	/** JVM constant for any other platform */
+	private static final int OTHER = -1;
+
+	/**
+	 * The file type of the Finder on a Macintosh.  Hardcoding "Finder" would keep non-U.S. English
+	 * systems from working properly.
+	 */
+	private static final String FINDER_TYPE = "FNDR";
+
+	/**
+	 * The creator code of the Finder on a Macintosh, which is needed to send AppleEvents to the
+	 * application.
+	 */
+	private static final String FINDER_CREATOR = "MACS";
+
+	/** The name for the AppleEvent type corresponding to a GetURL event. */
+	private static final String GURL_EVENT = "GURL";
+
+	/**
+	 * The first parameter that needs to be passed into Runtime.exec() to open the default web
+	 * browser on Windows.
+	 */
+    private static final String FIRST_WINDOWS_PARAMETER = "/c";
+
+    /** The second parameter for Runtime.exec() on Windows. */
+    private static final String SECOND_WINDOWS_PARAMETER = "start";
+
+    /**
+     * The third parameter for Runtime.exec() on Windows.  This is a "title"
+     * parameter that the command line expects.  Setting this parameter allows
+     * URLs containing spaces to work.
+     */
+    private static final String THIRD_WINDOWS_PARAMETER = "\"\"";
+
+	/**
+	 * The shell parameters for Netscape that opens a given URL in an already-open copy of Netscape
+	 * on many command-line systems.
+	 */
+	private static final String NETSCAPE_REMOTE_PARAMETER = "-remote";
+	private static final String NETSCAPE_OPEN_PARAMETER_START = "'openURL(";
+	private static final String NETSCAPE_OPEN_PARAMETER_END = ")'";
+
+	/**
+	 * The message from any exception thrown throughout the initialization process.
+	 */
+	private static String errorMessage;
+
+	/**
+	 * An initialization block that determines the operating system and loads the necessary
+	 * runtime data.
+	 */
+	static {
+		loadedWithoutErrors = true;
+		String osName = System.getProperty("os.name");
+		if (osName.startsWith("Mac OS")) {
+			String mrjVersion = System.getProperty("mrj.version");
+			String majorMRJVersion = mrjVersion.substring(0, 3);
+			try {
+				double version = Double.valueOf(majorMRJVersion).doubleValue();
+				if (version == 2) {
+					jvm = MRJ_2_0;
+				} else if (version >= 2.1 && version < 3) {
+					// Assume that all 2.x versions of MRJ work the same.  MRJ 2.1 actually
+					// works via Runtime.exec() and 2.2 supports that but has an openURL() method
+					// as well that we currently ignore.
+					jvm = MRJ_2_1;
+				} else if (version == 3.0) {
+					jvm = MRJ_3_0;
+				} else if (version >= 3.1) {
+					// Assume that all 3.1 and later versions of MRJ work the same.
+					jvm = MRJ_3_1;
+				} else {
+					loadedWithoutErrors = false;
+					errorMessage = "Unsupported MRJ version: " + version;
+				}
+			} catch (NumberFormatException nfe) {
+				loadedWithoutErrors = false;
+				errorMessage = "Invalid MRJ version: " + mrjVersion;
+			}
+		} else if (osName.startsWith("Windows")) {
+			if (osName.indexOf("9") != -1) {
+				jvm = WINDOWS_9x;
+			} else {
+				jvm = WINDOWS_NT;
+			}
+		} else {
+			jvm = OTHER;
+		}
+
+		if (loadedWithoutErrors) {	// if we haven't hit any errors yet
+			loadedWithoutErrors = loadClasses();
+		}
+	}
+
+	/**
+	 * This class should be never be instantiated; this just ensures so.
+	 */
+	private BrowserLauncher() { }
+
+	/**
+	 * Called by a static initializer to load any classes, fields, and methods required at runtime
+	 * to locate the user's web browser.
+	 * @return <code>true</code> if all intialization succeeded
+	 *			<code>false</code> if any portion of the initialization failed
+	 */
+	private static boolean loadClasses() {
+		switch (jvm) {
+			case MRJ_2_0:
+				try {
+					Class aeTargetClass = Class.forName("com.apple.MacOS.AETarget");
+					Class osUtilsClass = Class.forName("com.apple.MacOS.OSUtils");
+					Class appleEventClass = Class.forName("com.apple.MacOS.AppleEvent");
+					Class aeClass = Class.forName("com.apple.MacOS.ae");
+					aeDescClass = Class.forName("com.apple.MacOS.AEDesc");
+
+					aeTargetConstructor = aeTargetClass.getDeclaredConstructor(new Class [] { int.class });
+					appleEventConstructor = appleEventClass.getDeclaredConstructor(new Class[] { int.class, int.class, aeTargetClass, int.class, int.class });
+					aeDescConstructor = aeDescClass.getDeclaredConstructor(new Class[] { String.class });
+
+					makeOSType = osUtilsClass.getDeclaredMethod("makeOSType", new Class [] { String.class });
+					putParameter = appleEventClass.getDeclaredMethod("putParameter", new Class[] { int.class, aeDescClass });
+					sendNoReply = appleEventClass.getDeclaredMethod("sendNoReply", new Class[] { });
+
+					Field keyDirectObjectField = aeClass.getDeclaredField("keyDirectObject");
+					keyDirectObject = (Integer) keyDirectObjectField.get(null);
+					Field autoGenerateReturnIDField = appleEventClass.getDeclaredField("kAutoGenerateReturnID");
+					kAutoGenerateReturnID = (Integer) autoGenerateReturnIDField.get(null);
+					Field anyTransactionIDField = appleEventClass.getDeclaredField("kAnyTransactionID");
+					kAnyTransactionID = (Integer) anyTransactionIDField.get(null);
+				} catch (ClassNotFoundException cnfe) {
+					errorMessage = cnfe.getMessage();
+					return false;
+				} catch (NoSuchMethodException nsme) {
+					errorMessage = nsme.getMessage();
+					return false;
+				} catch (NoSuchFieldException nsfe) {
+					errorMessage = nsfe.getMessage();
+					return false;
+				} catch (IllegalAccessException iae) {
+					errorMessage = iae.getMessage();
+					return false;
+				}
+				break;
+			case MRJ_2_1:
+				try {
+					mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
+					mrjOSTypeClass = Class.forName("com.apple.mrj.MRJOSType");
+					Field systemFolderField = mrjFileUtilsClass.getDeclaredField("kSystemFolderType");
+					kSystemFolderType = systemFolderField.get(null);
+					findFolder = mrjFileUtilsClass.getDeclaredMethod("findFolder", new Class[] { mrjOSTypeClass });
+					getFileCreator = mrjFileUtilsClass.getDeclaredMethod("getFileCreator", new Class[] { File.class });
+					getFileType = mrjFileUtilsClass.getDeclaredMethod("getFileType", new Class[] { File.class });
+				} catch (ClassNotFoundException cnfe) {
+					errorMessage = cnfe.getMessage();
+					return false;
+				} catch (NoSuchFieldException nsfe) {
+					errorMessage = nsfe.getMessage();
+					return false;
+				} catch (NoSuchMethodException nsme) {
+					errorMessage = nsme.getMessage();
+					return false;
+				} catch (SecurityException se) {
+					errorMessage = se.getMessage();
+					return false;
+				} catch (IllegalAccessException iae) {
+					errorMessage = iae.getMessage();
+					return false;
+				}
+				break;
+			case MRJ_3_0:
+			    try {
+					Class linker = Class.forName("com.apple.mrj.jdirect.Linker");
+					Constructor constructor = linker.getConstructor(new Class[]{ Class.class });
+					linkage = constructor.newInstance(new Object[] { BrowserLauncher.class });
+				} catch (ClassNotFoundException cnfe) {
+					errorMessage = cnfe.getMessage();
+					return false;
+				} catch (NoSuchMethodException nsme) {
+					errorMessage = nsme.getMessage();
+					return false;
+				} catch (InvocationTargetException ite) {
+					errorMessage = ite.getMessage();
+					return false;
+				} catch (InstantiationException ie) {
+					errorMessage = ie.getMessage();
+					return false;
+				} catch (IllegalAccessException iae) {
+					errorMessage = iae.getMessage();
+					return false;
+				}
+				break;
+			case MRJ_3_1:
+				try {
+					mrjFileUtilsClass = Class.forName("com.apple.mrj.MRJFileUtils");
+					openURL = mrjFileUtilsClass.getDeclaredMethod("openURL", new Class[] { String.class });
+				} catch (ClassNotFoundException cnfe) {
+					errorMessage = cnfe.getMessage();
+					return false;
+				} catch (NoSuchMethodException nsme) {
+					errorMessage = nsme.getMessage();
+					return false;
+				}
+				break;
+			default:
+			    break;
+		}
+		return true;
+	}
+
+	/**
+	 * Attempts to locate the default web browser on the local system.  Caches results so it
+	 * only locates the browser once for each use of this class per JVM instance.
+	 * @return The browser for the system.  Note that this may not be what you would consider
+	 *			to be a standard web browser; instead, it's the application that gets called to
+	 *			open the default web browser.  In some cases, this will be a non-String object
+	 *			that provides the means of calling the default browser.
+	 */
+	private static Object locateBrowser() {
+		if (browser != null) {
+			return browser;
+		}
+		switch (jvm) {
+			case MRJ_2_0:
+				try {
+					Integer finderCreatorCode = (Integer) makeOSType.invoke(null, new Object[] { FINDER_CREATOR });
+					Object aeTarget = aeTargetConstructor.newInstance(new Object[] { finderCreatorCode });
+					Integer gurlType = (Integer) makeOSType.invoke(null, new Object[] { GURL_EVENT });
+					Object appleEvent = appleEventConstructor.newInstance(new Object[] { gurlType, gurlType, aeTarget, kAutoGenerateReturnID, kAnyTransactionID });
+					// Don't set browser = appleEvent because then the next time we call
+					// locateBrowser(), we'll get the same AppleEvent, to which we'll already have
+					// added the relevant parameter. Instead, regenerate the AppleEvent every time.
+					// There's probably a way to do this better; if any has any ideas, please let
+					// me know.
+					return appleEvent;
+				} catch (IllegalAccessException iae) {
+					browser = null;
+					errorMessage = iae.getMessage();
+					return browser;
+				} catch (InstantiationException ie) {
+					browser = null;
+					errorMessage = ie.getMessage();
+					return browser;
+				} catch (InvocationTargetException ite) {
+					browser = null;
+					errorMessage = ite.getMessage();
+					return browser;
+				}
+			case MRJ_2_1:
+				File systemFolder;
+				try {
+					systemFolder = (File) findFolder.invoke(null, new Object[] { kSystemFolderType });
+				} catch (IllegalArgumentException iare) {
+					browser = null;
+					errorMessage = iare.getMessage();
+					return browser;
+				} catch (IllegalAccessException iae) {
+					browser = null;
+					errorMessage = iae.getMessage();
+					return browser;
+				} catch (InvocationTargetException ite) {
+					browser = null;
+					errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
+					return browser;
+				}
+				String[] systemFolderFiles = systemFolder.list();
+				// Avoid a FilenameFilter because that can't be stopped mid-list
+				for(int i = 0; i < systemFolderFiles.length; i++) {
+					try {
+						File file = new File(systemFolder, systemFolderFiles[i]);
+						if (!file.isFile()) {
+							continue;
+						}
+						// We're looking for a file with a creator code of 'MACS' and
+						// a type of 'FNDR'.  Only requiring the type results in non-Finder
+						// applications being picked up on certain Mac OS 9 systems,
+						// especially German ones, and sending a GURL event to those
+						// applications results in a logout under Multiple Users.
+						Object fileType = getFileType.invoke(null, new Object[] { file });
+						if (FINDER_TYPE.equals(fileType.toString())) {
+							Object fileCreator = getFileCreator.invoke(null, new Object[] { file });
+							if (FINDER_CREATOR.equals(fileCreator.toString())) {
+								browser = file.toString();	// Actually the Finder, but that's OK
+								return browser;
+							}
+						}
+					} catch (IllegalArgumentException iare) {
+						browser = browser;
+						errorMessage = iare.getMessage();
+						return null;
+					} catch (IllegalAccessException iae) {
+						browser = null;
+						errorMessage = iae.getMessage();
+						return browser;
+					} catch (InvocationTargetException ite) {
+						browser = null;
+						errorMessage = ite.getTargetException().getClass() + ": " + ite.getTargetException().getMessage();
+						return browser;
+					}
+				}
+				browser = null;
+				break;
+			case MRJ_3_0:
+			case MRJ_3_1:
+				browser = "";	// Return something non-null
+				break;
+			case WINDOWS_NT:
+				browser = "cmd.exe";
+				break;
+			case WINDOWS_9x:
+				browser = "command.com";
+				break;
+			case OTHER:
+			default:
+				browser = "netscape";
+				break;
+		}
+		return browser;
+	}
+
+	/**
+	 * Attempts to open the default web browser to the given URL.
+	 * @param url The URL to open
+	 * @throws IOException If the web browser could not be located or does not run
+	 */
+	public static void openURL(String url) throws IOException {
+		if (!loadedWithoutErrors) {
+			throw new IOException("Exception in finding browser: " + errorMessage);
+		}
+		Object browser = locateBrowser();
+		if (browser == null) {
+			throw new IOException("Unable to locate browser: " + errorMessage);
+		}
+
+		switch (jvm) {
+			case MRJ_2_0:
+				Object aeDesc = null;
+				try {
+					aeDesc = aeDescConstructor.newInstance(new Object[] { url });
+					putParameter.invoke(browser, new Object[] { keyDirectObject, aeDesc });
+					sendNoReply.invoke(browser, new Object[] { });
+				} catch (InvocationTargetException ite) {
+					throw new IOException("InvocationTargetException while creating AEDesc: " + ite.getMessage());
+				} catch (IllegalAccessException iae) {
+					throw new IOException("IllegalAccessException while building AppleEvent: " + iae.getMessage());
+				} catch (InstantiationException ie) {
+					throw new IOException("InstantiationException while creating AEDesc: " + ie.getMessage());
+				} finally {
+					aeDesc = null;	// Encourage it to get disposed if it was created
+					browser = null;	// Ditto
+				}
+				break;
+			case MRJ_2_1:
+				Runtime.getRuntime().exec(new String[] { (String) browser, url } );
+				break;
+			case MRJ_3_0:
+				int[] instance = new int[1];
+				int result = ICStart(instance, 0);
+				if (result == 0) {
+					int[] selectionStart = new int[] { 0 };
+					byte[] urlBytes = url.getBytes();
+					int[] selectionEnd = new int[] { urlBytes.length };
+					result = ICLaunchURL(instance[0], new byte[] { 0 }, urlBytes,
+											urlBytes.length, selectionStart,
+											selectionEnd);
+					if (result == 0) {
+						// Ignore the return value; the URL was launched successfully
+						// regardless of what happens here.
+						ICStop(instance);
+					} else {
+						throw new IOException("Unable to launch URL: " + result);
+					}
+				} else {
+					throw new IOException("Unable to create an Internet Config instance: " + result);
+				}
+				break;
+			case MRJ_3_1:
+				try {
+					openURL.invoke(null, new Object[] { url });
+				} catch (InvocationTargetException ite) {
+					throw new IOException("InvocationTargetException while calling openURL: " + ite.getMessage());
+				} catch (IllegalAccessException iae) {
+					throw new IOException("IllegalAccessException while calling openURL: " + iae.getMessage());
+				}
+				break;
+		    case WINDOWS_NT:
+		    case WINDOWS_9x:
+		    	// Add quotes around the URL to allow ampersands and other special
+		    	// characters to work.
+				Process process = Runtime.getRuntime().exec(new String[] { (String) browser,
+																FIRST_WINDOWS_PARAMETER,
+																SECOND_WINDOWS_PARAMETER,
+																THIRD_WINDOWS_PARAMETER,
+																'"' + url + '"' });
+				// This avoids a memory leak on some versions of Java on Windows.
+				// That's hinted at in <http://developer.java.sun.com/developer/qow/archive/68/>.
+				try {
+					process.waitFor();
+					process.exitValue();
+				} catch (InterruptedException ie) {
+					throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
+				}
+				break;
+			case OTHER:
+				// Assume that we're on Unix and that Netscape is installed
+
+				// First, attempt to open the URL in a currently running session of Netscape
+				process = Runtime.getRuntime().exec(new String[] { (String) browser,
+													NETSCAPE_REMOTE_PARAMETER,
+													NETSCAPE_OPEN_PARAMETER_START +
+													url +
+													NETSCAPE_OPEN_PARAMETER_END });
+				try {
+					int exitCode = process.waitFor();
+					if (exitCode != 0) {	// if Netscape was not open
+						Runtime.getRuntime().exec(new String[] { (String) browser, url });
+					}
+				} catch (InterruptedException ie) {
+					throw new IOException("InterruptedException while launching browser: " + ie.getMessage());
+				}
+				break;
+			default:
+				// This should never occur, but if it does, we'll try the simplest thing possible
+				Runtime.getRuntime().exec(new String[] { (String) browser, url });
+				break;
+		}
+	}
+
+	/**
+	 * Methods required for Mac OS X.  The presence of native methods does not cause
+	 * any problems on other platforms.
+	 */
+	private native static int ICStart(int[] instance, int signature);
+	private native static int ICStop(int[] instance);
+	private native static int ICLaunchURL(int instance, byte[] hint, byte[] data, int len,
+											int[] selectionStart, int[] selectionEnd);
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/util/OptimizationStrategyWrapper.java b/src/main/java/es/uvigo/darwin/xprottest/util/OptimizationStrategyWrapper.java
new file mode 100755
index 0000000..b431998
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/util/OptimizationStrategyWrapper.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.xprottest.util;
+
+/**
+ * The class OptimizationStrategyWrapper models a ProtTest optimization
+ * strategy (about topology usage), providing a description and a option
+ * value together.
+ * 
+ * @author Diego Darriba
+ */
+public class OptimizationStrategyWrapper {
+
+    private String description;
+    private int value;
+    
+    public int getValue() {
+        return value;
+    }
+    
+    public OptimizationStrategyWrapper(String description, int value) {
+        this.description = description;
+        this.value = value;
+    }
+
+    @Override
+    public String toString() {
+        return description;
+    }
+    
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/util/TextAreaAppender.java b/src/main/java/es/uvigo/darwin/xprottest/util/TextAreaAppender.java
new file mode 100755
index 0000000..c447024
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/util/TextAreaAppender.java
@@ -0,0 +1,31 @@
+package es.uvigo.darwin.xprottest.util;
+
+import java.io.IOException;
+import javax.swing.JTextArea;
+import java.io.Writer;
+
+/**
+ * Simple way to "print" to a JTextArea; just say
+ * PrintWriter out = new PrintWriter(new TextAreaAppender(myTextArea));
+ * Then out.println() et all will all appear in the TextArea.
+ */
+public final class TextAreaAppender extends Writer {
+
+	private final JTextArea textArea;
+
+	public TextAreaAppender(final JTextArea textArea) {
+		this.textArea = textArea;
+	}
+
+    @Override
+    public void flush(){ }
+    
+    @Override
+    public void close(){ }
+
+    @Override
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        textArea.append(new String(cbuf, off, len));
+        textArea.setCaretPosition(textArea.getDocument().getLength());
+    }
+}
diff --git a/src/main/java/es/uvigo/darwin/xprottest/util/TextAreaWriter.java b/src/main/java/es/uvigo/darwin/xprottest/util/TextAreaWriter.java
new file mode 100755
index 0000000..1626ca1
--- /dev/null
+++ b/src/main/java/es/uvigo/darwin/xprottest/util/TextAreaWriter.java
@@ -0,0 +1,31 @@
+package es.uvigo.darwin.xprottest.util;
+
+import java.io.IOException;
+import javax.swing.JTextArea;
+import java.io.Writer;
+
+/**
+ * Simple way to "print" to a JTextArea; just say
+ * PrintWriter out = new PrintWriter(new TextAreaAppender(myTextArea));
+ * Then out.println() et all will all appear in the TextArea.
+ */
+public final class TextAreaWriter extends Writer {
+
+	private final JTextArea textArea;
+
+	public TextAreaWriter(final JTextArea textArea) {
+		this.textArea = textArea;
+	}
+
+    @Override
+    public void flush(){ }
+    
+    @Override
+    public void close(){ }
+
+    @Override
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        textArea.append(new String(cbuf, off, len));
+        textArea.setCaretPosition(off);
+    }
+}
diff --git a/src/main/resources/CHANGELOG b/src/main/resources/CHANGELOG
new file mode 100644
index 0000000..638c215
--- /dev/null
+++ b/src/main/resources/CHANGELOG
@@ -0,0 +1,40 @@
+-----------------------------------------------------------------------------
+ProtTest 3 Change Log -	23/Jan/2014
+
+Diego Darriba (ddarriba at udc.es)
+Guillermo L. Taboada (taboada at udc.es)
+Ramón Doallo (doallo at udc.es)
+David Posada (dposada at uvigo.es)
+
+(c) Universidad de Vigo, Vigo, Spain
+(c) Grupo de Arquitectura de Computadores, UDC, Spain
+
+-----------------------------------------------------------------------------
+
+ProtTest 3.4 (23/Jan/2014)
+
+  * Fix : Fixed problem while trying to execute ProtTest from outside its home directory.
+
+  * Enhancement : Added configuration property for disable logging.
+		  Added configuration property for using a system-wide installed PhyML.
+
+ProtTest 3.3 (16/Jul/2013)
+
+  * Enhancement : Added real-time PhyML logging.
+
+  * Enhancement : Removed sample size selection. Fixed to alignment length.
+
+ProtTest 3.2 (16/Mar/2012)
+
+    * Enhancement: Enable the model selection and phylogenetic averaging
+        using more than one single Information Criterion:
+
+        "-sort" argument is replaced by -AIC, -BIC, -AICC and -DT arguments.
+
+    * Enhancement: By default, all model matrices are computed unless you
+        explicitly specify a subset.
+
+ProtTest 3.1 (5/Mar/2012)
+
+    * Enhancement: Added suport for old PhyML versions that does not support
+        the --no-memory-check option, through prottest.properties file.
diff --git a/src/main/resources/COPYING b/src/main/resources/COPYING
new file mode 100755
index 0000000..d60c31a
--- /dev/null
+++ b/src/main/resources/COPYING
@@ -0,0 +1,340 @@
+		    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.
diff --git a/src/main/resources/README b/src/main/resources/README
new file mode 100755
index 0000000..3368595
--- /dev/null
+++ b/src/main/resources/README
@@ -0,0 +1,311 @@
+-----------------------------------------------------------------------------
+ProtTest 3 Readme -	23/Jan/2014
+
+Diego Darriba (ddarriba at udc.es)
+Guillermo L. Taboada (taboada at udc.es)
+Ramón Doallo (doallo at udc.es)
+David Posada (dposada at uvigo.es)
+
+(c) Universidad de Vigo, Vigo, Spain
+(c) Grupo de Arquitectura de Computadores, UDC, Spain
+
+Citation:
+
+    Darriba D, Taboada GL, Doallo R, Posada D. ProtTest 3: fast selection of
+    best-fit models of protein evolution. Bioinformatics, 27:1164-1165, 2011 
+
+  In addition, given that ProtTest uses Phyml intensively, we encourage users to 
+  cite this program as well when using ProtTest:
+
+    Guindon S, Gascuel O. 2003. A simple, fast, and accurate algorithm to 
+    estimate large phylogenies by maximum likelihood. Syst Biol. 52: 696-704. 
+    [Phyml]
+
+-----------------------------------------------------------------------------
+
+TOC
+
+0. Quick Start
+1. Introduction
+2. Installation
+3. Structure
+4. How to run
+  4.1. Required conditions
+  4.2. Console execution
+    4.2.1. Sequential execution
+    4.2.2. Multithread execution
+    4.2.3. Cluster execution
+    4.2.4. Cluster hybrid execution
+  4.3. Graphical user interface execution
+5. Frequently Asked Questions
+
+-----------------------------------------------------------------------------
+0. Quick Start
+-----------------------------------------------------------------------------
+
+Console version
+
+$ tar zvxf prottest-3.4-yyyymmdd.tar.gz
+(Linux/Unix/OS X)
+$ export PROTTEST_HOME=$PWD/prottest3
+(Windows)
+$ set PROTTEST_HOME=$CWD\prottest3
+$ cd $PROTTEST_HOME
+$ java -jar prottest-3.4.jar -i examples/COX2_PF0016/alignment -all-matrices -all-distributions -threads 2
+
+Graphical version
+
+$ tar zvxf prottest-3.4-yyyymmdd.tar.gz
+(Linux/Unix/OS X)
+$ export PROTTEST_HOME=$PWD/prottest3
+(Windows)
+$ set PROTTEST_HOME=$CWD\prottest3
+$ cd $PROTTEST_HOME
+$ ./runXProtTest.sh
+
+-----------------------------------------------------------------------------
+1. Introduction
+-----------------------------------------------------------------------------
+
+ProtTest3 is a High Performance Computing implementation of ProtTest, for
+selection of best-fit models of protein evolution. It is currently under
+development so it could have some errors and the documentation is pending.
+
+Please, report bugs and enquiries about ProtTest 3 to: ddarriba at udc.es,
+dposada at uvigo.es.
+
+The main page of the ProtTest project is located at
+https://bitbucket.org/diegodl/prottest3
+
+-----------------------------------------------------------------------------
+2. Installation
+-----------------------------------------------------------------------------
+
+All required software is included in the distributions. For further information, 
+please refer to the 'How to run' section.
+
+-----------------------------------------------------------------------------
+3. Structure
+-----------------------------------------------------------------------------
+
+Inside the ProtTest 3 directory you should find the following structure:
+
+$PROTTEST_HOME/
+  |
+  |
+  |--bin/
+     # auxiliary binaries to calculate models likelihood
+  |--examples/
+     # some test alignments and trees
+  |
+  | filecluster8.conf.template  # machines file template for 8 node cluster
+  | machines			# machines file for cluster execution
+  | prottest.properties		# ProtTest3 configuration file (always required)
+  | prottest-3.4.jar		# ProtTest3 package
+  | README			# this README file
+  | COPYING                     # ProtTest3 licese
+  | runProtTestHPC.sh		# basic script for ProtTest3 cluster execution
+  | runXProtTestHPC.sh		# basic script for ProtTest3 graphical version
+  
+- The ProtTest properties (prottest.properties) file must be located in the 
+ProtTest root directory. It has the execution preferences. Please refer to such
+file to know more about the execution properties.
+
+- The external applications should be located on "bin" directory under the 
+ProtTest root, where at least the one which matches your computer architecture
+must exist.
+
+-----------------------------------------------------------------------------
+4. How to run
+-----------------------------------------------------------------------------
+
+There are several ways to run ProtTest according to the resources you want
+to use.
+
+It's preferred to use JRE 1.6 to run ProtTest, in fact, the graphical user
+interface will only work with JRE 1.6 or newer version.
+
+You can download the newest version at http://java.sun.com/javase/
+
+-----------------------------------------------------------------------------
+	4.1. Required conditions
+-----------------------------------------------------------------------------
+
+In order to run ProtTest there will be some general constraints you have to
+satisfy:
+
+- You should run it from the ProtTest root directory (i.e. the directory where
+you have unpackaged the distribution).
+
+-----------------------------------------------------------------------------
+	4.2. Console execution
+-----------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------
+	4.2.1 Sequential execution
+-----------------------------------------------------------------------------
+
+Under command line you can use several parallel executions of ProtTest, but first
+it is important to understand how to run the sequential execution.
+
+These are the parameters of the sequential execution:
+
+     -i alignment_filename
+            Alignment input file (required)
+     -t tree_filename
+            Tree file       (optional) [default: NJ tree]
+     -o output_filename
+            Output file     (optional) [default: standard output]
+     -log enabled/disabled
+            Enables / Disables PhyML logging into log directory (see prottest.properties)
+     -[matrix]
+            Include matrix (Amino-acid) = JTT LG DCMut MtREV MtMam MtArt Dayhoff WAG 
+	                                  RtREV CpREV Blosum62 VT HIVb HIVw FLU 
+                If you don't specify any matrix, all matrices displayed above will
+                be included.
+     -I
+            Include models with a proportion of invariable sites
+     -G
+            Include models with rate variation among sites and number of categories
+     -IG
+            include models with both +I and +G properties
+     -all-distributions
+            Include models with rate variation among sites, number of categories and both
+     -ncat number_of_categories
+            Define number of categories for +G and +I+G models [default: 4]
+     -F
+            Include models with empirical frequency estimation 
+     -AIC
+            Display models sorted by Akaike Information Criterion (AIC)
+     -BIC
+            Display models sorted by Bayesian Information Criterion (BIC)
+     -AICC
+            Display models sorted by Corrected Akaike Information Criterion (AICc)
+     -DT
+            Display models sorted by Decision Theory Criterion
+     -all
+            Displays a 7-framework comparison table
+     -S optimization_strategy
+            Optimization strategy mode: [default: 0]
+             		0: Fixed BIONJ JTT
+             		1: BIONJ Tree
+             		2: Maximum Likelihood tree
+             		3: User defined topology
+     -s moves
+            Tree search operation for ML search: 
+            NNI (fastest), SPR (slowest), BEST (best of NNI and SPR) [default: NNI]
+     -t1      				
+            Display best-model's newick tree [default: false]
+     -t2      				
+            Display best-model's ASCII tree  [default: false]
+     -tc consensus_threshold 
+            Display consensus tree with the specified threshold, between 0.5 and 1.0
+            [0.5 = majority rule consensus ; 1.0 = strict consensus]
+     -threads number_or_threads			
+            Number of threads requested to compute (only if MPJ is not used) [default: 1]
+     -verbose
+            Verbose mode [default: false]
+
+
+Basic execution example:
+
+	$ cd $PROTTEST_HOME
+	$ java -jar prottest-3.4.jar -i examples/COX2_PF0016/alignment -all-distributions -F -AIC -BIC -tc
+
+
+-----------------------------------------------------------------------------
+	4.2.2 Multithread execution
+-----------------------------------------------------------------------------
+
+Just like the sequential execution, but adding the number of threads option. You 
+can use up to the number of cores in your machine and beyond. Following the basic
+execution example, a recommended multithread execution in a quad-core machine will be:
+
+	$ cd $PROTTEST_HOME
+	$ java -jar prottest-3.4.jar -i examples/COX2_PF0016/alignment -all-distributions -F -AIC -BIC -tc -threads 4
+
+It is remarkable that the substitution models will not be computed in a specific
+order, so the full output will be shown once all models have been computed. 
+Meanwhile, the main thread will notify each executed model by the standard output.
+
+-----------------------------------------------------------------------------
+	4.2.3 Cluster execution
+-----------------------------------------------------------------------------
+
+1. Besides the multithreading support, it is possible to run ProtTest in 
+a cluster. This support has been implemented using a Java message-passing 
+(MPJ) library, MPJ Express (http://mpj-express.org/). To execute ProtTest 
+in a cluster environment you have to:
+
+$ cd $PROTTEST_HOME
+$ export MPJ_HOME=$PROTTEST_HOME/mpj
+$ export PATH=$MPJ_HOME/bin:$PATH
+
+You can also add the last two lines to ~/.bashrc to automatically set this
+variables at console startup.
+
+2. $PROTTEST_HOME/machines file contains the set of compute nodes amongst the
+mpj processes will be executed. By default it points to the localhost machine,
+so you should change it if you want to run parallel exeecution over a cluster
+machine, just writing on each line the compute nodes (e.g. see 
+filecluster8.conf.template).
+
+3. Start the MPJ Express daemons:
+
+$ mpjboot machines
+
+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.
+
+4. Run ProtTest. For the execution the ProtTest distribution provides a
+bash script: 'runProtTestHPC.sh'
+
+The basic syntax is:
+	./runProtTestHPC.sh $NUMBER_OF_PROCESSORS $APPLICATION_PARAMETERS
+
+$ ./runProtTestHPC.sh 2 -i examples/COX2_PF0016/alignment -all-distributions -F -AIC -BIC -tc
+
+-----------------------------------------------------------------------------
+	4.2.4 Cluster hybrid execution
+-----------------------------------------------------------------------------
+
+This strategy relies on a thread-based implementation of phyml together with the
+distributed memory of ProtTest version. Please request us the thread-based
+phyml source code and further documentation.
+
+-----------------------------------------------------------------------------
+	4.3. Graphical user interface execution
+-----------------------------------------------------------------------------
+
+If you are running ProtTest on your desktop computer, you'd better use the
+graphical user interface, provided by the XProtTest package. It will be
+show results clearer to the user and will be easier to manipulate them too.
+
+The graphical interface can use a sequential or a shared memory execution
+of the application, so it will be the best choice for running ProtTest on
+a local multicore machine.
+
+$ cd $PROTTEST_HOME
+$ ./runXProtTestHPC.sh
+
+-----------------------------------------------------------------------------
+5. Frequently Asked Questions
+-----------------------------------------------------------------------------
+
+ 5.1. I got this error when running ProtTest 3
+
+      ./phyml-prottest-linux: /lib/libc.so.6: version `GLIBC_2.7' not found 
+
+    ---
+
+    You can try to update GLIB to the required version (2.7). However, this is
+    not always possible, for example when running ProtTest on a cluster. If
+    you have an old version of PhyML you can try to use it just linking the
+    binary file to $PROTTEST_HOME/bin/phyml
+
+    If this does not work, it is possible that your "old" version of PhyML 
+    does not support the --no-memory-check argument, included in lattest PhyML
+    versions. In this case, edit the prottest.properties file and change the
+    "no-memory-check" property to "no".
diff --git a/src/main/resources/THIRDPARTYLICENSES b/src/main/resources/THIRDPARTYLICENSES
new file mode 100755
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/src/main/resources/examples/COX2_PF0016/alignment b/src/main/resources/examples/COX2_PF0016/alignment
new file mode 100755
index 0000000..1a78cb2
--- /dev/null
+++ b/src/main/resources/examples/COX2_PF0016/alignment
@@ -0,0 +1,30 @@
+28 149
+COX2_SYNY3   MAHNHMGHMGSMGNMVAMAGDGDVALGIGLDSEEQGVNPLMVDVKGIQYAWIFTYPETGIISGELHAPIDRPVQLNMEAGDVIHAFWIPQLRLKQDVIPGRGSTLVFNASTPGQYPVICAELCGAYHGGMKSVFYAHTPEEYDDWVAAN
+COX2_ZOOAN    MTIKTIGHQWYWSYEYSDFI------KVEFDS-------YMTPYEEDNKK----MFRLLETDNHVTLPMNSFIRIIVTAADVLHSWTIPSLGIKADATPGRLNQSSFMINRPGLLYGQCSEICGANHSFMPIVIESVSTKKFIEWIKNL
+COX2_PERAM    VTLKTIGHQWYWSYEYSDFA------KVEFDS-------YMIPQDEMDHS----MFRLLDVDNRAVLPMNTFIRIIVTAADVLHSWTIPSLGVKADATPGRLNQVSFLINRPGVLYGQCSEICGANHSFMPIVIESISTNGFINWILKM
+COX2_SYMST    ITLKTIGHQWYWSYEYSDFK------HIEFDS-------YMIPYNEMEES----GLRLLEVDNRTTLPMQTQVRILITAADVLHSWTVPSLGIKVDATPGRLNQTSFFINRPGIFFGQCSEICGANHSFMPIMIESVNIKSFINWIQNM
+COX2_ACHDO    ITMKTIGHQWYWSYEYMDFKN-----IIEFDS-------YMSALDKLSS------FRLLDVDNRTILPMNTQIRTLVTAADVIHSWTVSALGVKTDATPGRLNQINFMINRPGLFYGQCSEICGANHSFMPIVIESVNLKNFINWIKNY
+COX2_ONCFA    MTLKVIGHQWYWSYEYSDFK------NIEFDS-------YMKPTNELMNN----EFRLLEVDNRVLLPMNKQIRILITAADVLHSWAIPSLGVKIDATPGRLNQGSIKINRPGILFGQCSEICGANHSFMPIVIESVPIKNFLKWINKS
+COX2_CTEFE    ISLKAIGHQWYWSYEYTDFN------NISFDS-------YMIPSNELNLN----SFRLLDVDNRIILPINSQIRILITATDVLHSWTIPSLGIKIDATPGRLNQSNFMMNRPGLYFGQCSEICGANHSFMPIVIESILINSFIKWISSN
+COX2_ANOGA    ITLKSIGHQWYWSYEYSDFL------NLEFDS-------YMVPTNELETN----GFRLLDVDNRVVLPMNNQIRILVTATDVLHSWTVPSLGVKVDATPGRLNQLNFLINRPGLFFGQCSEICGANHSFMPIVIESIPMNYFIKWITSM
+COX2_LOCMI    ITIKTIGRQWYWSYEYSDFI------NVEFDT-------YMTPENELNTD----EFRLLEVDNRTTLPMNTEVRVLTSASDVLHSWAVPALVLKIDATPGRLNQGMFMINRPGLFFGQCSEICGANHSFMPIVIESTSIKLFIKWLSNM
+COX2_SITGR    LLIKIIGHQWYWSYEYSDYK------NIEFDS-------YMIPTKELNSF----NFRLLEVDNRTPIPYKTQIRILVTSADVIHSWTIPSMSIKIDGTPGRLNQANLIANRSSIFFGQCSEICGANHSFMPIVLESITPNLFLNWVISK
+COX2_ADABI    VTLKTIGHQWYWTYEYSDFK------KLEFDS-------YMLSYDNLNPF----NFRLLEVDNRTILPYLSNIRLLTSSADVIHSWTIPSSGVKIDASPGRLNQMSFTLNRTGIFYGQCSEICGANHSFMPISIESISPSNFIKWVNKS
+COX2_LASSP    ITIKSVGHQWYWSYEYSDFL------NIEFDS-------FMIPSNQLNPN----EFRLLDTDNRCILPFNYPIRILTTSMDVIHSWTVPSLGIKMDSTPGRLNQSLLYMYRPGLYFGQCSEICGTNHSFMPIVIESTNFSYFKNWLKSF
+COX2_EXERO    MTIKSIGHQWYWSYEYSDFK------NIDFNS-------FMINSK--NLN----HFRLLDVDNRMIIPMNNQIRMLINSADVIHSWTVPSLGVKIDSVPGRINQTLMMINRPGIYFGQCSEICGMNHSFMPIVIESTSNNNFISWLKSL
+COX2_APILI    FSIKSIGHQWYWSYEYPEFN------NIEFDS-------YMLNYN--NLN----QFRLLETDNRMVIPMKIPLRLITTSTDVIHSWTVPSLGIKVDAVPGRINQLNLISKRPGIFFGQCSEICGMNHSFMPIMIESTSFQYFLNWVNKQ
+COX2_PARLI    LTIKAIGHQWYWSYEYTDYN------DLEFDS-------YMVPTSDVSLG----NPRLLEVDNRLILPMQNPIRVLVSSADVLHSWAVPSLGVKMDAVPGRLNQTTFFAARAGLFYGQCSEICGANHSFMPILIESVPFSNFENWVAQY
+COX2_BALMU    LTVKTMGHQWYWSYEYTDYE------DLSFDS-------YMIPTSDLKPG----ELRLLEVDNRVVLPMEMTIRMLVSSEDVLHSWAVPSLGLKTDAIPGRLNQTTLMSTRPGLFYGQCSEICGSNHSFMPIVLELVPLEFFEKWSASM
+COX2_CROLA    LTIKAMGHQWYWSYEYTDYE------NLSFDS-------YMIPTQDLTPG----QFRLLETDHRMVVPMESPIRILVSAEDVLHSWALPAMGVKMDAVPGRLNQTAFIASRPGVFYGQCSEICGANHSFMPIVVEAVPLSHFENWSTLM
+COX2_CHICK    LTLKAIGHQWYWTYEYTDFK------DLSFDS-------YMTPTTDLPLG----HFRLLEVDHRIVIPMESPIRVIITADDVLHSWAVPALGVKTDAIPGRLNQTSFITTRPGVFYGQCSEICGANHSYMPIVVESTPLKHFEAWSSLL
+COX2_CERAE    FTIKSIGHQWYWTYEYTDYG------GLIFNS-------YMLPPLFLNPG----DLRLLEVDNRVVLPIEAPVRMMITSQDVLHSWTIPTLGLKTDAVPGRLNQTTFTATRPGVYYGQCSEICGANHSFMPIVAELIPLKIFEMGPVFT
+COX2_BETVU   ITIKAIGHQWYRSYEYSDYNS-SDEQSLTFDS-------YTIPEDDPELG----QSRLLEVDNRVVVPAKTHIRIIVTSADVLHSWAVPSSGVKCDAVPGRLNQTSILVQREGVYYGQCSEICGTNHAFMPIVVEAVSRKDYGSRVSNQ
+COX2_ALBTU    IVLKAIGHQWYWSYEMPSMN------VSSIDS-------YMIPEDDLKPG----EYRLLEVDNRPTVPYGMDINVIATSADVIHAWALPSMGVKMDAVPGRLNSMGFHANLPGIYYGQCSEICGANHSFMPIAIEAVDVKDFINMCN--
+COX2_CANGA   MTIKAIGYQWYWKYEYSDFIN-DNGETIEFES-------YVIPDDLLEEG----QLRLLDTDTSVVVPVDTHIRFVVTGADVIHDFAIPSLGIKVDANPGRLNQVSALIQREGVFYGQCSELCGVNHAAMPIKIEAVSLPKFLEWLNEQ
+COX2_BREAN   MTIKAMGLQWYWKYEYSDFMD-DKGETMEFES-------YMIPEDLLEEG----QLRQLDVDSPMVCPVDTHMRFMVTAADVMHDFAMPSLGIKIDAVPGRLNQTSALIQREGVYYGQCSELCGVMHSSMPMKIEAVSLGEFLAWIDEQ
+COX2_NEUCR   MSVLAEGHQWYWSYQYPDFLD-SNDEFIEFDS-------YIVPESDLEEG----ALRMLEVDNRVILPELTHVRFIITAGDVIHDFAVPSLGVKCDAYPRRLNQVSVFINREGVFYGQCSEICGILHSSMPIVIESVSLEKFLTWLEEQ
+COX2_EMENI   LVVYAEGHQWYWSYQYPDFTN-EDNEFIEFDS-------YIVPESDLEEG----QFRMLEVDNRVIIPELTHTAFVIS-ADVIHSYACPSLGIKADAYPGRLNQASVYINGPGTFFGQCSEICGILHSSMNIAIQSVSIKDFLLWLRDQ
+COX2_SCHPO   MTVKAIGRQWFWTYELNDFVT-NENEPVSFDS-------YMVPEEDLEEG----SLRQLEVDNRLVLPIDTRIRLILTSGDVIHSWAVPSLGIKCDCIPGRLNQVSLSIDREGLFYGQCSELCGVLHSSMPIVVQGVSLEDFLAWLEEN
+COX2_ASCSU    LTVKVTGHQWYWSYEFSDIP------GLEFDS-------YMKSLDQLELG----EPRLLEVDNRCVVPCDVNIRFCITSGDVIHSWALPSMSIKLDAMSGILSTLSYSFPVVGVFYGQCSEICGANHSFMPVALEVTLLDNFKSWCVGL
+COX2_PARDE   LVIKAIGHQWYWSYEYPNDG-------VAFDA-------LMLEKEALADAGYSEDEYLLATDNPVVVPVGKKVLVQVTATDVIHAWTIPAFAVKQDAVPGRIAQLWFSVDQEGVYFGQCSELCGINHAYMPIVVKAVSQEKYEAWLAGA
+
diff --git a/src/main/resources/examples/COX2_PF0016/tree b/src/main/resources/examples/COX2_PF0016/tree
new file mode 100755
index 0000000..05bc1be
--- /dev/null
+++ b/src/main/resources/examples/COX2_PF0016/tree
@@ -0,0 +1 @@
+((((((((((COX2_PERAM:0.12268,COX2_ZOOAN:0.14756):0.11296,((COX2_LOCMI:0.20148,((COX2_ANOGA:0.10575,COX2_CTEFE:0.14893):0.07661,COX2_ONCFA:0.14446):0.02458):0.03199,COX2_SYMST:0.14364):0.02951):0.02164,COX2_ACHDO:0.15257):0.02391,(((COX2_APILI:0.28114,COX2_LASSP:0.19564):0.06636,COX2_EXERO:0.14195):0.10415,COX2_SITGR:0.26620):0.05473):0.02165,COX2_ADABI:0.29483):0.12302,((COX2_PARLI:0.18778,(COX2_BALMU:0.16978,(COX2_CROLA:0.10531,COX2_CHICK:0.19774):0.08705):0.05161):0.00000,COX2_CERAE:0. [...]
diff --git a/src/main/resources/examples/HIV1.2008.pol.nex b/src/main/resources/examples/HIV1.2008.pol.nex
new file mode 100755
index 0000000..14db7cd
--- /dev/null
+++ b/src/main/resources/examples/HIV1.2008.pol.nex
@@ -0,0 +1,37 @@
+36 1034
+A1.AU.03. FFRENLAFQQ-GEARKFPSEQTRANS-----------PTSGALWDGG-----RDNLPSEAGAEGQGTG---------PTLSFPQITLWQRPIVTVRIEGQLREALLDTGADDTVLEDIDLPGKWKPRMIGGIGGFIKVKQYDQISIEICGKRAIGTVLVGPTPVNIIGRNMXXQIGCTLNXPISPIETVPVKLKPGMDGPKVKQWPLTAEKIKALTEICTDMEKEGKISKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDENFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPYRAKNPDIIIYQYMDDLYVGSDLEIGQHRAKIEELRAHLLSWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPINLPEKESWTVNDIQKLVGKLNWASQIYAGIKVKQLCKLLRGAKALTDVVTLTEEAEL [...]
+A1.KE.94. FFRENLAFQK-GEAREFSSEQTGTNS-----------STSRDLWDGG-----RDSLPSEAGAERQGTG---------PTLSFPQITLWQRPLVTVRIGGQLKEALLDTGADDTVLEDINLPGKWKPKMIGGIGGFIKVKQYDQILIEICGKKAIGTVLVGPTPVNIIGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTEMEKEGKISKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLHEEFRKYTAFTIPSTNNETPGVRYQYNVLPQGWKGSPAIFQSSMTKILEPFRSKNPEIVIYQYMDDLYVGSDLEIGQHRAKIEELRAHLLSWGLITPDKKHQKEPPFLWMGYELHPDKWTVQPIELPEKDSWTVNDIQKLVGKLNWASQIYAGIKVKQLCKLLRGAKALTDVVTLTEEAEL [...]
+A1.RW.92. FFRENLAFQQ-GEARKFSSEQTGAIS-----------PTSRDLWDRG-----RDSLPSEAGAERQGTG---------PTFSFPQITLWQRPLVTVRIGGQLKEALLDTGADDTVLEDINLPGKWKPRMIGGIGGFIKVKQYDQILIEICGKKAIGTVLVGPTPVNIIGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICSEMEKEGKISRIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDESFRKYTAFTIPSTNNETPGTRYQYNVLPQGWKGSPAIFQSSMTRILEPVRSKNPDIIIYQYMDDLYVGSDLEIGQHRAKIEELRAHLLSWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIVLPDKDHWTVNDIQKLVGKLNWASQIYPGIKVKQLCKLLRGAKALTDIVTLTEEAEL [...]
+A1.UG.92. FFRENLAFQQ-REARKFSSEQTRTNS----------PTSSRDLWDEG-----RDSLPSEAGAERQGPE---------PTFSFPQITLWQRPLVTVKIGGQLKEALLDTGADDTVLEDINLPGKWKPKMIGGIGGFIKVKQYDQILIEICGKKAIGTVLVGPTPVNIIGRNMLTQIGCTLNFPISPISTVPVKLKPGMDGPRIKQWPLTEEKIKALTEICADMEREGKISKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDESFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPAIFQASMTKILEPFRSKNPDIVIYQYMDDLYVGSDLEIGQHRTKIEELREHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIELPEKESWTVNDIQKLVGKLNWASQIYAGIKVKQLCKLLRGAKALTDIVTLTEEAEL [...]
+B.FR.83.H FFREDLAFLQ-GKAREFSSEQTRANS-----------PTRRELQVWG-----RDNNSPSEAGADRQGT---------VSFNFPQVTLWQRPLVTIKIGGQLKEALLDTGADDTVLEEMSLPGRWKPKMIGGIGGFIKVRQYDQILIEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALVEICTEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDEDFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRKQNPDIVIYQYMDDLYVGSDLEIGQHRTKIEELRQHLLRWGLTTPDKKHQKEPPFLWMGYELHPDKWTVQPIVLPEKDSWTVNDIQKLVGKLNWASQIYPGIKVRQLCKLLRGTKALTEVIPLTEEAEL [...]
+B.NL.00.6 FFREDLAFPQ-GEAREFSSEQTRANSPFSEQTRANS-PTRRELQVWG-----RDNNSLSEAGANRQGT---------VSFSFPQITLWQRPIVTIKIGGQLKEALLDTGADDTVLEEMDLPGRWKPKMIGGIGGFIKVRQYDQILIEISGHKTIGTVLVGPTPVNIIGRNLLTQLGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALVEICTELEKEGKISKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKDFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRKQNPDIVIYQYMDDLYVGSDLEMGQHRTRIEELRQHLLKWGFDTPDKKHQKEPPFLWMGYELHPDKWTVQPIVLPEKDXWXVNDIQKLVGKXNWASQIYPGIKVRQLCKLLRGTKALTEIVPLTAEAEL [...]
+B.TH.90.B FFRENLAFPQ-GKAREFSSEQTRADS-----------PTSRELQVWG-----RDNNSLSEAGDNRQGT---------ISFNCPQITLWQRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQILVEICGHKAIGTVLIGPTPVNIIGRNLLTQLGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALVEICTEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKDFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPAIFQCSMTKILEPFRKQNPDIVIYQYMDDLYVGSDLEIGQHRTKIEELRQHLLRWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIVLPEKDSWTVNDIQKLVGKLNWASQIYPGIKVKQLCKLLRGTKALTEVVPLTKEAEL [...]
+B.US.98.1 FFREDLAFPQ-RKAREFSSEQTRANS-----------PTSRELQVWG-----GDNNSLSEAGATRIS------------FSFPQITLWQRPLVTIKIGGQLKEALLDTGADDTVLEEMNLPGRWKPKMIGGIGGFIKVRQYDQIPIEICGNKAIGTVLIGPTPVNIIGRNLLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALAEICAEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKKTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDREFRKYTAFTIPSVNNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRKQNPEIVIYQYVDDLYVGSDLEIGQHRTKIEELRQHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIVLPEKDTWTVNDIQKLVGKLNWASQIYAGIKVRHLCKLLRGTKALTEVIPLTEEAEL [...]
+C.BR.92.B FFRENLAFPQ-GEARKSSSEQNRANS-----------PTRRELQVWG-----RDNNSLSEAGDDRQGT----------ALNFPQITLWQRPLVNIKVGGQLKEALLDTGADDTVLEEIKLPGNWKPKMIGGIGGFIKVRQYDQILIEICGKKAIGTVLVGPTPVNIIGRNMLTQLGCTLNFPISPIETVPVKLKPGMDGPKVKQWLLTEEKIKALTAICDEMEREGKITKIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRT?DFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDEGFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPSIFQSSTTKILEPFRAQNPEIIIYQYMDDLYVGSDLEIGQHRAKIEELREHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPEKDSWTVNDIQKLVGKLNWASQIYPGIKVRQLCKLLRGAKALTDIVPLTEEAEL [...]
+C.ET.86.E FFRETLAFQQ-GKAREFPSEQTRANSPTRESQTRANSPTTRELQVR------GS-NTFSEAGAERQGS-----------LNFPQITLWQRPLVTIKIGGQLKEALLDTGADDTVLEEINLPGKWKPKMIGGIGGFIKVRQYDQIIIEICGKKAIGTVLVGPTPVNIIGRNMLTQLGRTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTAICEEMEQEGKISRIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDEGFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPPIFQSSMPQILEPFRAPNPEIVIYQYMDDLYVGSDLEIGQHRAPIEELREHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPEKDSWTVNDIQKLVGKLNWASQIYPGIKVRQLCKLLRGAKALTDIVTLTEEAEL [...]
+C.IN.95.9 FFRENLAFPQ-GEAREFPPE?TRANS-----------STSRELQVR------GD-NPSSEAGAERQGT-----------FNFPQITLWQRPLVSIRVGGQIKEALLDTGADDTVLEEVSLPGKWRPKMIGGIGGFIKVRQYEEIPIEICGKKAIGTVLVGPTPVNIIGRNMLTQLGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTAICDEMEKEGKITKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLYEDFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQNSMTRILEPFRAQNPEIVIYQYMDDLYVGSDLEIGQHRAKIEELRKHLLRWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPEKDSWTVNDIQKLVGKLNWASQIYPGIKVRQLCKLLRGTKALTDIVPLTEEAEL [...]
+C.ZA.04.S FFRENLAFPE-GEAREFSPEQTRANS-----------PTSRELQVR------GD-DPCSETGAERQGT-----------FNFPQITLWQRPLVSIKIGGQTREALLDTGADDTVLEEINLPGKWKPKMIGGIGGFIKVRQYDQILIEICGKKAIGTVLVGPTPVNIIGRNMLTQLGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLSEEKIKALTAICEEMEKEGKITKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDEGFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRAKNPEIAIYQYMDDLYVGSDLEIGQHRAKIEELREHLLR?GFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPEKDSWTVNDIQKLVGKLNWASQIYPGIQVKQLCRLLRGAKALTDIVPLTEEAEL [...]
+D.CD.83.E FFRENLAFPQ-GKAGELSPKQTRANS-----------PTSRELRVWG-----RD-NPLSKTGAERQGT---------VSFNFPQITLWQRPLVAIKIGGQLKEALLDTGADDTVLEEMNLPGKWKPKMIGGIGGFIKVRQYDQIPIEICGQKAIGTVLVGPTPVNIIGRNLLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTDMEKEGKISRIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDEDFRKYTAFTISSINNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRKQNPEMVIYQYMDDLYVGSDLEIGQHRTKIEKLREHLLRWGFTRPDKKHQKEPPFLWMGYELHPDKWTVQSIKLPEKESWTVNDIQNLVERLNWASQIYPGIKVRQLCKLLRGTKALTEVIPLTEEAEL [...]
+D.CM.01.0 FFRENLAFQQ-GKARELSSEQTRANS-----------PTSRELRVRG-----GD-SPLSETGAERQRP-------GTVSFNFPQITLWQRPLVTIKIGGQLKEALLDTGADDTVLEDINLPGKWKPKMIGGIGGFIKVRQYDQIPIEICGQKAIGTVLVGPTPVNIIGRNLLTQIGCTLNFPISPIETVPVKLKPGMDGPKIKQWPLTEEKIKALTDICKEMEKEGKISRIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKEFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPAIFQCSMTKILEPFKKQNPELIIYSYMDDLYVGSDLEIGQHRAKIEKLREHLLKWGLTTPDKKHQKEPPFLWMGYELHPDKWTVQPITLPEKESWTVNDIQKLVGKLNWASQIYPGIKVRQLCKLLRGAKALTEIIPLTKEAEL [...]
+D.TZ.01.A FFRENLAFPQ-RKARELPSEQTRANS-----------PTSRDLRVWG-----GD-KTLSETGAERQGQ-------GTVSFSFPQITLWQRPLVTIKIGGQLKEALLDTGADDTVLEEMSLPGKWKPKMIGGIGGFIKVRQYDQILIEICGQKAIGTVLVGPTPVNIIGRNLLTQIGCTLNFPISPIATVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTEMEKEGKISRIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKDFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRKQNPEIVIYQYMDDLYVGSDLEIGQHRTKIEELRDHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIKLPEKESWTVNDIQKLVGKLNWASQIYSGIKVKQLCKLLRGAKALTEVIPLTKEAEL [...]
+D.UG.94.9 FFRENLAFPQ-WKAREFPSEQTPSRANS---------PTSRDLRIRG-----GD-NTSSETGAERQGT---------VSFNLPQITLWQRPVVTVKIGGQLKEALLDTGADDTVLEEINLPGKWKPKMIGGIGGFIKVRQYDQIPLEICGHKAIGTVLVGPTPVNIIGRNLLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALIEICSELEKEGKISKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLHEDFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRKQNPEMIIYQYMDDLYVGSDLEIGQHRIKIEELRGHLLKWGFTTPDKKYQKEPPFLWMGYELHPDKWTVQPIHLPEKESWTVNDIQKLVGKLNWASQIYPGIKVRQLCKCLRGAKALTEVIPLTAEAEL [...]
+F1.BE.93. FFRENLAFQQ-GEARKFPSEQTRANS-----------PTSRELRVQR-----GD-NPLSEAGAERRGT--------VPSLSFPQITLWQRPLVTIKIGGQIKEALLDTGADDTVLEDINLPGKWKPKMIGGIGGFIKVKQYDNILIEICGHKAIGTVLVGPTPVNIIGRNMLTQIGCTLNFPVSPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICLEMEKEGKISKIGPENPYNTPVFAIKKKDSSKWRKLVDFKELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKDFKKYTAFTIPSVNNETPGIRYQYNVLPQGWKGSPAIFQCSMTKILEPFRMKNPDIVIYQYMDDLYVGSDLEIGQHRTKIEELREHLLRWGFTTPDKKHQKEPPFLWMGHELHPDKWTVQPIQLPNKDSWTVNDIQKLVGKLNWASQIYPGIKVRPLCKLLRGAKALTDIVPLTAEAEL [...]
+F1.BR.93. FFRENLAFQQ-GEARKLHPEQARAVS-----------PASRELQVRG-----GD-NPISEAGAERRGT--------VPSLSFPQITLWQRPLVTIRVGGQLKEALLDTGADDTVLEDVNLPGKWKPKMIGGIGGFIKVKQYDSILIEICGHRAIGTVLVGPTPVNIIGRNMLTQIGCTLHFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICMEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKDFRKYTASTIPSTNNETPGVRYQYNVLPQGWKGSPAIFQYSMTKILDPFRAKNPDIVIYQYMDDLYVGSDLEIGQHRTKIEELREHLLKWGLTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPDKDSWTVNDIQKLVGKLNWASQIYPGIKVKQLCKLLRGAKALTDIVPLTTEAEL [...]
+F1.FI.93. FFRENLAFQQ-GEARKFPSE?TRANS-----------PASREPRDQR-----RG-NSLSEAGAERRGT--------VPSLSFPQITLWQRPLVTIKIGGQLKEALLDTGADDTVLEDINLPGKWKPKMIGGIGGFIKVKQYDHILIEICGHKAIGTVLVGPTPVNIVGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTDMEKEGKISRIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKDFRKYTAFTIPSVNNETPGIRYQYNVLPQGWKGSPAIFQCSMTKILEPFRTRNPDIVIYQYMDDLYVGSDLEIGQHRTKIEELREHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPDKDSWTVDDIQKLVGKLNWASXIYPGIKVRQLCKLLRGAKALTDMVPLTAEANL [...]
+F1.FR.96. FFRENLAFQQ-GEARKFSSEQARANS-----------PASGELRVQR-----GN-NPLSEAGAEGRGT------GTVSSLSLPQITFWQRPLVTIRVGGQLREALLDTGADDTVLEDIDLPGKWKPKIIGGIGGFIKVKQYDQITIDICGHKAIGTVLVGPTPVNIIGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTDMEKEGKISKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKEFRKYTAFTIPSLNNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRAKNPDIVIYQYMDDLYVGSDLELGQHRMKIEELREHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPEKDSWTVNDIQKLVGKLNWASQIYPGIKIKQLCKLLRGAKALTDIVPLTEEAEL [...]
+F2.CM.02. FFRENLAFQQ-REAWEFHSEQTRANG-----------PASRGLRVRR-----RD-NSLPEAGAERQGT--------VSSLDFPQITLWQRPVVTIKVEGQLREALLDTGADDTVLEDINLSGKWKPRMIGGIGGFIKVRQYDQVPIEICGQKAIGTVLVGPTPVNIIGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKEFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRARNPEIVVYQYMDDLYVGSDLEIGQHRAKIEELREHLLRWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQAIQLPNKSSWTVNDIQKLVGKLNWASQIYPGIRVKHLCKLLRGAKALTDVVPLTAEAEL [...]
+F2.CM.95. FFRENLAFQQ-GEARKFSSEQTRANS-----------PASRELRVRR-----GD-NPLPEAGAERRGT--------GSSLSFPQITLWQRPLVAIRVGGQLREALLDTGADDTVLEDINLPGKWKPKMIGGIGGFIKVRQYDQIPIEICGQKAIGTVLVGPTPVNIIGRNLLTQLGCTLNFPISPIETVPVKLKPGMDGPRVKQWPLTEEKIKALTEICTEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKEFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQCSMTKILEPFRAKNPEIVIYQYMDDLYVGSDLEIGQHRTKIEELREHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPEKSSWTVNDIQKLVGKLNWASQIYPGIRIKHLCRLLRGAKALTDVVPLTAEAEL [...]
+F2.CM.95b FFRENVAFQQ-GEARKFSSEQTRANS-----------PASRELRVRG-----GD-SSLPEAGAERQGT--------GSSLDFPQITLWQRPVVTIKVGGQLREALLDTGADDTVLEDINLPGKWKPKMIGGIGGFIKVRQYDQVSIEICGQKAIGTVLVGPTPVNIIGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKRSVTVLDVGDAYFSVPLDKEFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQSSMIKILEPFRKENPEIVIYQYMDDLYVGSDLEIGQHRAKIEELREHLLRWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQAIQLPDKSSWTVNDIQKLVGKLNWASQIYPGIRVKHLCKLLRGTKALTDVVPLTAEAEL [...]
+F2.CM.97. FFRENLAFQQ-GEAWKFSSEQTRANS-----------PASRKLRVRR-----RD-NSLPEAGAERQGN--------VPSLDFPQITLWQRPLVTIKVEGQLREALLDTGADDTVLEDINLSGKWKPRMIGGIGGFIKVRQYDQIPIEICGQKAIGTVLVGPTPVNIIGRNMLTQIGCTLNFPISSIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKEFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRVKNPEIVIYQYMDDLYVGSDLEIGQHRTKIEELREHLLRWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQAIQLPDKSSWTVNDIQKLVGKLNWASQIYPGIRVKHLCKLLRGAKALTDVVPLTVEAEL [...]
+G.BE.96.D FFRENLAFQQ-GEAREFPSEQARANS-----------PTRRELRVRG-----GD-SPLPEAGAEGKGT---------ISSIFPQITLWQRPIVKVRIGGQLIEALLDTGADDTVLEEIDLPGKWKPKMIGGIGGFIKVRQYDQILIEISGKRAIGTVLVGPTPINIIGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPRVKQWPLTEEKIKALTEICNEMEKEGKISKIGPENPYNTPIFAIKKKDSTRWRKLVDFRELNKRTQDFWEVPLGIPHPGGLKQKRSVTVLDVGDAYFSVPLDENFRKYTAFTIPSTNNETPGIRYQY--?PQGWKGSPAIFQSSMTKILEPFRTQNPEIVIYQYMDDLYVGSDLEIGQHRAKIEELREHLLRWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPNKENWTVNDIQKLVGKLNWASQIYPGIKVKQLCKLIRGAKALTDIVSMTAEAEM [...]
+G.KE.93.H F?RENLAFQQ-GEAREFSSEQARANS-----------PTRRELRVRR-----GN-SPLPEARAEGKGD---------TSLSFPQITLWQRPLVTVKIGGQLIEALLDTGADDTVLEDIKLPGKWKPKMIGGIGGFIKVRQYDQILIEISGKKAIGTVLVGPTPINIIGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTEMEREGKISKIGPENPYNTPIFAIRKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDESFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPPIFQSSMTKILEPFRIKNPEMVIYQYMDDLYVGSDLEIGQHRAKIKELREHLLRWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPEKESWTVNDIQKLVGKLNWASQIYPGIKVRQLCKLLRGAKALTDIVPLTAEAEL [...]
+G.NG.92.9 FFRENLAFQQ-GEARKLSPEQDRANS-----------PTSRELRIRR-----GD-SPLPEAGAKGEGA---------ISLNFPQITLWQRPLVTVKIGGQLIEALLDTGADDTVLEGINLPGKWKPKMIGGIGGFIKVRQYDQILIEIGGKKAIGTVLVGPTPINIIGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPRVKQWPLTEEKIKALTEICKDMEKEGKISKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKRSVTVLDVGDAYFSVPLDKDFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPSRTKNPEMVIYQYMDDLYVGSDLEIGQHRAKIEELREHLLKWGLTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPEKEDWTVNDIQKLVGKLNWASQIYPGIKVKHLCRLLRGAKALTDIVPLTAEAEM [...]
+G.PT.x.PT FFRENLAFQQ-GEAREFSPEQARANS-----------PTRRELRVRR-----GD-SPLPEARAEGQGV---------IPLNLPQITLWQRPLVTVRIGGQLIEALLDTGADDTVLEDINLPGKWKPKMIGGIGGFIKVRQYDQILIEICGKKAIGTVLVGPTPINIIGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTEMEREGKISKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPSGLKKKKSVTVLDVGDAYFSVPLDESFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRIKNPEIVIYQYMDDLYVGSDLEIGQHRAKIEELRKHLLNWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPDKESWTVNDIQKLVGKLNWASQIYPGIKIKQLCKLLRGAKALTDIVPLTAEAEL [...]
+H.BE.93.V FFRENLAFQQ-GKAREFPPEEARANS-----------PTSRELRVRR-----GD-HPLSEAGAERTGT----------SFNFPQITLWQRPIVTVKIEGQLKEALLDTGADDTVLEDINLPGKWKPKMIGGIGGFIKVRQYEQVAIEIFGKKAIGTVLVGPTPVNIIGRNILTQMGCTLNLPISPIETVPVTLKPGMDGPKVKQWPLTEEKIKALTEICLEMEKEGKISKIGPENPYNTPIFAIKKKNSTRWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVSVLDVGGAYFSVPLHEDFRKYTAFTIPSTNNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRKQNPEVIIYQYMDDLYVGSDLEIGQHREKIEELRAHLLRWGFTTPDQKHQKEPPFLWMGYELHPDKWTVQPVKLPEKDSWTVNDIQKLVGKLNWASQIYPGIKVKQLCXLLRGAKALTEIVPLTKEAEL [...]
+H.BE.93.W FFRENLAFQQ-REARKFSPEQARANS-----------PTSRELRVRG-----GD-DLLPEAGAEGQGT----------SLCFPQITLWQRPLVTVKIEGQLREALLDTGADDTVLEEINLLGRWKPKMIGGIGGFIKVRQYDQVAIEICGKKAIGTVLVGPTPVNIIGRNILTQIGCTLNFPISPIETVPVKLKPGMDGPRVKQWPLTEEKIKALTEICMEMEKEGKISKIGPENPYNTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVSVLDVGDAYFSVPLDKDFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILEPFRKQNPEIIIYQYMDDLYVGSDLEIGQHRAKIEELRAHLLRWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPVKLPEKDSWTVNDIQKLVGKLNWASQIYPGIKVRQLCKLLRGAKALTDVVPLTKEAEL [...]
+H.CF.90.0 FFRENLAFQQ-REARKFSPEQARTNS-----------PTSRELRVRR-----GD-DPLSEAGAAEGQG---------TSLSFPQITLWQRPLVTVKIEGQLREALLDTGADDTVLEEINLPGKWKPKMIGGIGGFIKVRQYEQVAIEICGKKAIGTVLVGPTPVNIIGRNILTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTEMEKEGKISRIGPENPYSTPIFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVSVLDVGDAYFSVPLDKEFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQSSMTKILAPFREQNPEMVIYQYMDDLYVGSDLEIGQHRAKIEELRAHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQTVKLPEKDSWTVNDIQKLVGKLNWASQIYPNIKVKQLCKLLRGAKALTDIIPLTKEAEL [...]
+J.CD.97.J FFRESLAFQQ-GEARELSPEQARTNS-----------PTSRKLRVRG-----ED-NSLPETGTEEGTI----------SFSFPQITLWQRPLVTVRVGGQLKEALLDTGADDTVLEEIDLPGKWKPKMIGGIGGFIKVRQYNDILIEIEGKKAIGTVLVGPTPVNIIGRNMLTQLGCTLNFPISPIETVPVKLKPGMDGPKIKQWPLTREKIEALTQICEEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWRK?VDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLYEDFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQCSMTKILEPFRAKNPEVVIYQYMDDLYVGSDLEIEQHRKKIEELREHLLRWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPVQLPEKESWTVNDIQKLVGKLNWASQIYPGIKVKQLCKLLRGTKALTDIVALTAEAEL [...]
+J.SE.93.S FFREDLAFQQ-REARELSPEQTRANS-----------PTSREPRAR------RG-DPLPETGAEGQGT---------VSSNFPQITLWQRPLVTIRIGGQLREALLDTGADDTVLEDIDLPRKWKPKMIGGIGGFIKVRQYNEVPIEIEGKKAIGTVLIGPTPVNIIGRNMLTQLGCTLNFPISPIETVPVKLKPGMDGPKIKQWPLTEEKIKALTQICAEMEEEGKISRVGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLYEDFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQCSMTKILKPFRERNPEIVIYQYMDDLYVGSDLEIEQHRRKIKELREHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPEKEDWTVNDIQKLVGKLNWASQIYPGIKVKQLCKLLKGAKALTDIVPLTREAEL [...]
+J.SE.94.S FFREDLAFQQ-REAREFSPEQTRANS-----------PTSREPRVR------RG-DPLPETGAEGQGT---------VSSNFPQITLWQRPLVTIRIGGQLREALLDTGADDTVLEEIDLPGKWKPKMIGGIGGFIKVRQYNEVPIEIEGKKAIGTVLIGPTPVNIIGRNMLTQLGCTLNFPISPIETVPVKLKPGMDGPKIKQWPLTEEKIKALTQICAELEEEGKISRIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLYEDFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQCSMTKILKPFRERNPEIVIYQYMDDLYVGSDLEIEQHRRKIKELREHLLKWGFYTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPEKEDWTVNDIQKLVGKLNWASQIYPGIKIKELCKLIRGAKALTDIVPLTREAEL [...]
+K.CD.97.E FFREVLASQQ-REARKFSSEQTRANS-----------PTSRELWVRG-----ED-NPLSETGNERSGT--------GSSFNFPQITLWQRPVVTVKVGGQLREALLDTGADDTVLEEINLPGKWKPKMIGGIGGFIKVRQYDQVCMEICGQKAIGTVLVGPTPVNIIGRNMLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALVEICTEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWIKLVDFRELNKRTPDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKDFRKYTAFTIPSINNETPGIRYQYNVLPQGWKGSPAIFQCSMTKILEPFRRKNPDMVLYQYMDDLYVGSDLEIGQHRAKIEELREHLLRWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPDKDSWTVNDIQKLVGKLNWASQIFPGIKVKQLCKLLRGVKALTDIVPLTAEAEL [...]
+K.CM.96.M FFRENLAFPQ-GEAREFSSEQTRANS-----------PTSRELRVRG-----GD-NPLSEAGDQRQGT--------EPSFNFPQITLWQRPIVTIKVGGQLREALLDTGADDTVLEEINLPGKWKPKMIGGIGGFIKVRQYDQVLIEICGQKAIGTVLVGPTPVNIIGRNLLTQIGCTLNFPISPIETVPVKLKPGMDGPKVKQWPLTEEKIKALTEICTEMEKEGKISKIGPENPYNTPVFAIKKKDSTKWRKLVDFRELNKRTQDFWEVQLGIPHPAGLKKKKSVTVLDVGDAYFSVPLDKDFRKYTAFTIPSINNETPGVRYQYNVLPQGWKGSPAIFQHSMTKILEPFRIKNPEMVIYQYMDDLYVGSDLEIGQPRTKIEELREHLLKWGFTTPDKKHQKEPPFLWMGYELHPDKWTVQPIQLPDKDSWTVNDIQKLVGKLNWASQIYPGIKVKQLCKLLRGVKALTDIVPLTAEAEL [...]
diff --git a/src/main/resources/examples/Ribosomal_L5_PF00673/alignment b/src/main/resources/examples/Ribosomal_L5_PF00673/alignment
new file mode 100755
index 0000000..89347db
--- /dev/null
+++ b/src/main/resources/examples/Ribosomal_L5_PF00673/alignment
@@ -0,0 +1,23 @@
+21 113
+RL5X_THETH   PIGLRVTLRRDRMWIFLEKLLNVALPRIRDFRGLN--PNSFDGRGNYNLGLREQLIFPEITYDMVDALRGMDIAVVT------TAETDEE----------ARALLELLGFPFR
+RL5_THEMA    PIGLKVTLRGARMYNFLYKLINIVLPKVRDFRGLD--PNSFDGRGNYSFGLSEQLVFPELNPDEVRRIQGMDITIVT------TAKTDQE----------ARRLLELFGMPFK
+RL5_MYCCA    AIGAKVTLRGKKMYDFLDKLINVALPRVRDFRGVS--KTSFDGFGNFYTGIKEQIIFPEVDHDKVIRLRGMDITIVT------SAKTNKE----------AFALLQKIGMPFE
+RK5_CYAPA    PIGVMVTLRGDYMYAFLDRLINLSLPRIRDFRGIT--AKSFDGRGNYNLGLKEQLIFPEVDYDGIEQIRGMDISIVT------TAKTDQE----------GLALLKSLGMPFA
+RL5_MICLU    PIGTHATLRGDRMWEFLDRLVTLPLPRIRDFRGLS--DRQFDGNGNYTFGLSEQTVFHEIDQDKIDRVRGMDITVVT------TAKNDDE----------GRALLKALGFPFK
+RL5_BUCAK    PIGCKVTLRGERMWEFFERLISIAVPRIRDFRGLS--AKSFDGRGNYSMGVREQIIFPEIDYDKVDRVRGLDITITT------TAKSDDE----------GRALLAAFNFPFR
+RL5_MYCGE    LIGCKVTLRNKKMWSFLEKLIYIALPRVRDFRGLS--LRSFDGKGNYTIGIKEQIIFPEIVYDDIKRIRGFDITIVT------STNKDSE----------ALALLRALKMPFV
+RK5_EUGGR    PVGMFLTLRSEKMYSFLDRLINLSLPRIRDFQGIN--KNCFDGSGNFSFGLSEQSMFPEINFDKMIKVQGLNITIVT------TAETNQE----------AFFLLKELGIPFR
+RK5_ODOSI   ELGLTVTLRGSKMYSFLTKLIFFTFAQIRDFRGLS--VRSFDKAGNYTLGLKEQLIFPEIDYDDVDQTQGFSITLVF------SSTAPKSRSKTMDRVLNGMVLFKFLRFPLN
+RL5_SULAC    PIGVKATLRRQAAVEFLKKVL-----PAVNFRLK---QSSFDNYGNVSFGIAEHVLIPGTRYDPEIGIFGMDVAITLVRPGYRTMKRKRKKA----SIPRRHRVTKEEAINFM
+RL5_METVA    PIGLKVTLRGKNAEEFLENAF-----VAFKVSGKVLYASSFDKVGNFSFGVPEHIDFPGQKYDPTVGIYGMDICVTFEKPGYRVKSRKLKRS----HIPAKHLVKKEEAIEYI
+RL5_METJA    PIGLKVTLRGKKAEEFLKNAF-----EAFQKEGKKLYDYSFDDYGNFSFGIHEHIDFPGQKYDPMIGIFGMDVCVTLERPGFRVKRRKRCRA----KIPRRHRLTREEAIEFI
+RL5_HALMA    PIGAKVTLRDEMAEEFLQTAL-----PLAELATS-----QFDDTGNFSFGVEEHTEFPSQEYDPSIGIYGLDVTVNLVRPGYRVAKRDKASR----SIPTKHRLNPADAVAFI
+RL11_YEAST   KIAVHVTVRGPKAEEILERGL-----KVKEYQLR---DRNFSATGNFGFGIDEHIDL-GIKYDPSIGIFGMDFYVVMNRPGARVTRRKRCKG----TVGNSHKTTKEDTVSWF
+RL11_SCHPO   KIACHVTVRGPKAEEILERGL-----KVKEYELK---KRNFSATGNFGFGIQEHIDL-GIKYDPSIGIYGMDFYVVMDRPGMRVARRKAQRG----RVGYTHKINAEDTINWF
+RL11_LEICH   KIAVHCTVRGKKAEELLEKGL-----KVKEFELK---SYNFSDTGSFGFGIDEHIDL-GIKYDPSTGIYGMDFYVVLGRRGERVAHRKRKCS----RVGHSHHVTKEEAMKWF
+RL11_DROME   KIAVHCTVRGAKAEEILERGL-----KVREYELR---RENFSSTGNFGFGIQEHIDL-GIKYDPSIGIYGLDFYVVLGRPGYNVNHRKRKSG----TVGFQHRLTKEDAMKWF
+RL11_HUMAN   KIAVHCTVRGAKAEEILEKGL-----KVREYELR---KNNFSDTGNFGFGIQEHIDL-GIKYDPSIGIYGLDFYVVLGRPGFSIADKKRRTG----CIGAKHRISKEEAMRWF
+RL11_CHLRE   KISCYVTVRGEKAYDLVKRGL-----AVKEFELI---RKNFSDTGNFGFGIQEHIDL-GLKYDPSTGIYGMDFYVCLERRGYRVARRRKQKA----HVGVKHKVTKEDAIKWF
+R111_ARATH   KIACYVTVRGEKAMQLLESGL-----KVKEYELL---RRNFSDTGCFGFGIQEHIDL-GIKYDPSTGIYGMDFYVVLERPGYRVARRRRCKA----RVGIQHRVTKDDAMKWF
+RL11_TETTH   KMAVHVTIRGDKARDILTRGL-----KVKEMELR---KKNFSNTGNFGFGIQEHIDL-GMKYDPSTGIFGMDFYVVLERPGTRVARRRRATS----RVGNNQMISKEECINWF
+
diff --git a/src/main/resources/examples/Ribosomal_L5_PF00673/tree b/src/main/resources/examples/Ribosomal_L5_PF00673/tree
new file mode 100755
index 0000000..6c892ba
--- /dev/null
+++ b/src/main/resources/examples/Ribosomal_L5_PF00673/tree
@@ -0,0 +1,9 @@
+(((((((((((RL11_HUMAN:0.1551800,RL11_DROME:0.0854900):0.0882500,(((RL11_YEAST:
+0.1429600,RL11_SCHPO:0.0875000):0.0873900,RL11_TETTH:0.2339800):0.0652200,
+(R111_ARATH:0.0698900,RL11_CHLRE:0.1904000):0.0941200):0.0839000):0.0287300,
+RL11_LEICH:0.1414200):0.4521600,((RL5_METJA:0.1374100,RL5_METVA:0.2718300)
+:0.1528200,RL5_SULAC:0.3595300):0.0839100):0.0845700,RL5_HALMA:0.3691600)
+:0.8932200,RL5_MYCCA:0.1851800):0.1082600,RL5_MYCGE:0.2360800):0.0507100,
+RK5_ODOSI:0.6278600):0.0727300,(RL5_BUCAK:0.1570200,RL5_MICLU:0.2811600)
+:0.1017400):0.0420600,(RK5_CYAPA:0.1638300,RK5_EUGGR:0.4177100):0.0974800)
+:0.0807800,RL5X_THETH:0.2117200,RL5_THEMA:0.2253200);
diff --git a/src/main/resources/filecluster8.conf.template b/src/main/resources/filecluster8.conf.template
new file mode 100755
index 0000000..9a90c18
--- /dev/null
+++ b/src/main/resources/filecluster8.conf.template
@@ -0,0 +1,8 @@
+compute-node-1-0
+compute-node-1-1
+compute-node-1-2
+compute-node-1-3
+compute-node-1-4
+compute-node-1-5
+compute-node-1-6
+compute-node-1-7
diff --git a/src/main/resources/machines b/src/main/resources/machines
new file mode 100755
index 0000000..2fbb50c
--- /dev/null
+++ b/src/main/resources/machines
@@ -0,0 +1 @@
+localhost
diff --git a/src/main/resources/models/FLU b/src/main/resources/models/FLU
new file mode 100755
index 0000000..4594d9f
--- /dev/null
+++ b/src/main/resources/models/FLU
@@ -0,0 +1,22 @@
+
+0.138658764751059	
+0.0533665787145181	0.161000889039552	
+0.584852305649886	0.00677184253227681	7.73739287051356	
+0.0264470951166826	0.16720700818221	1.30249856764315e-005	0.014132062548787	
+0.353753981649393	3.29271694159791	0.530642655337477	0.145469388422239	0.00254733397966779	
+1.4842345032161	0.124897616909194	0.0616521921873234	5.37051127867923	3.91106992668137e-011	1.19562912226203	
+1.13231312248046	1.19062446519178	0.322524647863997	1.93483278448943	0.116941459124876	0.108051341246072	1.59309882471598	
+0.214757862168721	1.87956993845887	1.38709603234116	0.887570549414031	0.0218446166959521	5.33031341222104	0.256491863423002	0.0587745274250666	
+0.149926734229061	0.246117171830255	0.21857197541607	0.0140859174993809	0.00111215807314139	0.0288399502994541	0.0142107118685268	1.62662283098296e-005	0.243190142026506	
+0.0231169515264061	0.296045557460629	0.000835873174542931	0.00573068208525287	0.00561362724916376	1.02036695531654	0.016499535540562	0.00651622937676521	0.321611693603646	3.51207228207807	
+0.474333610192982	15.3000966197798	2.6468479652886	0.290042980143818	3.83228119049152e-006	2.559587177122	3.88148880863814	0.264148929349066	0.347302791211758	0.227707997165566	0.129223639195248	
+0.0587454231508643	0.890162345593224	0.00525168778853117	0.0417629637305017	0.111457310321926	0.190259181297527	0.313974351356074	0.00150046692269255	0.00127350890508147	9.01795420287895	6.74693648486614	1.33129161941264	
+0.0804909094320368	0.0160550314767596	0.000836445615590923	1.0600102849456e-006	0.10405366623526	0.0326806570137471	0.00100350082518749	0.00123664495412902	0.119028506158521	1.46335727834648	2.98680003596399	0.319895904499071	0.279910508981581	
+0.659311477863896	0.154027179890711	0.0364417719063219	0.188539456415654	1.59312060172652e-013	0.712769599068934	0.319558828428154	0.0386317614553493	0.924466914225534	0.0805433268150369	0.634308520867322	0.195750631825315	0.0568693216513547	0.0071324304661639	
+3.01134451903854	0.950138410087378	3.88131053061457	0.338372183381345	0.336263344504404	0.487822498528951	0.307140298031341	1.58564657669139	0.580704249811294	0.290381075260226	0.570766693213698	0.283807671568883	0.00702658828739369	0.996685669575839	2.08738534433198	
+5.4182981753166	0.183076905018197	2.14033231636063	0.135481232622983	0.011975265782196	0.60234096342392	0.2801248951174	0.0188080299490973	0.368713573381758	2.90405228596936	0.0449263566753846	1.52696419998775	2.03151132062208	0.000134906239484254	0.54225109402693	2.2068599339404	
+0.195966354027106	1.36942940801512	0.000536284040016542	1.4893873721753e-005	0.0941066800969967	0.0440205200833047	0.155245492137294	0.196486447133033	0.0223729191088972	0.0321321499585514	0.431277662888057	4.97641445484395e-005	0.0704600385245663	0.814753093809928	0.000431020702277328	0.0998357527014247	0.207066205546908	
+0.0182892882245349	0.0998554972524385	0.373101926513925	0.525398542949365	0.601692431136271	0.0722059354079545	0.104092870343653	0.0748149970972622	6.44895444648517	0.273934263183281	0.340058468374384	0.0124162215506117	0.874272174533394	5.39392424532822	0.000182294881489116	0.392552239890831	0.124898020409882	0.42775543040588	
+3.53200526987468	0.103964386383736	0.0102575172450253	0.297123975243582	0.0549045639492389	0.406697814049488	0.285047948309311	0.337229618868315	0.0986313546653266	14.3940521944257	0.890598579382591	0.0731279296372675	4.90484223478739	0.592587985458668	0.0589719751511691	0.0882564232979724	0.654109108255219	0.256900461407996	0.167581646770807	
+
+0.0470718	0.0509102	0.0742143	0.0478596	0.0250216	0.0333036	0.0545874	0.0763734	0.0199642	0.0671336	0.0714981	0.0567845	0.0181507	0.0304961	0.0506561	0.0884091	0.0743386	0.0185237	0.0314741	0.0632292	
diff --git a/src/main/resources/mpj.tar.gz b/src/main/resources/mpj.tar.gz
new file mode 100755
index 0000000..46151f6
Binary files /dev/null and b/src/main/resources/mpj.tar.gz differ
diff --git a/src/main/resources/prottest.properties b/src/main/resources/prottest.properties
new file mode 100755
index 0000000..2571159
--- /dev/null
+++ b/src/main/resources/prottest.properties
@@ -0,0 +1,102 @@
+# -------------------------------------------------------------------
+# Likelihood analyzer
+#
+# 'phyml' PhyML is the only supported stable analyzer right now.
+# 'raxml' RAxML is not supported yet, but it is in development stage.
+# -------------------------------------------------------------------
+analyzer=phyml
+
+# ------------------------------------------------------------------
+# Phyml Binaries path                                    
+#                                                        
+# By default, ProtTest will search for the PhyML executables in 
+# $PROTTEST_HOME/bin. Users can define a different path, wether 
+# absolute (starting with '/' or 'C:\\') or relative to 
+# $PROTTEST_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	            = bin
+
+# -------------------------------------------------------------------
+# Use --no-memory-check argument (only for PhyML)
+#
+# Latest versions of PhyML support this argument. Without this 
+# argument, huge input alignments could crash during the model
+# optimization waiting for the user to check the memory requirements.
+# However, using this argument the user should be aware of the memory
+# that the model optimization process will require in each node 
+# (number of processes per node times the memory requirement per 
+# single optimization. If not, a single node could run out of memory.
+# -------------------------------------------------------------------
+no-memory-check=yes
+
+# -------------------------------------------------------------------
+# Parallel strategy
+#
+# if using MPJExpress you can choose the parallel strategy
+# to follow:
+#
+# 'static' by default. It distributes models amongst processors in
+# a static way. This is the best choice for a little number
+# of processors.
+#
+# 'dynamic' It does a better distribution of the computation load,
+# but the root process doesn't compute any likelihood data, so it will
+# be one processor less available to compute.
+#
+# 'dynamic_improved' Like the dynamic distribution, but there will be
+# an extra thread to do the distribution, so the whole group of
+# processors will compute the likelihood data.
+#
+# 'hybrid' An hybrid distribution coupling a distributed memory
+# implementation of ProtTest-HPC with a threaded version of the
+# likelihood computation.
+# -------------------------------------------------------------------
+parallel_strategy=dynamic_improved
+
+# -------------------------------------------------------------------
+# Thread Scheduling
+#
+# Uncomment line below to schedule openMP threads among the machine
+# cores.
+#
+# number_of_threads declares the maximum of process elements which
+# can be used from each node. If it is commented, the maximum number
+# of processors available will be used.
+#
+# -------------------------------------------------------------------
+#phyml_thread_scheduling=true
+#number_of_threads=2
+
+# -------------------------------------------------------------------
+# Snapshot directory
+#
+# ProtTestHPC provides fault-tolerance adding checkpointing support.
+# This is, being capable of resume a stopped execution just executing
+# the application again with the same parameters.
+#
+# The snapshot directory will be the place where the temporary status
+# files will be saved and loaded.
+# -------------------------------------------------------------------
+snapshot_dir=snapshot/
+
+# -------------------------------------------------------------------
+# Logging directory
+#
+# ProtTestHPC allows automatic logging for the user activity. Every
+# execution generates a log file. 
+#
+# Log level is configurable:
+#   'info'    Only general information messages are logged (default)
+#   'fine'    General debug information is also logged
+#   'finer'   More complex debug information is logged
+#   'finest'  All activity is tracked
+# -------------------------------------------------------------------
+log_dir=log/
+log_level=info
diff --git a/src/main/resources/runProtTestHPC.sh b/src/main/resources/runProtTestHPC.sh
new file mode 100755
index 0000000..5d08a4a
--- /dev/null
+++ b/src/main/resources/runProtTestHPC.sh
@@ -0,0 +1,4 @@
+export MPJ_HOME=$PWD/mpj
+export NP=$1
+shift
+$MPJ_HOME/bin/mpjrun.sh -dev niodev -wdir $PWD/ -np $NP -jar prottest-3.4.jar  $*
diff --git a/src/main/resources/runXProtTestHPC.bat b/src/main/resources/runXProtTestHPC.bat
new file mode 100755
index 0000000..e1bd4bf
--- /dev/null
+++ b/src/main/resources/runXProtTestHPC.bat
@@ -0,0 +1 @@
+java -cp prottest-3.4.jar es.uvigo.darwin.xprottest.XProtTestApp
diff --git a/src/main/resources/runXProtTestHPC.sh b/src/main/resources/runXProtTestHPC.sh
new file mode 100755
index 0000000..e1bd4bf
--- /dev/null
+++ b/src/main/resources/runXProtTestHPC.sh
@@ -0,0 +1 @@
+java -cp prottest-3.4.jar es.uvigo.darwin.xprottest.XProtTestApp
diff --git a/src/test/resources/VertCOII.trees b/src/test/resources/VertCOII.trees
new file mode 100755
index 0000000..50c14da
--- /dev/null
+++ b/src/test/resources/VertCOII.trees
@@ -0,0 +1,8 @@
+(1,2,(3,((6,7),(4,5)))) [0.707865];
+(1,(2,3),((6,7),(4,5))) [0.132335];
+(1,2,(3,(7,(6,(4,5))))) [0.082397];
+(1,(2,3),(7,(6,(4,5)))) [0.051186];
+(1,3,(2,((6,7),(4,5)))) [0.013733];
+(1,2,(3,(6,(7,(4,5))))) [0.007491];
+(1,3,(2,(7,(6,(4,5))))) [0.003745];
+(1,(2,3),(6,(7,(4,5)))) [0.001248];
diff --git a/src/test/resources/VertCOII.trprobs b/src/test/resources/VertCOII.trprobs
new file mode 100755
index 0000000..2103126
--- /dev/null
+++ b/src/test/resources/VertCOII.trprobs
@@ -0,0 +1,26 @@
+#NEXUS
+
+[ID: 0256489503]
+[This file contains the trees that were found during the MCMC
+search, sorted by posterior probability. "p" indicates the
+posterior probability of the tree whereas "P" indicates the
+cumulative posterior probability.]
+
+begin trees;
+   translate
+    1 Trout,
+    2 Frog,
+    3 Chicken,
+    4 Rat,
+    5 Mouse,
+    6 Cow,
+    7 Whale;
+   tree tree_1 [p = 0.708, P = 0.708] = [&W 0.707865] (1,2,(3,((6,7),(4,5))));
+   tree tree_2 [p = 0.132, P = 0.840] = [&W 0.132335] (1,(2,3),((6,7),(4,5)));
+   tree tree_3 [p = 0.082, P = 0.923] = [&W 0.082397] (1,2,(3,(7,(6,(4,5)))));
+   tree tree_4 [p = 0.051, P = 0.974] = [&W 0.051186] (1,(2,3),(7,(6,(4,5))));
+   tree tree_5 [p = 0.014, P = 0.988] = [&W 0.013733] (1,3,(2,((6,7),(4,5))));
+   tree tree_6 [p = 0.007, P = 0.995] = [&W 0.007491] (1,2,(3,(6,(7,(4,5)))));
+   tree tree_7 [p = 0.004, P = 0.999] = [&W 0.003745] (1,3,(2,(7,(6,(4,5)))));
+   tree tree_8 [p = 0.001, P = 1.000] = [&W 0.001248] (1,(2,3),(6,(7,(4,5))));
+end;
diff --git a/src/test/resources/testConsensus.sh b/src/test/resources/testConsensus.sh
new file mode 100755
index 0000000..212dd06
--- /dev/null
+++ b/src/test/resources/testConsensus.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+# Usage:
+#   sh testConsensus.sh FILENAME THRESHOLD
+#
+
+java -cp prottest-hpc.jar es.uvigo.darwin.prottest.consensus.Consensus $1 $2
diff --git a/src/test/resources/treeweights b/src/test/resources/treeweights
new file mode 100755
index 0000000..9fb98a4
--- /dev/null
+++ b/src/test/resources/treeweights
@@ -0,0 +1,25 @@
+((((((seq05:0.0077052441,(seq02:0.0111145304,(seq04:0.0020223938,seq03:0.0010157336):0.0075797472):0.0007496592):0.0171711541,seq01:0.0215304231):0.0092866832,seq06:0.0234123934):0.0839055134,seq10:0.2162744040):0.0678883105,seq07:0.0045842099):0.0033768164,seq09:0.0052205651,seq08:0.0060496451)[0.6044448518027933];
+((((((seq05:0.0077019984,(seq02:0.0111043579,(seq04:0.0020189219,seq03:0.0010140227):0.0075786575):0.0007397696):0.0171540818,seq01:0.0216147652):0.0093065511,seq06:0.0234637037):0.0850988342,seq10:0.2198141537):0.0681983513,seq07:0.0045539427):0.0033889360,seq09:0.0052200230,seq08:0.0060390825)[0.3122925586551285];
+(((((((seq04:0.0020072367,seq03:0.0010099963):0.0068295666,(seq02:0.0110746329,seq05:0.0082779326):0.0007704663):0.0172809633,seq01:0.0212924422):0.0076864019,seq06:0.0235197630):0.0798131754,seq10:0.2041408437):0.0647571261,seq07:0.0046699330):0.0032809253,seq09:0.0051113643,seq08:0.0060034254)[0.04015353319722536];
+((((((((seq04:0.0020263474,seq03:0.0010154378):0.0075716365,seq02:0.0111432259):0.0007110708,seq05:0.0077410097):0.0172619298,seq01:0.0215902855):0.0096043288,seq06:0.0231079057):0.0840300827,seq10:0.2149918557):0.0678403508,seq07:0.0046391422):0.0033165272,seq09:0.0052592579,seq08:0.0060534982)[0.027155794158633294];
+((((((seq05:0.0077465523,(seq02:0.0111430058,(seq04:0.0020244012,seq03:0.0010144860):0.0075765991):0.0006962556):0.0172655570,seq01:0.0216940056):0.0096262212,seq06:0.0231716075):0.0853867698,seq10:0.2189915255):0.0681779032,seq07:0.0046008122):0.0033351156,seq09:0.0052648635,seq08:0.0060457251)[0.014153903283194807];
+(((((((seq04:0.0020077813,seq03:0.0010087652):0.0068387708,(seq05:0.0082749335,seq02:0.0110769293):0.0007408180):0.0173425670,seq01:0.0212708925):0.0080434376,seq06:0.0232204283):0.0798564918,seq10:0.2032317054):0.0647363574,seq07:0.0047183263):0.0032403931,seq09:0.0051361082,seq08:0.0060009611)[0.001799358902984481];
+(((((((seq04:0.0020066427,seq03:0.0010057269):0.0066005758,(seq02:0.0109545639,seq05:0.0082288953):0.0009075007):0.0167646862,seq01:0.0201471031):0.0079147042,seq06:0.0220762149):0.0625656035,seq10:0.1496005616):0.0604749727,seq07:0.0052497997):0.0028439565,seq09:0.0050053208,seq08:0.0060419296)[3.8246098397130133E-14];
+(((((((seq04:0.0020089207,seq03:0.0010063352):0.0066175633,(seq05:0.0082360811,seq02:0.0109689813):0.0008858127):0.0168244215,seq01:0.0201504467):0.0081607986,seq06:0.0219457398):0.0626475214,seq10:0.1495585895):0.0604826110,seq07:0.0053271195):0.0028070525,seq09:0.0050167148,seq08:0.0060477153)[2.0605471459815532E-15];
+(((((((seq04:0.0019580958,seq03:0.0009758187):0.0066926874,(seq02:0.0110554554,seq05:0.0077880968):0.0008423307):0.0161959005,seq01:0.0211843004):0.0082359303,seq06:0.0215600694):0.0766275178,seq10:0.2056305491):0.0688321995,seq07:0.0046770599):0.0031912170,seq09:0.0053392070,seq08:0.0059538554)[6.541197018992573E-54];
+((((((seq05:0.0073248171,(seq02:0.0108517006,(seq04:0.0019554045,seq03:0.0009739229):0.0072029740):0.0008294110):0.0162862942,seq01:0.0207057765):0.0094779049,seq06:0.0212873196):0.0784846448,seq10:0.2113501151):0.0692184451,seq07:0.0046440279):0.0032081617,seq09:0.0053646732,seq08:0.0059524572)[4.219979115694137E-54];
+(((((((seq04:0.0019384486,seq03:0.0009700175):0.0065709567,(seq02:0.0109362246,seq05:0.0076986496):0.0008852850):0.0159233437,seq01:0.0207508000):0.0078865942,seq06:0.0213188047):0.0736050585,seq10:0.1962459426):0.0657553238,seq07:0.0047122770):0.0031519672,seq09:0.0051949011,seq08:0.0058870096)[3.533345910935345E-55];
+((((((seq05:0.0075146892,(seq02:0.0112664485,(seq04:0.0020281975,seq03:0.0010169502):0.0074765820):0.0009128315):0.0166409570,seq01:0.0214075315):0.0090209014,seq06:0.0228607022):0.0784238564,seq10:0.2087226511):0.0706491533,seq07:0.0050107284):0.0032010821,seq09:0.0053195750,seq08:0.0061319835)[2.0035396837899554E-57];
+((((((seq05:0.0075041280,(seq02:0.0112571504,(seq04:0.0020247149,seq03:0.0010151551):0.0074778361):0.0009104218):0.0166371342,seq01:0.0215129779):0.0090366986,seq06:0.0229536870):0.0800606769,seq10:0.2140114474):0.0712798148,seq07:0.0049744579):0.0032156966,seq09:0.0053289942,seq08:0.0061227020)[1.2844176925995497E-57];
+(((((((seq04:0.0020093312,seq03:0.0010096022):0.0069365358,(seq02:0.0113749375,seq05:0.0079949171):0.0007923111):0.0166256990,seq01:0.0213384957):0.0075699254,seq06:0.0229288389):0.0759084974,seq10:0.2012177218):0.0683135220,seq07:0.0050070486):0.0031722589,seq09:0.0052172273,seq08:0.0060826276)[1.2547050827258674E-58];
+((((((seq05:0.0074449819,(seq02:0.0111012907,(seq04:0.0020270019,seq03:0.0009973045):0.0073888637):0.0010896807):0.0164691675,seq01:0.0205783703):0.0091903908,seq06:0.0220758046):0.0677359174,seq10:0.1776723548):0.0655628028,seq07:0.0064365161):0.0016679435,seq09:0.0051508249,seq08:0.0060470243)[2.2832403590625373E-59];
+((((((seq05:0.0074369935,(seq02:0.0110945016,(seq04:0.0020252484,seq03:0.0009961127):0.0073869722):0.0010870647):0.0164578918,seq01:0.0205916388):0.0091792951,seq06:0.0221071518):0.0681371054,seq10:0.1791495483):0.0656647816,seq07:0.0064641602):0.0016290156,seq09:0.0051504246,seq08:0.0060391689)[1.016236039095543E-59];
+((((((seq05:0.0074283331,(seq02:0.0110219182,(seq04:0.0020131047,seq03:0.0009948961):0.0073286220):0.0010708984):0.0163947221,seq01:0.0203080535):0.0090280585,seq06:0.0218301832):0.0658207365,seq10:0.1728346403):0.0645232415,seq07:0.0062913235):0.0017849410,seq09:0.0050864725,seq08:0.0060272634)[1.7726413761399364E-60];
+(((((((seq04:0.0019341546,seq03:0.0009675243):0.0064546901,(seq02:0.0108336211,seq05:0.0076303300):0.0009293048):0.0153954205,seq01:0.0197297019):0.0078691272,seq06:0.0204324657):0.0578353178,seq10:0.1402602763):0.0588056578,seq07:0.0051935077):0.0027894076,seq09:0.0049312950,seq08:0.0058474190)[2.8550135068966413E-69];
+((((((seq05:0.0074050367,(seq02:0.0110047986,(seq04:0.0020212650,seq03:0.0010050635):0.0072993043):0.0011436254):0.0162097019,seq01:0.0198985425):0.0090719450,seq06:0.0212066823):0.0591739431,seq10:0.1426713016):0.0603002256,seq07:0.0060650127):0.0021053210,seq09:0.0050434256,seq08:0.0060928522)[2.1250209625413596E-70];
+(((((((seq04:0.0020039070,seq03:0.0010035673):0.0067284599,(seq02:0.0112377794,seq05:0.0079095215):0.0009235712):0.0160433685,seq01:0.0203392313):0.0077845136,seq06:0.0215830772):0.0602238630,seq10:0.1443002872):0.0611760826,seq07:0.0054445870):0.0027871862,seq09:0.0050528257,seq08:0.0060518337)[2.0740056894741138E-72];
+((((((seq05:0.0074821173,(seq02:0.0113030757,(seq04:0.0020267279,seq03:0.0010015074):0.0072204442):0.0011071576):0.0160962400,seq01:0.0208426467):0.0090799287,seq06:0.0216939651):0.0660874416,seq10:0.1740781555):0.0667885362,seq07:0.0063431934):0.0018941720,seq09:0.0052215599,seq08:0.0060441980)[5.8586243815199E-104];
+((((((seq05:0.0074681896,(seq02:0.0112904172,(seq04:0.0020242012,seq03:0.0009999433):0.0072187543):0.0011055276):0.0160814837,seq01:0.0208530480):0.0090857063,seq06:0.0217065056):0.0664546405,seq10:0.1755240452):0.0669507862,seq07:0.0063586917):0.0018650513,seq09:0.0052221492,seq08:0.0060340033)[2.757500983613677E-104];
+((((((seq05:0.0074620947,(seq02:0.0112215490,(seq04:0.0020114478,seq03:0.0009972352):0.0071500887):0.0010818454):0.0159899536,seq01:0.0205670556):0.0088603188,seq06:0.0214990066):0.0642369545,seq10:0.1692837552):0.0656716571,seq07:0.0062379978):0.0019634889,seq09:0.0051485359,seq08:0.0060212578)[3.908094526533152E-105];
+((((((seq05:0.0074178676,(seq02:0.0111284547,(seq04:0.0020057572,seq03:0.0009990083):0.0070451850):0.0011428865):0.0157078653,seq01:0.0200370209):0.0087090219,seq06:0.0209345894):0.0581338862,seq10:0.1391897197):0.0602068296,seq07:0.0060543462):0.0021623486,seq09:0.0050467770,seq08:0.0060316591)[6.962968867234838E-116];
+

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



More information about the debian-med-commit mailing list