[med-svn] [relion] 03/05: Imported Upstream version 1.3

Roland Fehrenbacher rfehren-guest at moszumanska.debian.org
Thu Oct 9 19:53:35 UTC 2014


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

rfehren-guest pushed a commit to branch master
in repository relion.

commit 1c618979e7a800928086113456370b795a6738d8
Author: Roland Fehrenbacher <rf at q-leap.de>
Date:   Tue Jul 29 14:13:13 2014 +0200

    Imported Upstream version 1.3
---
 AUTHORS                            |     8 +
 COPYING                            |   340 +
 ChangeLog                          |     0
 INSTALL                            |   268 +
 INSTALL.sh                         |    80 +
 Makefile.am                        |   316 +
 Makefile.in                        |  1601 +++
 NEWS                               |     0
 README                             |     7 +
 aclocal.m4                         |  8935 +++++++++++++++++
 autogen.sh                         |     8 +
 compile                            |   143 +
 config.guess                       |  1501 +++
 config.h.in                        |    65 +
 config.sub                         |  1705 ++++
 configure                          | 18370 +++++++++++++++++++++++++++++++++++
 configure.ac                       |    84 +
 depcomp                            |   630 ++
 external/fftw-3.2.2.tar.gz         |   Bin 0 -> 3495117 bytes
 external/fltk-1.3.0.tar.gz         |   Bin 0 -> 4111820 bytes
 install-sh                         |   520 +
 ltmain.sh                          |  8406 ++++++++++++++++
 missing                            |   376 +
 relion.h                           |    55 +
 relion.pc.in                       |    11 +
 scripts/qsub.csh                   |    12 +
 scripts/star_datablock_ctfdat      |    24 +
 scripts/star_datablock_singlefiles |    29 +
 scripts/star_datablock_stack       |    29 +
 scripts/star_loopheader            |    31 +
 scripts/star_plottable             |    29 +
 scripts/star_printtable            |    28 +
 src/Healpix_2.15a/arr.h            |   447 +
 src/Healpix_2.15a/cxxutils.cc      |   297 +
 src/Healpix_2.15a/cxxutils.h       |   268 +
 src/Healpix_2.15a/datatypes.h      |   224 +
 src/Healpix_2.15a/geom_utils.h     |    64 +
 src/Healpix_2.15a/healpix_base.cc  |   784 ++
 src/Healpix_2.15a/healpix_base.h   |   285 +
 src/Healpix_2.15a/lsconstants.h    |   112 +
 src/Healpix_2.15a/message_error.h  |    96 +
 src/Healpix_2.15a/openmp_support.h |    86 +
 src/Healpix_2.15a/pointing.h       |   115 +
 src/Healpix_2.15a/vec3.h           |   125 +
 src/apps/autopick.cpp              |    46 +
 src/apps/autopick_mpi.cpp          |    46 +
 src/apps/display.cpp               |    61 +
 src/apps/find_tiltpairs.cpp        |   503 +
 src/apps/image_handler.cpp         |   465 +
 src/apps/maingui.cpp               |    66 +
 src/apps/manualpick.cpp            |    54 +
 src/apps/mask_create.cpp           |   170 +
 src/apps/particle_polish.cpp       |    46 +
 src/apps/particle_polish_mpi.cpp   |    46 +
 src/apps/particle_sort.cpp         |    49 +
 src/apps/particle_sort_mpi.cpp     |    46 +
 src/apps/postprocess.cpp           |    46 +
 src/apps/preprocess.cpp            |    48 +
 src/apps/preprocess_mpi.cpp        |    48 +
 src/apps/project.cpp               |   329 +
 src/apps/reconstruct.cpp           |   449 +
 src/apps/refine.cpp                |    51 +
 src/apps/refine_mpi.cpp            |    57 +
 src/apps/run_ctffind.cpp           |    47 +
 src/apps/run_ctffind_mpi.cpp       |    47 +
 src/apps/stack_create.cpp          |   216 +
 src/args.cpp                       |   364 +
 src/args.h                         |   208 +
 src/assembly.cpp                   |   420 +
 src/assembly.h                     |   253 +
 src/autopicker.cpp                 |   870 ++
 src/autopicker.h                   |   150 +
 src/autopicker_mpi.cpp             |    70 +
 src/autopicker_mpi.h               |    37 +
 src/backprojector.cpp              |  1323 +++
 src/backprojector.h                |   276 +
 src/complex.cpp                    |   164 +
 src/complex.h                      |    84 +
 src/ctf.cpp                        |   203 +
 src/ctf.h                          |   217 +
 src/ctffind_runner.cpp             |   307 +
 src/ctffind_runner.h               |   115 +
 src/ctffind_runner_mpi.cpp         |    78 +
 src/ctffind_runner_mpi.h           |    50 +
 src/displayer.cpp                  |  1965 ++++
 src/displayer.h                    |   490 +
 src/error.cpp                      |    63 +
 src/error.h                        |    90 +
 src/euler.cpp                      |   392 +
 src/euler.h                        |   311 +
 src/exp_model.cpp                  |  1122 +++
 src/exp_model.h                    |   438 +
 src/fftw.cpp                       |  1149 +++
 src/fftw.h                         |   841 ++
 src/filename.cpp                   |   434 +
 src/filename.h                     |   520 +
 src/funcs.cpp                      |   733 ++
 src/funcs.h                        |   499 +
 src/gcc_version.h                  |    67 +
 src/gui_entries.cpp                |   655 ++
 src/gui_entries.h                  |   418 +
 src/gui_jobwindow.cpp              |  3132 ++++++
 src/gui_jobwindow.h                |   708 ++
 src/gui_mainwindow.cpp             |   583 ++
 src/gui_mainwindow.h               |   134 +
 src/healpix_sampling.cpp           |  1964 ++++
 src/healpix_sampling.h             |   362 +
 src/image.cpp                      |   199 +
 src/image.h                        |  1329 +++
 src/macros.h                       |   391 +
 src/manualpicker.cpp               |   510 +
 src/manualpicker.h                 |   124 +
 src/mask.cpp                       |   332 +
 src/mask.h                         |    47 +
 src/matrix1d.cpp                   |    71 +
 src/matrix1d.h                     |  1288 +++
 src/matrix2d.cpp                   |    36 +
 src/matrix2d.h                     |  1492 +++
 src/memory.cpp                     |    56 +
 src/memory.h                       |   189 +
 src/metadata_container.cpp         |   486 +
 src/metadata_container.h           |   174 +
 src/metadata_label.cpp             |   140 +
 src/metadata_label.h               |   644 ++
 src/metadata_table.cpp             |   801 ++
 src/metadata_table.h               |   399 +
 src/ml_model.cpp                   |  1272 +++
 src/ml_model.h                     |   293 +
 src/ml_optimiser.cpp               |  5784 +++++++++++
 src/ml_optimiser.h                 |   631 ++
 src/ml_optimiser_mpi.cpp           |  1680 ++++
 src/ml_optimiser_mpi.h             |   139 +
 src/mpi.cpp                        |   250 +
 src/mpi.h                          |    91 +
 src/multidim_array.cpp             |    77 +
 src/multidim_array.h               |  4261 ++++++++
 src/numerical_recipes.cpp          |  1340 +++
 src/numerical_recipes.h            |   273 +
 src/parallel.cpp                   |   339 +
 src/parallel.h                     |   401 +
 src/particle_polisher.cpp          |  1616 +++
 src/particle_polisher.h            |   225 +
 src/particle_polisher_mpi.cpp      |   428 +
 src/particle_polisher_mpi.h        |    67 +
 src/particle_sorter.cpp            |   693 ++
 src/particle_sorter.h              |   126 +
 src/particle_sorter_mpi.cpp        |    91 +
 src/particle_sorter_mpi.h          |    51 +
 src/postprocessing.cpp             |   647 ++
 src/postprocessing.h               |   151 +
 src/preprocessing.cpp              |   849 ++
 src/preprocessing.h                |   167 +
 src/preprocessing_mpi.cpp          |   107 +
 src/preprocessing_mpi.h            |    50 +
 src/projector.cpp                  |   478 +
 src/projector.h                    |   230 +
 src/rwIMAGIC.h                     |   343 +
 src/rwMRC.h                        |   472 +
 src/rwSPIDER.h                     |   427 +
 src/strings.cpp                    |   546 ++
 src/strings.h                      |   404 +
 src/symmetries.cpp                 |   921 ++
 src/symmetries.h                   |   272 +
 src/tabfuncs.cpp                   |   122 +
 src/tabfuncs.h                     |   154 +
 src/time.cpp                       |   239 +
 src/time.h                         |   284 +
 src/transformations.cpp            |   223 +
 src/transformations.h              |   960 ++
 169 files changed, 108591 insertions(+)

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..fb0a127
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,8 @@
+This program is developed in the group of Sjors H.W. Scheres at the MRC Laboratory of Molecular Biology.
+
+However, it does also contain pieces of code from the following packages:
+XMIPP: http:/xmipp.cnb.csic.es
+BSOFT: http://lsbr.niams.nih.gov/bsoft/
+HEALPIX: http://healpix.jpl.nasa.gov/
+
+Original disclaimers in the code of these external packages have been maintained as much as possible. Please contact Sjors Scheres (scheres at mrc-lmb.cam.ac.uk) if you feel this has not been done correctly. 
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..623b625
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..4ce7af4
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,268 @@
+Specific Relion Installation Instructions
+**************************************************
+
+Note that compilation of the parallel version of RELION needs an
+existing MPI installation on your system. We use the open-source
+flavour openMPI, but any flavour will probably do. Just make sure the
+mpi executables (e.g. mpiCC and mpirun) are in your PATH and the
+libraries are in your LD_LIBRARY_PATH. We use the following lines in
+our .cshrc:
+
+setenv PATH /public/EM/OpenMPI/bin:$PATH
+setenv LD_LIBRARY_PATH /public/EM/OpenMPI/lib:$LD_LIBRARY_PATH
+
+Together with the RELION source code, come tar.gz files for fftw-3.2.2
+and fltk-1.3.0. These two external libraries are needed to build
+RELION. Standard installation of the whole package, including these
+external libraries is performed by executing the following command:
+
+./INSTALL.sh -j 8
+
+Where -j 8 indicates that 8 threads may be used in parallel for
+compilation. By default the package will be built inside the relion
+directory. Edit the PREFIX variable in the INSTALL.sh script to change
+this.
+
+See the RELION wiki pages (http://www2.mrc-lmb.cam.ac.uk/relion) for
+more details, e.g. on how to use pre-existing builds of fftw or fltk
+on your system.
+
+What follows is only useful if you want to configure RELION in
+non-standard ways.
+
+General Automake Installation Instructions
+**************************************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).  Here is a another example:
+
+     /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/INSTALL.sh b/INSTALL.sh
new file mode 100755
index 0000000..481a2f5
--- /dev/null
+++ b/INSTALL.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env sh
+
+#Some flags variables
+BUILD_FFTW=true
+BUILD_FLTK=true
+BUILD_RELION=true
+N_THREADS=$@
+
+# do we have mpi and fltk?
+# Set the param below to "false" if you do not have an MPI installation and only want to build the sequential version of RELION
+HAVE_MPI=true
+# Set the param below to "false" if you have trouble compiling fltk and still want to build RELION without the GUI
+HAVE_FLTK=true
+
+#Some path variables
+# Note that as of RELION-1.3, the prefix actually needs to be RELION_HOME. You can move the bin and lib directories elsewhere after building
+RELION_HOME=$PWD
+PREFIX=$RELION_HOME
+
+#External libraries versions
+VFFTW=fftw-3.2.2
+VFLTK=fltk-1.3.0
+
+# Some other vars
+GREEN="\033[32m"
+ENDC="\033[0m"
+
+
+
+#################### FFTW ###########################
+# In case Fortran compilation fails consider adding  --disable-fortran to the ./configure line below. 
+if $BUILD_FFTW; then
+  echo -e "$GREEN Compiling $VFFTW ...$ENDC"
+  echo -e "See $RELION_HOME/external/fftw_build.log for details"
+  cd external
+  tar -zxf $VFFTW.tar.gz
+  cd $VFFTW
+  ./configure --enable-threads --enable-shared prefix=$PREFIX > $RELION_HOME/external/fftw_build.log
+  make $N_THREADS >> $RELION_HOME/external/fftw_build.log 
+  make install >> $RELION_HOME/external/fftw_build.log 
+  cd ../..
+fi
+
+#################### FLTK ###########################
+if $BUILD_FLTK; then
+  echo -e "$GREEN Compiling $VFLTK ...$ENDC"
+  echo -e "See $RELION_HOME/external/fltk_build.log for details"
+  cd external
+  tar -zxf $VFLTK.tar.gz
+  cd $VFLTK
+  ./configure --enable-shared prefix=$PREFIX > $RELION_HOME/external/fltk_build.log
+  make $N_THREADS >> $RELION_HOME/external/fltk_build.log
+  make install >> $RELION_HOME/external/fltk_build.log
+  cd ../..
+fi
+
+#################### RELION ###########################
+if $BUILD_RELION; then
+  echo -e "$GREEN Compiling relion ...$ENDC"
+  echo -e "See $RELION_HOME/relion_build.log for details"
+ if $HAVE_FLTK; then
+  fltk_cxx=`$PREFIX/bin/fltk-config --cxxflags`
+  fltk_ld=`$PREFIX/bin/fltk-config --ldflags`
+ else
+  fltk_cxx=""
+  fltk_ld=""
+ fi
+ if $HAVE_MPI; then
+  ./configure prefix=$PREFIX --enable-mpi CPPFLAGS="-I$PREFIX/include $fltk_cxx"  LDFLAGS="-L$PREFIX/lib $fltk_ld" > $RELION_HOME/relion_build.log
+ else
+  ./configure prefix=$PREFIX CPPFLAGS="-I$PREFIX/include $fltk_cxx"  LDFLAGS="-L$PREFIX/lib $fltk_ld" > $RELION_HOME/relion_build.log
+ fi
+ make $N_THREADS >> $RELION_HOME/relion_build.log
+ make install >> $RELION_HOME/relion_build.log
+ mv $RELION_HOME/bin/relion_maingui $PREFIX/bin/relion 
+ cp $RELION_HOME/scripts/qsub.csh $PREFIX/bin/qsub.csh
+fi
+
+echo "Done!"
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..9897ebb
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,316 @@
+## LibRelion:
+
+## Place generated object files (.o) into the same directory as their source
+## files, in order to avoid collisions when non-recursive make is used.
+AUTOMAKE_OPTIONS = subdir-objects
+
+## Additional flags to pass to aclocal when it is invoked automatically at
+## make time. The ${ACLOCAL_FLAGS} variable is picked up from the environment
+## to provide a way for the user to supply additional arguments.
+ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS}
+
+## Define an independent executable script for inclusion in the distribution
+## archive.  However, it will not be installed on an end user's system due to
+## the noinst_ prefix.
+dist_noinst_SCRIPTS = autogen.sh
+
+# Install my_script in $(bindir) and distribute it.
+dist_bin_SCRIPTS = \
+scripts/star_datablock_ctfdat \
+scripts/star_datablock_stack \
+scripts/star_datablock_singlefiles \
+scripts/star_loopheader \
+scripts/star_plottable \
+scripts/star_printtable \
+scripts/qsub.csh
+
+### Include tar.gz of FFTW and FLTK in distribution, as well as all source files for the GUI
+EXTRA_DIST = INSTALL.sh \
+external/fftw-3.2.2.tar.gz \
+external/fltk-1.3.0.tar.gz 
+
+###############################################################################
+#
+# Core library
+#
+###############################################################################
+
+## Define a libtool archive target "librelion- at RELION_API_VERSION@.la", with
+## @RELION_API_VERSION@ substituted into the generated Makefile at configure
+## time.
+## The libtool archive file (.la) will be installed into the directory named
+## by the predefined variable $(bindir), along with the actual shared library
+## file (.so).
+lib_LTLIBRARIES = librelion- at RELION_API_VERSION@.la
+
+## Define the source file list for the "librelion- at RELION_API_VERSION@.la"
+## target.  Note that @RELION_API_VERSION@ is not interpreted by Automake and
+## will therefore be treated as if it were literally part of the target name,
+## and the variable name derived from that.
+## The file extension .cc is recognized by Automake, and makes it produce
+## rules which invoke the C++ compiler to produce a libtool object file (.lo)
+## from each source file.  Note that it is not necessary to list header files
+## which are already listed elsewhere in a _HEADERS variable assignment.
+librelion_ at RELION_API_VERSION@_la_SOURCES = src/args.cpp \
+src/assembly.cpp \
+src/autopicker.cpp \
+src/backprojector.cpp \
+src/complex.cpp \
+src/ctf.cpp \
+src/ctffind_runner.cpp \
+src/error.cpp \
+src/euler.cpp \
+src/exp_model.cpp \
+src/fftw.cpp \
+src/filename.cpp \
+src/funcs.cpp \
+src/healpix_sampling.cpp \
+src/image.cpp \
+src/mask.cpp \
+src/matrix1d.cpp \
+src/matrix2d.cpp \
+src/memory.cpp \
+src/metadata_container.cpp \
+src/metadata_label.cpp \
+src/metadata_table.cpp \
+src/ml_model.cpp \
+src/ml_optimiser.cpp \
+src/multidim_array.cpp \
+src/numerical_recipes.cpp \
+src/parallel.cpp \
+src/particle_polisher.cpp \
+src/particle_sorter.cpp \
+src/postprocessing.cpp \
+src/preprocessing.cpp \
+src/projector.cpp \
+src/strings.cpp \
+src/symmetries.cpp \
+src/tabfuncs.cpp \
+src/time.cpp \
+src/transformations.cpp \
+src/Healpix_2.15a/cxxutils.cc \
+src/Healpix_2.15a/healpix_base.cc 
+
+## Define the list of public header files and their install location.  The
+## nobase_ prefix instructs Automake to not strip the directory part from each
+## filename, in order to avoid the need to define separate file lists for each
+## installation directory.  This only works if the directory hierarchy in the
+## source tree matches the hierarchy at the install location, however.
+relion_includedir = $(includedir)/relion-$(RELION_API_VERSION)
+nobase_relion_include_HEADERS = relion.h \
+src/args.h \
+src/assembly.h \
+src/autopicker.h \
+src/backprojector.h \
+src/complex.h \
+src/ctf.h \
+src/ctffind_runner.h \
+src/displayer.h \
+src/error.h \
+src/euler.h \
+src/exp_model.h \
+src/fftw.h \
+src/filename.h \
+src/funcs.h \
+src/gcc_version.h \
+src/gui_entries.h \
+src/gui_jobwindow.h \
+src/gui_mainwindow.h \
+src/healpix_sampling.h \
+src/image.h \
+src/macros.h \
+src/mask.h \
+src/matrix1d.h \
+src/matrix2d.h \
+src/memory.h \
+src/metadata_container.h \
+src/metadata_label.h \
+src/metadata_table.h \
+src/ml_model.h \
+src/ml_optimiser.h \
+src/multidim_array.h \
+src/numerical_recipes.h \
+src/parallel.h \
+src/particle_polisher.h \
+src/particle_sorter.h \
+src/postprocessing.h \
+src/preprocessing.h \
+src/projector.h \
+src/rwIMAGIC.h \
+src/rwMRC.h \
+src/rwSPIDER.h \
+src/strings.h \
+src/symmetries.h \
+src/tabfuncs.h \
+src/time.h \
+src/transformations.h \
+src/Healpix_2.15a/arr.h \
+src/Healpix_2.15a/cxxutils.h \
+src/Healpix_2.15a/datatypes.h \
+src/Healpix_2.15a/geom_utils.h \
+src/Healpix_2.15a/lsconstants.h \
+src/Healpix_2.15a/message_error.h \
+src/Healpix_2.15a/openmp_support.h \
+src/Healpix_2.15a/pointing.h \
+src/Healpix_2.15a/vec3.h \
+src/Healpix_2.15a/healpix_base.h 
+
+if HAVE_MPI
+ librelion_ at RELION_API_VERSION@_la_SOURCES += src/mpi.cpp \
+ src/autopicker_mpi.cpp \
+ src/ctffind_runner_mpi.cpp \
+ src/particle_polisher_mpi.cpp \
+ src/particle_sorter_mpi.cpp \
+ src/preprocessing_mpi.cpp \
+ src/ml_optimiser_mpi.cpp
+ nobase_relion_include_HEADERS += src/mpi.h \
+ src/autopicker_mpi.h \
+ src/ctffind_runner_mpi.h \
+ src/particle_polisher_mpi.h \
+ src/particle_sorter_mpi.h \
+ src/preprocessing_mpi.h \
+ src/ml_optimiser_mpi.h
+endif
+
+if HAVE_FLTK
+ librelion_ at RELION_API_VERSION@_la_SOURCES += src/displayer.cpp \
+ src/gui_entries.cpp \
+ src/gui_jobwindow.cpp \
+ src/gui_mainwindow.cpp \
+ src/manualpicker.cpp 
+ nobase_relion_include_HEADERS += src/displayer.h \
+ src/gui_entries.h \
+ src/gui_jobwindow.h \
+ src/gui_mainwindow.h \
+ src/manualpicker.h 
+endif
+
+## Instruct libtool to include ABI version information in the generated shared
+## library file (.so).  The library ABI version is defined in configure.ac, so
+## that all version information is kept in one place.
+librelion_ at RELION_API_VERSION@_la_LDFLAGS = -version-info $(RELION_SO_VERSION) $(FFT_LIBS)
+
+## The generated configuration header is installed in its own subdirectory of
+## $(libdir).  The reason for this is that the configuration information put
+## into this header file describes the target platform the installed library
+## has been built for.  Thus the file must not be installed into a location
+## intended for architecture-independent files, as defined by the Filesystem
+## Hierarchy Standard (FHS).
+relion_libincludedir = $(libdir)/relion-$(RELION_API_VERSION)/include
+
+## Install the generated pkg-config file (.pc) into the expected location for
+## architecture-dependent package configuration information.  Occasionally,
+## pkg-config files are also used for architecture-independent data packages,
+## in which case the correct install location would be $(datadir)/pkgconfig.
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = relion-$(RELION_API_VERSION).pc
+
+
+###############################################################################
+#
+# Applications
+#
+###############################################################################
+
+bin_PROGRAMS = project reconstruct refine preprocess postprocess autopick particle_polish particle_sort run_ctffind
+if HAVE_MPI
+ bin_PROGRAMS += refine_mpi preprocess_mpi autopick_mpi particle_polish_mpi particle_sort_mpi run_ctffind_mpi
+endif
+if HAVE_FLTK
+ bin_PROGRAMS += manualpick display maingui 	
+endif
+
+RelionLibs = librelion-$(RELION_API_VERSION).la 
+
+refine_SOURCES = src/apps/refine.cpp
+refine_LDADD = $(RelionLibs) 
+
+refine_mpi_SOURCES = src/apps/refine_mpi.cpp
+refine_mpi_LDADD = $(RelionLibs)
+
+reconstruct_SOURCES = src/apps/reconstruct.cpp
+reconstruct_LDADD = $(RelionLibs)
+
+project_SOURCES = src/apps/project.cpp
+project_LDADD = $(RelionLibs)
+
+postprocess_SOURCES = src/apps/postprocess.cpp
+postprocess_LDADD = $(RelionLibs)
+
+preprocess_SOURCES = src/apps/preprocess.cpp
+preprocess_LDADD = $(RelionLibs)
+
+preprocess_mpi_SOURCES = src/apps/preprocess_mpi.cpp
+preprocess_mpi_LDADD = $(RelionLibs)
+
+autopick_SOURCES = src/apps/autopick.cpp
+autopick_LDADD = $(RelionLibs)
+
+autopick_mpi_SOURCES = src/apps/autopick_mpi.cpp
+autopick_mpi_LDADD = $(RelionLibs)
+
+manualpick_SOURCES = src/apps/manualpick.cpp
+manualpick_LDADD = $(RelionLibs)
+
+particle_polish_SOURCES = src/apps/particle_polish.cpp
+particle_polish_LDADD = $(RelionLibs)
+
+particle_polish_mpi_SOURCES = src/apps/particle_polish_mpi.cpp
+particle_polish_mpi_LDADD = $(RelionLibs)
+
+particle_sort_SOURCES = src/apps/particle_sort.cpp
+particle_sort_LDADD = $(RelionLibs)
+
+particle_sort_mpi_SOURCES = src/apps/particle_sort_mpi.cpp
+particle_sort_mpi_LDADD = $(RelionLibs)
+
+run_ctffind_SOURCES = src/apps/run_ctffind.cpp
+run_ctffind_LDADD = $(RelionLibs)
+
+run_ctffind_mpi_SOURCES = src/apps/run_ctffind_mpi.cpp
+run_ctffind_mpi_LDADD = $(RelionLibs)
+
+display_SOURCES = src/apps/display.cpp
+display_LDADD = $(RelionLibs)
+
+maingui_SOURCES = src/apps/maingui.cpp
+maingui_LDADD = $(RelionLibs)
+
+bin_PROGRAMS += mask_create
+mask_create_SOURCES = src/apps/mask_create.cpp
+mask_create_LDADD = $(RelionLibs)
+
+bin_PROGRAMS += stack_create
+stack_create_SOURCES = src/apps/stack_create.cpp
+stack_create_LDADD = $(RelionLibs)
+
+bin_PROGRAMS += image_handler 
+image_handler_SOURCES = src/apps/image_handler.cpp
+image_handler_LDADD = $(RelionLibs)
+
+bin_PROGRAMS += find_tiltpairs
+find_tiltpairs_SOURCES = src/apps/find_tiltpairs.cpp
+find_tiltpairs_LDADD = $(RelionLibs)
+
+#bin_PROGRAMS += denovo_model
+#denovo_model_SOURCES = src/apps/denovo_model.cpp
+#denovo_model_LDADD = $(RelionLibs)
+
+#bin_PROGRAMS += tester
+#tester_SOURCES = src/apps/tester.cpp
+#tester_LDADD = $(RelionLibs)
+
+#bin_PROGRAMS += fsc2bfac 
+#fsc2bfac_SOURCES = src/apps/fsc2bfac.cpp
+#fsc2bfac_LDADD = $(RelionLibs)
+
+#bin_PROGRAMS += convert_bild2map
+#convert_bild2map_SOURCES = src/apps/convert_bild2map.cpp
+#convert_bild2map_LDADD = $(RelionLibs)
+
+#bin_PROGRAMS += composite_map
+#composite_map_SOURCES = src/apps/composite_map.cpp
+#composite_map_LDADD = $(RelionLibs)
+
+
+
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..4227e8d
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,1601 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+ at HAVE_MPI_TRUE@am__append_1 = src/mpi.cpp \
+ at HAVE_MPI_TRUE@ src/autopicker_mpi.cpp \
+ at HAVE_MPI_TRUE@ src/ctffind_runner_mpi.cpp \
+ at HAVE_MPI_TRUE@ src/particle_polisher_mpi.cpp \
+ at HAVE_MPI_TRUE@ src/particle_sorter_mpi.cpp \
+ at HAVE_MPI_TRUE@ src/preprocessing_mpi.cpp \
+ at HAVE_MPI_TRUE@ src/ml_optimiser_mpi.cpp
+
+ at HAVE_MPI_TRUE@am__append_2 = src/mpi.h \
+ at HAVE_MPI_TRUE@ src/autopicker_mpi.h \
+ at HAVE_MPI_TRUE@ src/ctffind_runner_mpi.h \
+ at HAVE_MPI_TRUE@ src/particle_polisher_mpi.h \
+ at HAVE_MPI_TRUE@ src/particle_sorter_mpi.h \
+ at HAVE_MPI_TRUE@ src/preprocessing_mpi.h \
+ at HAVE_MPI_TRUE@ src/ml_optimiser_mpi.h
+
+ at HAVE_FLTK_TRUE@am__append_3 = src/displayer.cpp \
+ at HAVE_FLTK_TRUE@ src/gui_entries.cpp \
+ at HAVE_FLTK_TRUE@ src/gui_jobwindow.cpp \
+ at HAVE_FLTK_TRUE@ src/gui_mainwindow.cpp \
+ at HAVE_FLTK_TRUE@ src/manualpicker.cpp 
+
+ at HAVE_FLTK_TRUE@am__append_4 = src/displayer.h \
+ at HAVE_FLTK_TRUE@ src/gui_entries.h \
+ at HAVE_FLTK_TRUE@ src/gui_jobwindow.h \
+ at HAVE_FLTK_TRUE@ src/gui_mainwindow.h \
+ at HAVE_FLTK_TRUE@ src/manualpicker.h 
+
+bin_PROGRAMS = project$(EXEEXT) reconstruct$(EXEEXT) refine$(EXEEXT) \
+	preprocess$(EXEEXT) postprocess$(EXEEXT) autopick$(EXEEXT) \
+	particle_polish$(EXEEXT) particle_sort$(EXEEXT) \
+	run_ctffind$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2) \
+	mask_create$(EXEEXT) stack_create$(EXEEXT) \
+	image_handler$(EXEEXT) find_tiltpairs$(EXEEXT)
+ at HAVE_MPI_TRUE@am__append_5 = refine_mpi preprocess_mpi autopick_mpi particle_polish_mpi particle_sort_mpi run_ctffind_mpi
+ at HAVE_FLTK_TRUE@am__append_6 = manualpick display maingui 	
+subdir = .
+DIST_COMMON = README $(am__configure_deps) \
+	$(am__nobase_relion_include_HEADERS_DIST) $(dist_bin_SCRIPTS) \
+	$(dist_noinst_SCRIPTS) $(srcdir)/Makefile.am \
+	$(srcdir)/Makefile.in $(srcdir)/config.h.in \
+	$(srcdir)/relion.pc.in $(top_srcdir)/configure AUTHORS COPYING \
+	ChangeLog INSTALL NEWS compile config.guess config.sub depcomp \
+	install-sh ltmain.sh missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = relion-${RELION_API_VERSION}.pc
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
+	"$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgconfigdir)" \
+	"$(DESTDIR)$(relion_includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+librelion_ at RELION_API_VERSION@_la_LIBADD =
+am__librelion_ at RELION_API_VERSION@_la_SOURCES_DIST = src/args.cpp \
+	src/assembly.cpp src/autopicker.cpp src/backprojector.cpp \
+	src/complex.cpp src/ctf.cpp src/ctffind_runner.cpp \
+	src/error.cpp src/euler.cpp src/exp_model.cpp src/fftw.cpp \
+	src/filename.cpp src/funcs.cpp src/healpix_sampling.cpp \
+	src/image.cpp src/mask.cpp src/matrix1d.cpp src/matrix2d.cpp \
+	src/memory.cpp src/metadata_container.cpp \
+	src/metadata_label.cpp src/metadata_table.cpp src/ml_model.cpp \
+	src/ml_optimiser.cpp src/multidim_array.cpp \
+	src/numerical_recipes.cpp src/parallel.cpp \
+	src/particle_polisher.cpp src/particle_sorter.cpp \
+	src/postprocessing.cpp src/preprocessing.cpp src/projector.cpp \
+	src/strings.cpp src/symmetries.cpp src/tabfuncs.cpp \
+	src/time.cpp src/transformations.cpp \
+	src/Healpix_2.15a/cxxutils.cc \
+	src/Healpix_2.15a/healpix_base.cc src/mpi.cpp \
+	src/autopicker_mpi.cpp src/ctffind_runner_mpi.cpp \
+	src/particle_polisher_mpi.cpp src/particle_sorter_mpi.cpp \
+	src/preprocessing_mpi.cpp src/ml_optimiser_mpi.cpp \
+	src/displayer.cpp src/gui_entries.cpp src/gui_jobwindow.cpp \
+	src/gui_mainwindow.cpp src/manualpicker.cpp
+am__dirstamp = $(am__leading_dot)dirstamp
+ at HAVE_MPI_TRUE@am__objects_1 = src/mpi.lo src/autopicker_mpi.lo \
+ at HAVE_MPI_TRUE@	src/ctffind_runner_mpi.lo \
+ at HAVE_MPI_TRUE@	src/particle_polisher_mpi.lo \
+ at HAVE_MPI_TRUE@	src/particle_sorter_mpi.lo \
+ at HAVE_MPI_TRUE@	src/preprocessing_mpi.lo \
+ at HAVE_MPI_TRUE@	src/ml_optimiser_mpi.lo
+ at HAVE_FLTK_TRUE@am__objects_2 = src/displayer.lo src/gui_entries.lo \
+ at HAVE_FLTK_TRUE@	src/gui_jobwindow.lo src/gui_mainwindow.lo \
+ at HAVE_FLTK_TRUE@	src/manualpicker.lo
+am_librelion_ at RELION_API_VERSION@_la_OBJECTS = src/args.lo \
+	src/assembly.lo src/autopicker.lo src/backprojector.lo \
+	src/complex.lo src/ctf.lo src/ctffind_runner.lo src/error.lo \
+	src/euler.lo src/exp_model.lo src/fftw.lo src/filename.lo \
+	src/funcs.lo src/healpix_sampling.lo src/image.lo src/mask.lo \
+	src/matrix1d.lo src/matrix2d.lo src/memory.lo \
+	src/metadata_container.lo src/metadata_label.lo \
+	src/metadata_table.lo src/ml_model.lo src/ml_optimiser.lo \
+	src/multidim_array.lo src/numerical_recipes.lo src/parallel.lo \
+	src/particle_polisher.lo src/particle_sorter.lo \
+	src/postprocessing.lo src/preprocessing.lo src/projector.lo \
+	src/strings.lo src/symmetries.lo src/tabfuncs.lo src/time.lo \
+	src/transformations.lo src/Healpix_2.15a/cxxutils.lo \
+	src/Healpix_2.15a/healpix_base.lo $(am__objects_1) \
+	$(am__objects_2)
+librelion_ at RELION_API_VERSION@_la_OBJECTS =  \
+	$(am_librelion_ at RELION_API_VERSION@_la_OBJECTS)
+librelion_ at RELION_API_VERSION@_la_LINK = $(LIBTOOL) --tag=CXX \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+	$(AM_CXXFLAGS) $(CXXFLAGS) \
+	$(librelion_ at RELION_API_VERSION@_la_LDFLAGS) $(LDFLAGS) -o $@
+ at HAVE_MPI_TRUE@am__EXEEXT_1 = refine_mpi$(EXEEXT) \
+ at HAVE_MPI_TRUE@	preprocess_mpi$(EXEEXT) autopick_mpi$(EXEEXT) \
+ at HAVE_MPI_TRUE@	particle_polish_mpi$(EXEEXT) \
+ at HAVE_MPI_TRUE@	particle_sort_mpi$(EXEEXT) \
+ at HAVE_MPI_TRUE@	run_ctffind_mpi$(EXEEXT)
+ at HAVE_FLTK_TRUE@am__EXEEXT_2 = manualpick$(EXEEXT) display$(EXEEXT) \
+ at HAVE_FLTK_TRUE@	maingui$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS)
+am_autopick_OBJECTS = src/apps/autopick.$(OBJEXT)
+autopick_OBJECTS = $(am_autopick_OBJECTS)
+autopick_DEPENDENCIES = $(RelionLibs)
+am_autopick_mpi_OBJECTS = src/apps/autopick_mpi.$(OBJEXT)
+autopick_mpi_OBJECTS = $(am_autopick_mpi_OBJECTS)
+autopick_mpi_DEPENDENCIES = $(RelionLibs)
+am_display_OBJECTS = src/apps/display.$(OBJEXT)
+display_OBJECTS = $(am_display_OBJECTS)
+display_DEPENDENCIES = $(RelionLibs)
+am_find_tiltpairs_OBJECTS = src/apps/find_tiltpairs.$(OBJEXT)
+find_tiltpairs_OBJECTS = $(am_find_tiltpairs_OBJECTS)
+find_tiltpairs_DEPENDENCIES = $(RelionLibs)
+am_image_handler_OBJECTS = src/apps/image_handler.$(OBJEXT)
+image_handler_OBJECTS = $(am_image_handler_OBJECTS)
+image_handler_DEPENDENCIES = $(RelionLibs)
+am_maingui_OBJECTS = src/apps/maingui.$(OBJEXT)
+maingui_OBJECTS = $(am_maingui_OBJECTS)
+maingui_DEPENDENCIES = $(RelionLibs)
+am_manualpick_OBJECTS = src/apps/manualpick.$(OBJEXT)
+manualpick_OBJECTS = $(am_manualpick_OBJECTS)
+manualpick_DEPENDENCIES = $(RelionLibs)
+am_mask_create_OBJECTS = src/apps/mask_create.$(OBJEXT)
+mask_create_OBJECTS = $(am_mask_create_OBJECTS)
+mask_create_DEPENDENCIES = $(RelionLibs)
+am_particle_polish_OBJECTS = src/apps/particle_polish.$(OBJEXT)
+particle_polish_OBJECTS = $(am_particle_polish_OBJECTS)
+particle_polish_DEPENDENCIES = $(RelionLibs)
+am_particle_polish_mpi_OBJECTS =  \
+	src/apps/particle_polish_mpi.$(OBJEXT)
+particle_polish_mpi_OBJECTS = $(am_particle_polish_mpi_OBJECTS)
+particle_polish_mpi_DEPENDENCIES = $(RelionLibs)
+am_particle_sort_OBJECTS = src/apps/particle_sort.$(OBJEXT)
+particle_sort_OBJECTS = $(am_particle_sort_OBJECTS)
+particle_sort_DEPENDENCIES = $(RelionLibs)
+am_particle_sort_mpi_OBJECTS = src/apps/particle_sort_mpi.$(OBJEXT)
+particle_sort_mpi_OBJECTS = $(am_particle_sort_mpi_OBJECTS)
+particle_sort_mpi_DEPENDENCIES = $(RelionLibs)
+am_postprocess_OBJECTS = src/apps/postprocess.$(OBJEXT)
+postprocess_OBJECTS = $(am_postprocess_OBJECTS)
+postprocess_DEPENDENCIES = $(RelionLibs)
+am_preprocess_OBJECTS = src/apps/preprocess.$(OBJEXT)
+preprocess_OBJECTS = $(am_preprocess_OBJECTS)
+preprocess_DEPENDENCIES = $(RelionLibs)
+am_preprocess_mpi_OBJECTS = src/apps/preprocess_mpi.$(OBJEXT)
+preprocess_mpi_OBJECTS = $(am_preprocess_mpi_OBJECTS)
+preprocess_mpi_DEPENDENCIES = $(RelionLibs)
+am_project_OBJECTS = src/apps/project.$(OBJEXT)
+project_OBJECTS = $(am_project_OBJECTS)
+project_DEPENDENCIES = $(RelionLibs)
+am_reconstruct_OBJECTS = src/apps/reconstruct.$(OBJEXT)
+reconstruct_OBJECTS = $(am_reconstruct_OBJECTS)
+reconstruct_DEPENDENCIES = $(RelionLibs)
+am_refine_OBJECTS = src/apps/refine.$(OBJEXT)
+refine_OBJECTS = $(am_refine_OBJECTS)
+refine_DEPENDENCIES = $(RelionLibs)
+am_refine_mpi_OBJECTS = src/apps/refine_mpi.$(OBJEXT)
+refine_mpi_OBJECTS = $(am_refine_mpi_OBJECTS)
+refine_mpi_DEPENDENCIES = $(RelionLibs)
+am_run_ctffind_OBJECTS = src/apps/run_ctffind.$(OBJEXT)
+run_ctffind_OBJECTS = $(am_run_ctffind_OBJECTS)
+run_ctffind_DEPENDENCIES = $(RelionLibs)
+am_run_ctffind_mpi_OBJECTS = src/apps/run_ctffind_mpi.$(OBJEXT)
+run_ctffind_mpi_OBJECTS = $(am_run_ctffind_mpi_OBJECTS)
+run_ctffind_mpi_DEPENDENCIES = $(RelionLibs)
+am_stack_create_OBJECTS = src/apps/stack_create.$(OBJEXT)
+stack_create_OBJECTS = $(am_stack_create_OBJECTS)
+stack_create_DEPENDENCIES = $(RelionLibs)
+SCRIPTS = $(dist_bin_SCRIPTS) $(dist_noinst_SCRIPTS)
+DEFAULT_INCLUDES = -I. at am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+	--mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) \
+	$(LDFLAGS) -o $@
+SOURCES = $(librelion_ at RELION_API_VERSION@_la_SOURCES) \
+	$(autopick_SOURCES) $(autopick_mpi_SOURCES) $(display_SOURCES) \
+	$(find_tiltpairs_SOURCES) $(image_handler_SOURCES) \
+	$(maingui_SOURCES) $(manualpick_SOURCES) \
+	$(mask_create_SOURCES) $(particle_polish_SOURCES) \
+	$(particle_polish_mpi_SOURCES) $(particle_sort_SOURCES) \
+	$(particle_sort_mpi_SOURCES) $(postprocess_SOURCES) \
+	$(preprocess_SOURCES) $(preprocess_mpi_SOURCES) \
+	$(project_SOURCES) $(reconstruct_SOURCES) $(refine_SOURCES) \
+	$(refine_mpi_SOURCES) $(run_ctffind_SOURCES) \
+	$(run_ctffind_mpi_SOURCES) $(stack_create_SOURCES)
+DIST_SOURCES = $(am__librelion_ at RELION_API_VERSION@_la_SOURCES_DIST) \
+	$(autopick_SOURCES) $(autopick_mpi_SOURCES) $(display_SOURCES) \
+	$(find_tiltpairs_SOURCES) $(image_handler_SOURCES) \
+	$(maingui_SOURCES) $(manualpick_SOURCES) \
+	$(mask_create_SOURCES) $(particle_polish_SOURCES) \
+	$(particle_polish_mpi_SOURCES) $(particle_sort_SOURCES) \
+	$(particle_sort_mpi_SOURCES) $(postprocess_SOURCES) \
+	$(preprocess_SOURCES) $(preprocess_mpi_SOURCES) \
+	$(project_SOURCES) $(reconstruct_SOURCES) $(refine_SOURCES) \
+	$(refine_mpi_SOURCES) $(run_ctffind_SOURCES) \
+	$(run_ctffind_mpi_SOURCES) $(stack_create_SOURCES)
+DATA = $(pkgconfig_DATA)
+am__nobase_relion_include_HEADERS_DIST = relion.h src/args.h \
+	src/assembly.h src/autopicker.h src/backprojector.h \
+	src/complex.h src/ctf.h src/ctffind_runner.h src/displayer.h \
+	src/error.h src/euler.h src/exp_model.h src/fftw.h \
+	src/filename.h src/funcs.h src/gcc_version.h src/gui_entries.h \
+	src/gui_jobwindow.h src/gui_mainwindow.h \
+	src/healpix_sampling.h src/image.h src/macros.h src/mask.h \
+	src/matrix1d.h src/matrix2d.h src/memory.h \
+	src/metadata_container.h src/metadata_label.h \
+	src/metadata_table.h src/ml_model.h src/ml_optimiser.h \
+	src/multidim_array.h src/numerical_recipes.h src/parallel.h \
+	src/particle_polisher.h src/particle_sorter.h \
+	src/postprocessing.h src/preprocessing.h src/projector.h \
+	src/rwIMAGIC.h src/rwMRC.h src/rwSPIDER.h src/strings.h \
+	src/symmetries.h src/tabfuncs.h src/time.h \
+	src/transformations.h src/Healpix_2.15a/arr.h \
+	src/Healpix_2.15a/cxxutils.h src/Healpix_2.15a/datatypes.h \
+	src/Healpix_2.15a/geom_utils.h src/Healpix_2.15a/lsconstants.h \
+	src/Healpix_2.15a/message_error.h \
+	src/Healpix_2.15a/openmp_support.h \
+	src/Healpix_2.15a/pointing.h src/Healpix_2.15a/vec3.h \
+	src/Healpix_2.15a/healpix_base.h src/mpi.h \
+	src/autopicker_mpi.h src/ctffind_runner_mpi.h \
+	src/particle_polisher_mpi.h src/particle_sorter_mpi.h \
+	src/preprocessing_mpi.h src/ml_optimiser_mpi.h \
+	src/manualpicker.h
+HEADERS = $(nobase_relion_include_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  { test ! -d "$(distdir)" \
+    || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+         && rm -fr "$(distdir)"; }; }
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+distuninstallcheck_listfiles = find . -type f -print
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MPICXX = @MPICXX@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RELION_API_VERSION = @RELION_API_VERSION@
+RELION_SO_VERSION = @RELION_SO_VERSION@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = subdir-objects
+ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS}
+dist_noinst_SCRIPTS = autogen.sh
+
+# Install my_script in $(bindir) and distribute it.
+dist_bin_SCRIPTS = \
+scripts/star_datablock_ctfdat \
+scripts/star_datablock_stack \
+scripts/star_datablock_singlefiles \
+scripts/star_loopheader \
+scripts/star_plottable \
+scripts/star_printtable \
+scripts/qsub.csh
+
+
+### Include tar.gz of FFTW and FLTK in distribution, as well as all source files for the GUI
+EXTRA_DIST = INSTALL.sh \
+external/fftw-3.2.2.tar.gz \
+external/fltk-1.3.0.tar.gz 
+
+
+###############################################################################
+#
+# Core library
+#
+###############################################################################
+lib_LTLIBRARIES = librelion- at RELION_API_VERSION@.la
+librelion_ at RELION_API_VERSION@_la_SOURCES = src/args.cpp \
+	src/assembly.cpp src/autopicker.cpp src/backprojector.cpp \
+	src/complex.cpp src/ctf.cpp src/ctffind_runner.cpp \
+	src/error.cpp src/euler.cpp src/exp_model.cpp src/fftw.cpp \
+	src/filename.cpp src/funcs.cpp src/healpix_sampling.cpp \
+	src/image.cpp src/mask.cpp src/matrix1d.cpp src/matrix2d.cpp \
+	src/memory.cpp src/metadata_container.cpp \
+	src/metadata_label.cpp src/metadata_table.cpp src/ml_model.cpp \
+	src/ml_optimiser.cpp src/multidim_array.cpp \
+	src/numerical_recipes.cpp src/parallel.cpp \
+	src/particle_polisher.cpp src/particle_sorter.cpp \
+	src/postprocessing.cpp src/preprocessing.cpp src/projector.cpp \
+	src/strings.cpp src/symmetries.cpp src/tabfuncs.cpp \
+	src/time.cpp src/transformations.cpp \
+	src/Healpix_2.15a/cxxutils.cc \
+	src/Healpix_2.15a/healpix_base.cc $(am__append_1) \
+	$(am__append_3)
+relion_includedir = $(includedir)/relion-$(RELION_API_VERSION)
+nobase_relion_include_HEADERS = relion.h src/args.h src/assembly.h \
+	src/autopicker.h src/backprojector.h src/complex.h src/ctf.h \
+	src/ctffind_runner.h src/displayer.h src/error.h src/euler.h \
+	src/exp_model.h src/fftw.h src/filename.h src/funcs.h \
+	src/gcc_version.h src/gui_entries.h src/gui_jobwindow.h \
+	src/gui_mainwindow.h src/healpix_sampling.h src/image.h \
+	src/macros.h src/mask.h src/matrix1d.h src/matrix2d.h \
+	src/memory.h src/metadata_container.h src/metadata_label.h \
+	src/metadata_table.h src/ml_model.h src/ml_optimiser.h \
+	src/multidim_array.h src/numerical_recipes.h src/parallel.h \
+	src/particle_polisher.h src/particle_sorter.h \
+	src/postprocessing.h src/preprocessing.h src/projector.h \
+	src/rwIMAGIC.h src/rwMRC.h src/rwSPIDER.h src/strings.h \
+	src/symmetries.h src/tabfuncs.h src/time.h \
+	src/transformations.h src/Healpix_2.15a/arr.h \
+	src/Healpix_2.15a/cxxutils.h src/Healpix_2.15a/datatypes.h \
+	src/Healpix_2.15a/geom_utils.h src/Healpix_2.15a/lsconstants.h \
+	src/Healpix_2.15a/message_error.h \
+	src/Healpix_2.15a/openmp_support.h \
+	src/Healpix_2.15a/pointing.h src/Healpix_2.15a/vec3.h \
+	src/Healpix_2.15a/healpix_base.h $(am__append_2) \
+	$(am__append_4)
+librelion_ at RELION_API_VERSION@_la_LDFLAGS = -version-info $(RELION_SO_VERSION) $(FFT_LIBS)
+relion_libincludedir = $(libdir)/relion-$(RELION_API_VERSION)/include
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = relion-$(RELION_API_VERSION).pc
+RelionLibs = librelion-$(RELION_API_VERSION).la 
+refine_SOURCES = src/apps/refine.cpp
+refine_LDADD = $(RelionLibs) 
+refine_mpi_SOURCES = src/apps/refine_mpi.cpp
+refine_mpi_LDADD = $(RelionLibs)
+reconstruct_SOURCES = src/apps/reconstruct.cpp
+reconstruct_LDADD = $(RelionLibs)
+project_SOURCES = src/apps/project.cpp
+project_LDADD = $(RelionLibs)
+postprocess_SOURCES = src/apps/postprocess.cpp
+postprocess_LDADD = $(RelionLibs)
+preprocess_SOURCES = src/apps/preprocess.cpp
+preprocess_LDADD = $(RelionLibs)
+preprocess_mpi_SOURCES = src/apps/preprocess_mpi.cpp
+preprocess_mpi_LDADD = $(RelionLibs)
+autopick_SOURCES = src/apps/autopick.cpp
+autopick_LDADD = $(RelionLibs)
+autopick_mpi_SOURCES = src/apps/autopick_mpi.cpp
+autopick_mpi_LDADD = $(RelionLibs)
+manualpick_SOURCES = src/apps/manualpick.cpp
+manualpick_LDADD = $(RelionLibs)
+particle_polish_SOURCES = src/apps/particle_polish.cpp
+particle_polish_LDADD = $(RelionLibs)
+particle_polish_mpi_SOURCES = src/apps/particle_polish_mpi.cpp
+particle_polish_mpi_LDADD = $(RelionLibs)
+particle_sort_SOURCES = src/apps/particle_sort.cpp
+particle_sort_LDADD = $(RelionLibs)
+particle_sort_mpi_SOURCES = src/apps/particle_sort_mpi.cpp
+particle_sort_mpi_LDADD = $(RelionLibs)
+run_ctffind_SOURCES = src/apps/run_ctffind.cpp
+run_ctffind_LDADD = $(RelionLibs)
+run_ctffind_mpi_SOURCES = src/apps/run_ctffind_mpi.cpp
+run_ctffind_mpi_LDADD = $(RelionLibs)
+display_SOURCES = src/apps/display.cpp
+display_LDADD = $(RelionLibs)
+maingui_SOURCES = src/apps/maingui.cpp
+maingui_LDADD = $(RelionLibs)
+mask_create_SOURCES = src/apps/mask_create.cpp
+mask_create_LDADD = $(RelionLibs)
+stack_create_SOURCES = src/apps/stack_create.cpp
+stack_create_LDADD = $(RelionLibs)
+image_handler_SOURCES = src/apps/image_handler.cpp
+image_handler_LDADD = $(RelionLibs)
+find_tiltpairs_SOURCES = src/apps/find_tiltpairs.cpp
+find_tiltpairs_LDADD = $(RelionLibs)
+all: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .cpp .lo .o .obj
+am--refresh:
+	@:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+	@if test ! -f $@; then \
+	  rm -f stamp-h1; \
+	  $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \
+	else :; fi
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in:  $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+relion-${RELION_API_VERSION}.pc: $(top_builddir)/config.status $(srcdir)/relion.pc.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+	  test "$$dir" != "$$p" || dir=.; \
+	  echo "rm -f \"$${dir}/so_locations\""; \
+	  rm -f "$${dir}/so_locations"; \
+	done
+src/$(am__dirstamp):
+	@$(MKDIR_P) src
+	@: > src/$(am__dirstamp)
+src/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) src/$(DEPDIR)
+	@: > src/$(DEPDIR)/$(am__dirstamp)
+src/args.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/assembly.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/autopicker.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/backprojector.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/complex.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/ctf.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/ctffind_runner.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/error.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/euler.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/exp_model.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/fftw.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/filename.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/funcs.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/healpix_sampling.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/image.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/mask.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/matrix1d.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/matrix2d.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/memory.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/metadata_container.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/metadata_label.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/metadata_table.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/ml_model.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/ml_optimiser.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/multidim_array.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/numerical_recipes.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/parallel.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/particle_polisher.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/particle_sorter.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/postprocessing.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/preprocessing.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/projector.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/strings.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/symmetries.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/tabfuncs.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/time.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/transformations.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/Healpix_2.15a/$(am__dirstamp):
+	@$(MKDIR_P) src/Healpix_2.15a
+	@: > src/Healpix_2.15a/$(am__dirstamp)
+src/Healpix_2.15a/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) src/Healpix_2.15a/$(DEPDIR)
+	@: > src/Healpix_2.15a/$(DEPDIR)/$(am__dirstamp)
+src/Healpix_2.15a/cxxutils.lo: src/Healpix_2.15a/$(am__dirstamp) \
+	src/Healpix_2.15a/$(DEPDIR)/$(am__dirstamp)
+src/Healpix_2.15a/healpix_base.lo: src/Healpix_2.15a/$(am__dirstamp) \
+	src/Healpix_2.15a/$(DEPDIR)/$(am__dirstamp)
+src/mpi.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/autopicker_mpi.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/ctffind_runner_mpi.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/particle_polisher_mpi.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/particle_sorter_mpi.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/preprocessing_mpi.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/ml_optimiser_mpi.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/displayer.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/gui_entries.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/gui_jobwindow.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/gui_mainwindow.lo: src/$(am__dirstamp) \
+	src/$(DEPDIR)/$(am__dirstamp)
+src/manualpicker.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+librelion- at RELION_API_VERSION@.la: $(librelion_ at RELION_API_VERSION@_la_OBJECTS) $(librelion_ at RELION_API_VERSION@_la_DEPENDENCIES) 
+	$(librelion_ at RELION_API_VERSION@_la_LINK) -rpath $(libdir) $(librelion_ at RELION_API_VERSION@_la_OBJECTS) $(librelion_ at RELION_API_VERSION@_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	for p in $$list; do echo "$$p $$p"; done | \
+	sed 's/$(EXEEXT)$$//' | \
+	while read p p1; do if test -f $$p || test -f $$p1; \
+	  then echo "$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+	    -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+	sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) files[d] = files[d] " " $$1; \
+	    else { print "f", $$3 "/" $$4, $$1; } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	    if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	    test -z "$$files" || { \
+	    echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+	    $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+	    } \
+	; done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	  sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+	      -e 's/$$/$(EXEEXT)/' `; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+src/apps/$(am__dirstamp):
+	@$(MKDIR_P) src/apps
+	@: > src/apps/$(am__dirstamp)
+src/apps/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) src/apps/$(DEPDIR)
+	@: > src/apps/$(DEPDIR)/$(am__dirstamp)
+src/apps/autopick.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+autopick$(EXEEXT): $(autopick_OBJECTS) $(autopick_DEPENDENCIES) 
+	@rm -f autopick$(EXEEXT)
+	$(CXXLINK) $(autopick_OBJECTS) $(autopick_LDADD) $(LIBS)
+src/apps/autopick_mpi.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+autopick_mpi$(EXEEXT): $(autopick_mpi_OBJECTS) $(autopick_mpi_DEPENDENCIES) 
+	@rm -f autopick_mpi$(EXEEXT)
+	$(CXXLINK) $(autopick_mpi_OBJECTS) $(autopick_mpi_LDADD) $(LIBS)
+src/apps/display.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+display$(EXEEXT): $(display_OBJECTS) $(display_DEPENDENCIES) 
+	@rm -f display$(EXEEXT)
+	$(CXXLINK) $(display_OBJECTS) $(display_LDADD) $(LIBS)
+src/apps/find_tiltpairs.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+find_tiltpairs$(EXEEXT): $(find_tiltpairs_OBJECTS) $(find_tiltpairs_DEPENDENCIES) 
+	@rm -f find_tiltpairs$(EXEEXT)
+	$(CXXLINK) $(find_tiltpairs_OBJECTS) $(find_tiltpairs_LDADD) $(LIBS)
+src/apps/image_handler.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+image_handler$(EXEEXT): $(image_handler_OBJECTS) $(image_handler_DEPENDENCIES) 
+	@rm -f image_handler$(EXEEXT)
+	$(CXXLINK) $(image_handler_OBJECTS) $(image_handler_LDADD) $(LIBS)
+src/apps/maingui.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+maingui$(EXEEXT): $(maingui_OBJECTS) $(maingui_DEPENDENCIES) 
+	@rm -f maingui$(EXEEXT)
+	$(CXXLINK) $(maingui_OBJECTS) $(maingui_LDADD) $(LIBS)
+src/apps/manualpick.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+manualpick$(EXEEXT): $(manualpick_OBJECTS) $(manualpick_DEPENDENCIES) 
+	@rm -f manualpick$(EXEEXT)
+	$(CXXLINK) $(manualpick_OBJECTS) $(manualpick_LDADD) $(LIBS)
+src/apps/mask_create.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+mask_create$(EXEEXT): $(mask_create_OBJECTS) $(mask_create_DEPENDENCIES) 
+	@rm -f mask_create$(EXEEXT)
+	$(CXXLINK) $(mask_create_OBJECTS) $(mask_create_LDADD) $(LIBS)
+src/apps/particle_polish.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+particle_polish$(EXEEXT): $(particle_polish_OBJECTS) $(particle_polish_DEPENDENCIES) 
+	@rm -f particle_polish$(EXEEXT)
+	$(CXXLINK) $(particle_polish_OBJECTS) $(particle_polish_LDADD) $(LIBS)
+src/apps/particle_polish_mpi.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+particle_polish_mpi$(EXEEXT): $(particle_polish_mpi_OBJECTS) $(particle_polish_mpi_DEPENDENCIES) 
+	@rm -f particle_polish_mpi$(EXEEXT)
+	$(CXXLINK) $(particle_polish_mpi_OBJECTS) $(particle_polish_mpi_LDADD) $(LIBS)
+src/apps/particle_sort.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+particle_sort$(EXEEXT): $(particle_sort_OBJECTS) $(particle_sort_DEPENDENCIES) 
+	@rm -f particle_sort$(EXEEXT)
+	$(CXXLINK) $(particle_sort_OBJECTS) $(particle_sort_LDADD) $(LIBS)
+src/apps/particle_sort_mpi.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+particle_sort_mpi$(EXEEXT): $(particle_sort_mpi_OBJECTS) $(particle_sort_mpi_DEPENDENCIES) 
+	@rm -f particle_sort_mpi$(EXEEXT)
+	$(CXXLINK) $(particle_sort_mpi_OBJECTS) $(particle_sort_mpi_LDADD) $(LIBS)
+src/apps/postprocess.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+postprocess$(EXEEXT): $(postprocess_OBJECTS) $(postprocess_DEPENDENCIES) 
+	@rm -f postprocess$(EXEEXT)
+	$(CXXLINK) $(postprocess_OBJECTS) $(postprocess_LDADD) $(LIBS)
+src/apps/preprocess.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+preprocess$(EXEEXT): $(preprocess_OBJECTS) $(preprocess_DEPENDENCIES) 
+	@rm -f preprocess$(EXEEXT)
+	$(CXXLINK) $(preprocess_OBJECTS) $(preprocess_LDADD) $(LIBS)
+src/apps/preprocess_mpi.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+preprocess_mpi$(EXEEXT): $(preprocess_mpi_OBJECTS) $(preprocess_mpi_DEPENDENCIES) 
+	@rm -f preprocess_mpi$(EXEEXT)
+	$(CXXLINK) $(preprocess_mpi_OBJECTS) $(preprocess_mpi_LDADD) $(LIBS)
+src/apps/project.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+project$(EXEEXT): $(project_OBJECTS) $(project_DEPENDENCIES) 
+	@rm -f project$(EXEEXT)
+	$(CXXLINK) $(project_OBJECTS) $(project_LDADD) $(LIBS)
+src/apps/reconstruct.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+reconstruct$(EXEEXT): $(reconstruct_OBJECTS) $(reconstruct_DEPENDENCIES) 
+	@rm -f reconstruct$(EXEEXT)
+	$(CXXLINK) $(reconstruct_OBJECTS) $(reconstruct_LDADD) $(LIBS)
+src/apps/refine.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+refine$(EXEEXT): $(refine_OBJECTS) $(refine_DEPENDENCIES) 
+	@rm -f refine$(EXEEXT)
+	$(CXXLINK) $(refine_OBJECTS) $(refine_LDADD) $(LIBS)
+src/apps/refine_mpi.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+refine_mpi$(EXEEXT): $(refine_mpi_OBJECTS) $(refine_mpi_DEPENDENCIES) 
+	@rm -f refine_mpi$(EXEEXT)
+	$(CXXLINK) $(refine_mpi_OBJECTS) $(refine_mpi_LDADD) $(LIBS)
+src/apps/run_ctffind.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+run_ctffind$(EXEEXT): $(run_ctffind_OBJECTS) $(run_ctffind_DEPENDENCIES) 
+	@rm -f run_ctffind$(EXEEXT)
+	$(CXXLINK) $(run_ctffind_OBJECTS) $(run_ctffind_LDADD) $(LIBS)
+src/apps/run_ctffind_mpi.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+run_ctffind_mpi$(EXEEXT): $(run_ctffind_mpi_OBJECTS) $(run_ctffind_mpi_DEPENDENCIES) 
+	@rm -f run_ctffind_mpi$(EXEEXT)
+	$(CXXLINK) $(run_ctffind_mpi_OBJECTS) $(run_ctffind_mpi_LDADD) $(LIBS)
+src/apps/stack_create.$(OBJEXT): src/apps/$(am__dirstamp) \
+	src/apps/$(DEPDIR)/$(am__dirstamp)
+stack_create$(EXEEXT): $(stack_create_OBJECTS) $(stack_create_DEPENDENCIES) 
+	@rm -f stack_create$(EXEEXT)
+	$(CXXLINK) $(stack_create_OBJECTS) $(stack_create_LDADD) $(LIBS)
+install-dist_binSCRIPTS: $(dist_bin_SCRIPTS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+	@list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
+	done | \
+	sed -e 'p;s,.*/,,;n' \
+	    -e 'h;s|.*|.|' \
+	    -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+	$(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+	  { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+	    if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+	      if (++n[d] == $(am__install_max)) { \
+		print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+	    else { print "f", d "/" $$4, $$1 } } \
+	  END { for (d in files) print "f", d, files[d] }' | \
+	while read type dir files; do \
+	     if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+	     test -z "$$files" || { \
+	       echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+	       $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+	     } \
+	; done
+
+uninstall-dist_binSCRIPTS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \
+	files=`for p in $$list; do echo "$$p"; done | \
+	       sed -e 's,.*/,,;$(transform)'`; \
+	test -n "$$list" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+	-rm -f src/Healpix_2.15a/cxxutils.$(OBJEXT)
+	-rm -f src/Healpix_2.15a/cxxutils.lo
+	-rm -f src/Healpix_2.15a/healpix_base.$(OBJEXT)
+	-rm -f src/Healpix_2.15a/healpix_base.lo
+	-rm -f src/apps/autopick.$(OBJEXT)
+	-rm -f src/apps/autopick_mpi.$(OBJEXT)
+	-rm -f src/apps/display.$(OBJEXT)
+	-rm -f src/apps/find_tiltpairs.$(OBJEXT)
+	-rm -f src/apps/image_handler.$(OBJEXT)
+	-rm -f src/apps/maingui.$(OBJEXT)
+	-rm -f src/apps/manualpick.$(OBJEXT)
+	-rm -f src/apps/mask_create.$(OBJEXT)
+	-rm -f src/apps/particle_polish.$(OBJEXT)
+	-rm -f src/apps/particle_polish_mpi.$(OBJEXT)
+	-rm -f src/apps/particle_sort.$(OBJEXT)
+	-rm -f src/apps/particle_sort_mpi.$(OBJEXT)
+	-rm -f src/apps/postprocess.$(OBJEXT)
+	-rm -f src/apps/preprocess.$(OBJEXT)
+	-rm -f src/apps/preprocess_mpi.$(OBJEXT)
+	-rm -f src/apps/project.$(OBJEXT)
+	-rm -f src/apps/reconstruct.$(OBJEXT)
+	-rm -f src/apps/refine.$(OBJEXT)
+	-rm -f src/apps/refine_mpi.$(OBJEXT)
+	-rm -f src/apps/run_ctffind.$(OBJEXT)
+	-rm -f src/apps/run_ctffind_mpi.$(OBJEXT)
+	-rm -f src/apps/stack_create.$(OBJEXT)
+	-rm -f src/args.$(OBJEXT)
+	-rm -f src/args.lo
+	-rm -f src/assembly.$(OBJEXT)
+	-rm -f src/assembly.lo
+	-rm -f src/autopicker.$(OBJEXT)
+	-rm -f src/autopicker.lo
+	-rm -f src/autopicker_mpi.$(OBJEXT)
+	-rm -f src/autopicker_mpi.lo
+	-rm -f src/backprojector.$(OBJEXT)
+	-rm -f src/backprojector.lo
+	-rm -f src/complex.$(OBJEXT)
+	-rm -f src/complex.lo
+	-rm -f src/ctf.$(OBJEXT)
+	-rm -f src/ctf.lo
+	-rm -f src/ctffind_runner.$(OBJEXT)
+	-rm -f src/ctffind_runner.lo
+	-rm -f src/ctffind_runner_mpi.$(OBJEXT)
+	-rm -f src/ctffind_runner_mpi.lo
+	-rm -f src/displayer.$(OBJEXT)
+	-rm -f src/displayer.lo
+	-rm -f src/error.$(OBJEXT)
+	-rm -f src/error.lo
+	-rm -f src/euler.$(OBJEXT)
+	-rm -f src/euler.lo
+	-rm -f src/exp_model.$(OBJEXT)
+	-rm -f src/exp_model.lo
+	-rm -f src/fftw.$(OBJEXT)
+	-rm -f src/fftw.lo
+	-rm -f src/filename.$(OBJEXT)
+	-rm -f src/filename.lo
+	-rm -f src/funcs.$(OBJEXT)
+	-rm -f src/funcs.lo
+	-rm -f src/gui_entries.$(OBJEXT)
+	-rm -f src/gui_entries.lo
+	-rm -f src/gui_jobwindow.$(OBJEXT)
+	-rm -f src/gui_jobwindow.lo
+	-rm -f src/gui_mainwindow.$(OBJEXT)
+	-rm -f src/gui_mainwindow.lo
+	-rm -f src/healpix_sampling.$(OBJEXT)
+	-rm -f src/healpix_sampling.lo
+	-rm -f src/image.$(OBJEXT)
+	-rm -f src/image.lo
+	-rm -f src/manualpicker.$(OBJEXT)
+	-rm -f src/manualpicker.lo
+	-rm -f src/mask.$(OBJEXT)
+	-rm -f src/mask.lo
+	-rm -f src/matrix1d.$(OBJEXT)
+	-rm -f src/matrix1d.lo
+	-rm -f src/matrix2d.$(OBJEXT)
+	-rm -f src/matrix2d.lo
+	-rm -f src/memory.$(OBJEXT)
+	-rm -f src/memory.lo
+	-rm -f src/metadata_container.$(OBJEXT)
+	-rm -f src/metadata_container.lo
+	-rm -f src/metadata_label.$(OBJEXT)
+	-rm -f src/metadata_label.lo
+	-rm -f src/metadata_table.$(OBJEXT)
+	-rm -f src/metadata_table.lo
+	-rm -f src/ml_model.$(OBJEXT)
+	-rm -f src/ml_model.lo
+	-rm -f src/ml_optimiser.$(OBJEXT)
+	-rm -f src/ml_optimiser.lo
+	-rm -f src/ml_optimiser_mpi.$(OBJEXT)
+	-rm -f src/ml_optimiser_mpi.lo
+	-rm -f src/mpi.$(OBJEXT)
+	-rm -f src/mpi.lo
+	-rm -f src/multidim_array.$(OBJEXT)
+	-rm -f src/multidim_array.lo
+	-rm -f src/numerical_recipes.$(OBJEXT)
+	-rm -f src/numerical_recipes.lo
+	-rm -f src/parallel.$(OBJEXT)
+	-rm -f src/parallel.lo
+	-rm -f src/particle_polisher.$(OBJEXT)
+	-rm -f src/particle_polisher.lo
+	-rm -f src/particle_polisher_mpi.$(OBJEXT)
+	-rm -f src/particle_polisher_mpi.lo
+	-rm -f src/particle_sorter.$(OBJEXT)
+	-rm -f src/particle_sorter.lo
+	-rm -f src/particle_sorter_mpi.$(OBJEXT)
+	-rm -f src/particle_sorter_mpi.lo
+	-rm -f src/postprocessing.$(OBJEXT)
+	-rm -f src/postprocessing.lo
+	-rm -f src/preprocessing.$(OBJEXT)
+	-rm -f src/preprocessing.lo
+	-rm -f src/preprocessing_mpi.$(OBJEXT)
+	-rm -f src/preprocessing_mpi.lo
+	-rm -f src/projector.$(OBJEXT)
+	-rm -f src/projector.lo
+	-rm -f src/strings.$(OBJEXT)
+	-rm -f src/strings.lo
+	-rm -f src/symmetries.$(OBJEXT)
+	-rm -f src/symmetries.lo
+	-rm -f src/tabfuncs.$(OBJEXT)
+	-rm -f src/tabfuncs.lo
+	-rm -f src/time.$(OBJEXT)
+	-rm -f src/time.lo
+	-rm -f src/transformations.$(OBJEXT)
+	-rm -f src/transformations.lo
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/args.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/assembly.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/autopicker.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/autopicker_mpi.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/backprojector.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/complex.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/ctf.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/ctffind_runner.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/ctffind_runner_mpi.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/displayer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/error.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/euler.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/exp_model.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/fftw.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/filename.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/funcs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/gui_entries.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/gui_jobwindow.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/gui_mainwindow.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/healpix_sampling.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/image.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/manualpicker.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/mask.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/matrix1d.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/matrix2d.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/memory.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/metadata_container.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/metadata_label.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/metadata_table.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/ml_model.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/ml_optimiser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/ml_optimiser_mpi.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/mpi.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/multidim_array.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/numerical_recipes.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/parallel.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/particle_polisher.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/particle_polisher_mpi.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/particle_sorter.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/particle_sorter_mpi.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/postprocessing.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/preprocessing.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/preprocessing_mpi.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/projector.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/strings.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/symmetries.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/tabfuncs.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/time.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/$(DEPDIR)/transformations.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/Healpix_2.15a/$(DEPDIR)/cxxutils.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/Healpix_2.15a/$(DEPDIR)/healpix_base.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/autopick.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/autopick_mpi.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/display.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/find_tiltpairs.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/image_handler.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/maingui.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/manualpick.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/mask_create.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/particle_polish.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/particle_polish_mpi.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/particle_sort.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/particle_sort_mpi.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/postprocess.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/preprocess.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/preprocess_mpi.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/project.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/reconstruct.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/refine.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/refine_mpi.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/run_ctffind.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/run_ctffind_mpi.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at src/apps/$(DEPDIR)/stack_create.Po at am__quote@
+
+.cc.o:
+ at am__fastdepCXX_TRUE@	depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+ at am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+ at am__fastdepCXX_TRUE@	depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+ at am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+ at am__fastdepCXX_TRUE@	depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+ at am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(LTCXXCOMPILE) -c -o $@ $<
+
+.cpp.o:
+ at am__fastdepCXX_TRUE@	depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+ at am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+ at am__fastdepCXX_TRUE@	depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+ at am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+ at am__fastdepCXX_TRUE@	depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+ at am__fastdepCXX_TRUE@	$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCXX_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+	-rm -rf src/.libs src/_libs
+	-rm -rf src/Healpix_2.15a/.libs src/Healpix_2.15a/_libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+install-pkgconfigDATA: $(pkgconfig_DATA)
+	@$(NORMAL_INSTALL)
+	test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)"
+	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+	done
+
+uninstall-pkgconfigDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	test -n "$$files" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(pkgconfigdir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(pkgconfigdir)" && rm -f $$files
+install-nobase_relion_includeHEADERS: $(nobase_relion_include_HEADERS)
+	@$(NORMAL_INSTALL)
+	test -z "$(relion_includedir)" || $(MKDIR_P) "$(DESTDIR)$(relion_includedir)"
+	@list='$(nobase_relion_include_HEADERS)'; test -n "$(relion_includedir)" || list=; \
+	$(am__nobase_list) | while read dir files; do \
+	  xfiles=; for file in $$files; do \
+	    if test -f "$$file"; then xfiles="$$xfiles $$file"; \
+	    else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
+	  test -z "$$xfiles" || { \
+	    test "x$$dir" = x. || { \
+	      echo "$(MKDIR_P) '$(DESTDIR)$(relion_includedir)/$$dir'"; \
+	      $(MKDIR_P) "$(DESTDIR)$(relion_includedir)/$$dir"; }; \
+	    echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(relion_includedir)/$$dir'"; \
+	    $(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(relion_includedir)/$$dir" || exit $$?; }; \
+	done
+
+uninstall-nobase_relion_includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(nobase_relion_include_HEADERS)'; test -n "$(relion_includedir)" || list=; \
+	$(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
+	test -n "$$files" || exit 0; \
+	echo " ( cd '$(DESTDIR)$(relion_includedir)' && rm -f" $$files ")"; \
+	cd "$(DESTDIR)$(relion_includedir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	set x; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+	      END { if (nonempty) { for (i in files) print i; }; }'`; \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -755 \
+		-exec chmod u+rwx,go+rx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
+	$(am__remove_distdir)
+
+dist-lzma: distdir
+	tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
+	$(am__remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz
+	$(am__remove_distdir)
+
+dist-tarZ: distdir
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__remove_distdir)
+
+dist-shar: distdir
+	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	$(am__remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__remove_distdir)
+
+dist dist-all: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lzma*) \
+	  lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir); chmod u+w $(distdir)
+	mkdir $(distdir)/_build
+	mkdir $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build \
+	  && ../configure --srcdir=.. --prefix="$$dc_install_base" \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@$(am__cd) '$(distuninstallcheck_dir)' \
+	&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) $(DATA) \
+		$(HEADERS) config.h
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(relion_includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f src/$(DEPDIR)/$(am__dirstamp)
+	-rm -f src/$(am__dirstamp)
+	-rm -f src/Healpix_2.15a/$(DEPDIR)/$(am__dirstamp)
+	-rm -f src/Healpix_2.15a/$(am__dirstamp)
+	-rm -f src/apps/$(DEPDIR)/$(am__dirstamp)
+	-rm -f src/apps/$(am__dirstamp)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+	clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf src/$(DEPDIR) src/Healpix_2.15a/$(DEPDIR) src/apps/$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-nobase_relion_includeHEADERS \
+	install-pkgconfigDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-dist_binSCRIPTS \
+	install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -rf src/$(DEPDIR) src/Healpix_2.15a/$(DEPDIR) src/apps/$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-dist_binSCRIPTS \
+	uninstall-libLTLIBRARIES \
+	uninstall-nobase_relion_includeHEADERS uninstall-pkgconfigDATA
+
+.MAKE: all install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \
+	clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+	clean-libtool ctags dist dist-all dist-bzip2 dist-gzip \
+	dist-lzma dist-shar dist-tarZ dist-xz dist-zip distcheck \
+	distclean distclean-compile distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags distcleancheck distdir \
+	distuninstallcheck dvi dvi-am html html-am info info-am \
+	install install-am install-binPROGRAMS install-data \
+	install-data-am install-dist_binSCRIPTS install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am \
+	install-libLTLIBRARIES install-man \
+	install-nobase_relion_includeHEADERS install-pdf \
+	install-pdf-am install-pkgconfigDATA install-ps install-ps-am \
+	install-strip installcheck installcheck-am installdirs \
+	maintainer-clean maintainer-clean-generic mostlyclean \
+	mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+	pdf pdf-am ps ps-am tags uninstall uninstall-am \
+	uninstall-binPROGRAMS uninstall-dist_binSCRIPTS \
+	uninstall-libLTLIBRARIES \
+	uninstall-nobase_relion_includeHEADERS uninstall-pkgconfigDATA
+
+
+#bin_PROGRAMS += denovo_model
+#denovo_model_SOURCES = src/apps/denovo_model.cpp
+#denovo_model_LDADD = $(RelionLibs)
+
+#bin_PROGRAMS += tester
+#tester_SOURCES = src/apps/tester.cpp
+#tester_LDADD = $(RelionLibs)
+
+#bin_PROGRAMS += fsc2bfac 
+#fsc2bfac_SOURCES = src/apps/fsc2bfac.cpp
+#fsc2bfac_LDADD = $(RelionLibs)
+
+#bin_PROGRAMS += convert_bild2map
+#convert_bild2map_SOURCES = src/apps/convert_bild2map.cpp
+#convert_bild2map_LDADD = $(RelionLibs)
+
+#bin_PROGRAMS += composite_map
+#composite_map_SOURCES = src/apps/composite_map.cpp
+#composite_map_LDADD = $(RelionLibs)
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644
index 0000000..8ca212a
--- /dev/null
+++ b/README
@@ -0,0 +1,7 @@
+RELION (for REgularised LIkelihood OptimisatioN) is a stand-alone computer program for Maximum A Posteriori refinement of (multiple) 3D reconstructions or 2D class averages in cryo-electron microscopy. It is developed in the research group of Sjors Scheres at the MRC Laboratory of Molecular Biology. The underlying theory of MAP refinement is given in a scientific publication: Scheres, JMB (2011) (DOI: 10.1016/j.jmb.2011.11.010). If RELION is useful in your work, please cite this paper. 
+
+The documentation of RELION is stored on the following Wiki page:
+http://www2.mrc-lmb.cam.ac.uk/relion
+
+The INSTALL.sh script is provided for convenient installation. Please see the above-mentioned Wiki for more information.
+
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..77bfcdb
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,8935 @@
+# generated automatically by aclocal 1.11.1 -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2007, 2008, 2009  Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.63],,
+[m4_warning([this file was generated for autoconf 2.63.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically `autoreconf'.])])
+
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008 Free Software Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008 Free Software Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can 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.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that 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 GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 56 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+       [m4_default([$3],
+		   [m4_fatal([Libtool version $1 or higher is required],
+		             63)])],
+       [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+  *\ * | *\	*)
+    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+_LT_PROG_ECHO_BACKSLASH
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    _LT_PATH_MAGIC
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME.  Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+	[m4_ifval([$1], [$1], [$2])])
+    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+    m4_ifval([$4],
+	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+    lt_dict_add_subkey([lt_decl_dict], [$2],
+	[tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+  [0], [m4_fatal([$0: too few arguments: $#])],
+  [1], [m4_fatal([$0: too few arguments: $#: $1])],
+  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+     m4_if([$2], [],
+	   m4_quote(lt_decl_varnames),
+	m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'.  VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "X$][$1" | $Xsed -e "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly.  In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+#    <var>='`$ECHO "X$<var>" | $Xsed -e "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+#    # Some comment about what VAR is for.
+#    visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+					   [description])))[]dnl
+m4_pushdef([_libtool_name],
+    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+    [0], [_libtool_name=[$]$1],
+    [1], [_libtool_name=$lt_[]$1],
+    [2], [_libtool_name=$lt_[]$1],
+    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'.  Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+	dnl If the libtool generation code has been placed in $CONFIG_LT,
+	dnl instead of duplicating it all over again into config.status,
+	dnl then we will have config.status run $CONFIG_LT later, so it
+	dnl needs to know what name is stored there:
+        [AC_CONFIG_COMMANDS([libtool],
+            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+    dnl If the libtool generation code is destined for config.status,
+    dnl expand the accumulated commands and init code now:
+    [AC_CONFIG_COMMANDS([libtool],
+        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Fix-up fallback echo if it was mangled by the above quoting rules.
+case \$lt_ECHO in
+*'\\\[$]0 --fallback-echo"')dnl "
+  lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\[$]0 --fallback-echo"\[$]/\[$]0 --fallback-echo"/'\`
+  ;;
+esac
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+cat >"$CONFIG_LT" <<_LTEOF
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate a libtool stub with the current configuration.
+
+lt_cl_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AS_SHELL_SANITIZE
+_AS_PREPARE
+
+exec AS_MESSAGE_FD>&1
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+  echo
+  AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+  -h, --help      print this help, then exit
+  -V, --version   print version number, then exit
+  -q, --quiet     do not print progress messages
+  -d, --debug     don't remove temporary files
+
+Report bugs to <bug-libtool at gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2008 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+  case $[1] in
+    --version | --v* | -V )
+      echo "$lt_cl_version"; exit 0 ;;
+    --help | --h* | -h )
+      echo "$lt_cl_help"; exit 0 ;;
+    --debug | --d* | -d )
+      debug=: ;;
+    --quiet | --q* | --silent | --s* | -q )
+      lt_cl_silent=: ;;
+
+    -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+    *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+  esac
+  shift
+done
+
+if $lt_cl_silent; then
+  exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure.  Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+if test "$no_create" != yes; then
+  lt_cl_success=:
+  test "$silent" = yes &&
+    lt_config_lt_args="$lt_config_lt_args --quiet"
+  exec AS_MESSAGE_LOG_FD>/dev/null
+  $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+  exec AS_MESSAGE_LOG_FD>>config.log
+  $lt_cl_success || AS_EXIT(1)
+fi
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars.  Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+  m4_if(_LT_TAG, [C], [
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+  _LT_PROG_LTMAIN
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+    || (rm -f "$cfgfile"; exit 1)
+
+  _LT_PROG_XSI_SHELLFNS
+
+  sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+    || (rm -f "$cfgfile"; exit 1)
+
+  mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+  [C],			[_LT_LANG(C)],
+  [C++],		[_LT_LANG(CXX)],
+  [Java],		[_LT_LANG(GCJ)],
+  [Fortran 77],		[_LT_LANG(F77)],
+  [Fortran],		[_LT_LANG(FC)],
+  [Windows Resource],	[_LT_LANG(RC)],
+  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+    [_LT_LANG($1)],
+    [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+  [LT_SUPPORTED_TAG([$1])dnl
+  m4_append([_LT_TAGS], [$1 ])dnl
+  m4_define([_LT_LANG_]$1[_enabled], [])dnl
+  _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+  [LT_LANG(CXX)],
+  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+  [LT_LANG(F77)],
+  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+  [LT_LANG(FC)],
+  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+  [LT_LANG(GCJ)],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+    [LT_LANG(GCJ)],
+    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+      [LT_LANG(GCJ)],
+      [m4_ifdef([AC_PROG_GCJ],
+	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([A][M_PROG_GCJ],
+	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([LT_PROG_GCJ],
+	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+  [LT_LANG(RC)],
+  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+    AC_CHECK_TOOL([LIPO], [lipo], [:])
+    AC_CHECK_TOOL([OTOOL], [otool], [:])
+    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+    _LT_DECL([], [DSYMUTIL], [1],
+      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+    _LT_DECL([], [NMEDIT], [1],
+      [Tool to change global to local symbols on Mac OS X])
+    _LT_DECL([], [LIPO], [1],
+      [Tool to manipulate fat objects and archives on Mac OS X])
+    _LT_DECL([], [OTOOL], [1],
+      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+    _LT_DECL([], [OTOOL64], [1],
+      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi])
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+	[lt_cv_ld_exported_symbols_list=yes],
+	[lt_cv_ld_exported_symbols_list=no])
+	LDFLAGS="$save_LDFLAGS"
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[012]])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[[012]]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES
+# --------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_automatic, $1)=yes
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  _LT_TAGVAR(link_all_deplibs, $1)=yes
+  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=echo
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    m4_if([$1], [CXX],
+[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    fi
+],[])
+  else
+  _LT_TAGVAR(ld_shlibs, $1)=no
+  fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX
+# -----------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+AC_LINK_IFELSE(AC_LANG_PROGRAM,[
+lt_aix_libpath_sed='
+    /Import File Strings/,/^$/ {
+	/^0/ {
+	    s/^0  *\(.*\)$/\1/
+	    p
+	}
+    }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi],[])
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[ifdef([AC_DIVERSION_NOTICE],
+	     [AC_DIVERT_PUSH(AC_DIVERSION_NOTICE)],
+	 [AC_DIVERT_PUSH(NOTICE)])
+$1
+AC_DIVERT_POP
+])# _LT_SHELL_INIT
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Add some code to the start of the generated configure script which
+# will find an echo command which doesn't interpret backslashes.
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[_LT_SHELL_INIT([
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$lt_ECHO in
+X*--fallback-echo)
+  # Remove one level of quotation (which was required for Make).
+  ECHO=`echo "$lt_ECHO" | sed 's,\\\\\[$]\\[$]0,'[$]0','`
+  ;;
+esac
+
+ECHO=${lt_ECHO-echo}
+if test "X[$]1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X[$]1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
+  # Yippee, $ECHO works!
+  :
+else
+  # Restart under the correct shell.
+  exec $SHELL "[$]0" --no-reexec ${1+"[$]@"}
+fi
+
+if test "X[$]1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<_LT_EOF
+[$]*
+_LT_EOF
+  exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$lt_ECHO"; then
+  if test "X${echo_test_string+set}" != Xset; then
+    # find a string as large as possible, as long as the shell can cope with it
+    for cmd in 'sed 50q "[$]0"' 'sed 20q "[$]0"' 'sed 10q "[$]0"' 'sed 2q "[$]0"' 'echo test'; do
+      # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+      if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
+	 { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
+      then
+        break
+      fi
+    done
+  fi
+
+  if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+     echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+     test "X$echo_testing_string" = "X$echo_test_string"; then
+    :
+  else
+    # The Solaris, AIX, and Digital Unix default echo programs unquote
+    # backslashes.  This makes it impossible to quote backslashes using
+    #   echo "$something" | sed 's/\\/\\\\/g'
+    #
+    # So, first we look for a working echo in the user's PATH.
+
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for dir in $PATH /usr/ucb; do
+      IFS="$lt_save_ifs"
+      if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+         test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+         echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+         test "X$echo_testing_string" = "X$echo_test_string"; then
+        ECHO="$dir/echo"
+        break
+      fi
+    done
+    IFS="$lt_save_ifs"
+
+    if test "X$ECHO" = Xecho; then
+      # We didn't find a better echo, so look for alternatives.
+      if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
+         echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
+         test "X$echo_testing_string" = "X$echo_test_string"; then
+        # This shell has a builtin print -r that does the trick.
+        ECHO='print -r'
+      elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
+	   test "X$CONFIG_SHELL" != X/bin/ksh; then
+        # If we have ksh, try running configure again with it.
+        ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+        export ORIGINAL_CONFIG_SHELL
+        CONFIG_SHELL=/bin/ksh
+        export CONFIG_SHELL
+        exec $CONFIG_SHELL "[$]0" --no-reexec ${1+"[$]@"}
+      else
+        # Try using printf.
+        ECHO='printf %s\n'
+        if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+	   echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+	   test "X$echo_testing_string" = "X$echo_test_string"; then
+	  # Cool, printf works
+	  :
+        elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+	     test "X$echo_testing_string" = 'X\t' &&
+	     echo_testing_string=`($ORIGINAL_CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+	     test "X$echo_testing_string" = "X$echo_test_string"; then
+	  CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+	  export CONFIG_SHELL
+	  SHELL="$CONFIG_SHELL"
+	  export SHELL
+	  ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
+        elif echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo '\t') 2>/dev/null` &&
+	     test "X$echo_testing_string" = 'X\t' &&
+	     echo_testing_string=`($CONFIG_SHELL "[$]0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+	     test "X$echo_testing_string" = "X$echo_test_string"; then
+	  ECHO="$CONFIG_SHELL [$]0 --fallback-echo"
+        else
+	  # maybe with a smaller string...
+	  prev=:
+
+	  for cmd in 'echo test' 'sed 2q "[$]0"' 'sed 10q "[$]0"' 'sed 20q "[$]0"' 'sed 50q "[$]0"'; do
+	    if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
+	    then
+	      break
+	    fi
+	    prev="$cmd"
+	  done
+
+	  if test "$prev" != 'sed 50q "[$]0"'; then
+	    echo_test_string=`eval $prev`
+	    export echo_test_string
+	    exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "[$]0" ${1+"[$]@"}
+	  else
+	    # Oops.  We lost completely, so just stick with echo.
+	    ECHO=echo
+	  fi
+        fi
+      fi
+    fi
+  fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+lt_ECHO=$ECHO
+if test "X$lt_ECHO" = "X$CONFIG_SHELL [$]0 --fallback-echo"; then
+   lt_ECHO="$CONFIG_SHELL \\\$\[$]0 --fallback-echo"
+fi
+
+AC_SUBST(lt_ECHO)
+])
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1],
+    [An echo program that does not interpret backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+  [AS_HELP_STRING([--disable-libtool-lock],
+    [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line __oline__ "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_i386"
+	    ;;
+	  ppc64-*linux*|powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  ppc*-*linux*|powerpc*-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+sparc*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*) LD="${LD-ld} -m elf64_sparc" ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[AC_CHECK_TOOL(AR, ar, false)
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1])
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+    [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+    [Commands used to build an old-style archive])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$5], , :, [$5])
+else
+    m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                  [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$4], , :, [$4])
+else
+    m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`$SHELL [$]0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
+	         = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+    [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+[#line __oline__ "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}]
+_LT_EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+    ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+	  [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+	[AC_CHECK_FUNC([dlopen],
+	      [lt_cv_dlopen="dlopen"],
+	  [AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+	    [AC_CHECK_LIB([svld], [dlopen],
+		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+	      [AC_CHECK_LIB([dld], [dld_link],
+		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+	      ])
+	    ])
+	  ])
+	])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+	  lt_cv_dlopen_self, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+	  lt_cv_dlopen_self_static, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+	 [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+	 [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+	 [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:__oline__: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:__oline__: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+	[Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+         [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+  [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+    [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+	[], [
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[123]]*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # Some binutils ld are patched to set DT_RUNPATH
+  save_LDFLAGS=$LDFLAGS
+  save_libdir=$libdir
+  eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+       LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+  AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+    [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+       [shlibpath_overrides_runpath=yes])])
+  LDFLAGS=$save_LDFLAGS
+  libdir=$save_libdir
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Add ABI-specific directories to the system library path.
+  sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+    [Variables whose values should be saved in libtool wrapper scripts and
+    restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+    [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+    [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+    [[List of archive names.  First name is the real one, the rest are links.
+    The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+    [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [postinstall_cmds], [2],
+    [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+    [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+    [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+    [[As "finish_cmds", except a single script fragment to be evaled but
+    not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+    [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+    [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+    [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="m4_if([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+_LT_DECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_DECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  if ( file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]].[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+    [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+    [Command to use when deplibs_check_method == "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  AC_CHECK_TOOLS(DUMPBIN, ["dumpbin -symbols" "link -dump -symbols"], :)
+  AC_SUBST([DUMPBIN])
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+  [lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:__oline__: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:__oline__: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:__oline__: output\"" >&AS_MESSAGE_LOG_FD)
+  cat conftest.out >&AS_MESSAGE_LOG_FD
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cygwin* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+
+  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+	[Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK ['"\
+"     {last_section=section; section=\$ 3};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx]"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+const struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_save_LIBS="$LIBS"
+	  lt_save_CFLAGS="$CFLAGS"
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS="$lt_save_LIBS"
+	  CFLAGS="$lt_save_CFLAGS"
+	else
+	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+    [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+    [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+    [lt_cv_sys_global_symbol_to_c_name_address], [1],
+    [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+    [Transform the output of nm in a C name address pair when lib prefix is needed])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+AC_MSG_CHECKING([for $compiler option to produce PIC])
+m4_if([$1], [CXX], [
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	else
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    if test "$host_cpu" != ia64; then
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64 which still supported -KPIC.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  xlc* | xlC*)
+	    # IBM XL 8.0 on PPC
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+	;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      xl*)
+	# IBM XL C 8.0/Fortran 10.1 on PPC
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)
+	  # Sun C 5.9
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  ;;
+	*Sun\ F*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t at m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+AC_MSG_RESULT([$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+	[How to pass a linker flag through the compiler])
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t at m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+	[Additional compiler flags for building library objects])
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+	[Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+  ;;
+  cygwin* | mingw* | cegcc*)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;/^.*[[ ]]__nm__/s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  *)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  esac
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+], [
+  runpath_var=
+  _LT_TAGVAR(allow_undefined_flag, $1)=
+  _LT_TAGVAR(always_export_symbols, $1)=no
+  _LT_TAGVAR(archive_cmds, $1)=
+  _LT_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_TAGVAR(compiler_needs_object, $1)=no
+  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(hardcode_automatic, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(inherit_rpath, $1)=no
+  _LT_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_TAGVAR(module_cmds, $1)=
+  _LT_TAGVAR(module_expsym_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  _LT_TAGVAR(ld_shlibs, $1)=yes
+  if test "$with_gnu_ld" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=no
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    interix[[3-9]]*)
+      _LT_TAGVAR(hardcode_direct, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95*)	# Portland Group f77 and f90 compilers
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+	  tmp_sharedflag='--shared' ;;
+	xl[[cC]]*)			# IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+	  _LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='-rpath $libdir'
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	_LT_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_TAGVAR(archive_cmds, $1)=''
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 _LT_SYS_MODULE_PATH_AIX
+	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	  # Exported symbols can be pulled into shared objects from archives
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[[45]]*)
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+      # FIXME: Should let the user specify the lib program.
+      _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+      _LT_TAGVAR(fix_srcfile_path, $1)='`cygpath -w "$srcfile"`'
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_DARWIN_LINKER_FEATURES($1)
+      ;;
+
+    dgux*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    freebsd1*)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)='+b $libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  ;;
+	*)
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+        save_LDFLAGS="$LDFLAGS"
+        LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+        AC_LINK_IFELSE(int foo(void) {},
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+        )
+        LDFLAGS="$save_LDFLAGS"
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(inherit_rpath, $1)=yes
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+	     _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	     ;;
+	   *)
+	     _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+        ;;
+	motorola)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+    [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_MSG_CHECKING([whether -lc should be explicitly linked in])
+      $RM conftest*
+      echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+	pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+        _LT_TAGVAR(allow_undefined_flag, $1)=
+        if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+        then
+	  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        else
+	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+        fi
+        _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $RM conftest*
+      AC_MSG_RESULT([$_LT_TAGVAR(archive_cmds_need_lc, $1)])
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+    [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+    [enable_shared_with_static_runtimes], [0],
+    [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+    [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+    [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+    [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+    [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+    [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+    [Commands used to build a loadable module if different from building
+    a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+    [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+    [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+    [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+    [Flag to hardcode $libdir into a binary during linking.
+    This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec_ld], [1],
+    [[If ld is used when linking, flag to hardcode $libdir into a binary
+    during linking.  This must work even if $libdir does not exist]])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+    [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary and the resulting library dependency is
+    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+    library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+    [Set to "yes" if building a shared library automatically hardcodes DIR
+    into the library and all subsequent libraries and executables linked
+    against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+    [Set to yes if linker adds runtime paths of dependent libraries
+    to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+    [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [fix_srcfile_path], [1],
+    [Fix the shell variable $srcfile for the compiler])
+_LT_TAGDECL([], [always_export_symbols], [0],
+    [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+    [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+    [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+    [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+    [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [file_list_spec], [1],
+    [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl    [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_SYS_DYNAMIC_LINKER($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+  LT_SYS_DLOPEN_SELF
+  _LT_CMD_STRIPLIB
+
+  # Report which library types will actually be built
+  AC_MSG_CHECKING([if libtool supports shared libraries])
+  AC_MSG_RESULT([$can_build_shared])
+
+  AC_MSG_CHECKING([whether to build shared libraries])
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[[4-9]]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  AC_MSG_RESULT([$enable_shared])
+
+  AC_MSG_CHECKING([whether to build static libraries])
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  AC_MSG_RESULT([$enable_static])
+
+  _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_PROG_CXX
+# ------------
+# Since AC_PROG_CXX is broken, in that it returns g++ if there is no c++
+# compiler, we have our own version here.
+m4_defun([_LT_PROG_CXX],
+[
+pushdef([AC_MSG_ERROR], [_lt_caught_CXX_error=yes])
+AC_PROG_CXX
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
+popdef([AC_MSG_ERROR])
+])# _LT_PROG_CXX
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([_LT_PROG_CXX], [])
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[AC_REQUIRE([_LT_PROG_CXX])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test "$GXX" = yes; then
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+    else
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+    fi
+
+    if test "$GXX" = yes; then
+      # Set up default GNU C++ configuration
+
+      LT_PATH_LD
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test "$with_gnu_ld" = yes; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='${wl}'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+        else
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+    _LT_TAGVAR(ld_shlibs, $1)=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+      aix[[4-9]]*)
+        if test "$host_cpu" = ia64; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=""
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # need to do runtime linking.
+          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        _LT_TAGVAR(archive_cmds, $1)=''
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+        if test "$GXX" = yes; then
+          case $host_os in aix4.[[012]]|aix4.[[012]].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag="$shared_flag "'${wl}-G'
+	  fi
+        else
+          # not using gcc
+          if test "$host_cpu" = ia64; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test "$aix_use_runtimelinking" = yes; then
+	      shared_flag='${wl}-G'
+	    else
+	      shared_flag='${wl}-bM:SRE'
+	    fi
+          fi
+        fi
+
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        _LT_TAGVAR(always_export_symbols, $1)=yes
+        if test "$aix_use_runtimelinking" = yes; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          _LT_SYS_MODULE_PATH_AIX
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+          if test "$host_cpu" = ia64; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    _LT_SYS_MODULE_PATH_AIX
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	    _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	    # Exported symbols can be pulled into shared objects from archives
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	    # This is similar to how AIX traditionally builds its shared
+	    # libraries.
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+        # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+        # as there is no search path for DLLs.
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+        _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+        _LT_TAGVAR(always_export_symbols, $1)=no
+        _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+        if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+          # If the export-symbols file already is a .def file (1st line
+          # is EXPORTS), use it as is; otherwise, prepend...
+          _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    cp $export_symbols $output_objdir/$soname.def;
+          else
+	    echo EXPORTS > $output_objdir/$soname.def;
+	    cat $export_symbols >> $output_objdir/$soname.def;
+          fi~
+          $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+        else
+          _LT_TAGVAR(ld_shlibs, $1)=no
+        fi
+        ;;
+      darwin* | rhapsody*)
+        _LT_DARWIN_LINKER_FEATURES($1)
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      freebsd[[12]]*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      freebsd-elf*)
+        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+        ;;
+
+      gnu*)
+        ;;
+
+      hpux9*)
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            _LT_TAGVAR(ld_shlibs, $1)=no
+            ;;
+          aCC*)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+            ;;
+          *)
+            if test "$GXX" = yes; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              _LT_TAGVAR(ld_shlibs, $1)=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            _LT_TAGVAR(hardcode_direct, $1)=no
+            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+            ;;
+          *)
+            _LT_TAGVAR(hardcode_direct, $1)=yes
+            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test $with_gnu_ld = no; then
+	        case $host_cpu in
+	          hppa*64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[[3-9]]*)
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test "$with_gnu_ld" = no; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	      else
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib'
+	      fi
+	    fi
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+	    ;;
+        esac
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(inherit_rpath, $1)=yes
+        ;;
+
+      linux* | k*bsd*-gnu)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [[1-5]]* | *pgcpp\ [[1-5]]*)
+	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+		compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
+	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
+		$RANLIB $oldlib'
+	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 will use weak symbols
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+	    ;;
+	  xl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    if test "x$supports_anon_versioning" = xyes; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+		echo "local: *; };" >> $output_objdir/$libname.ver~
+		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+	      _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='echo'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+	;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      openbsd*)
+	if test -f /usr/libexec/ld.so; then
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=echo
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+		;;
+	      *)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	          echo "-hidden">> $lib.exp~
+	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~
+	          $RM $lib.exp'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+		;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+	    ;;
+	  *)
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	      case $host in
+	        osf3*)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	        *)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	    case $host_os in
+	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands `-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+	    output_verbose_link_cmd='echo'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	        # platform.
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+	      fi
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+	      case $host_os in
+		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+		*)
+		  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We can NOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+	_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+	_LT_TAGVAR(link_all_deplibs, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	  *)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+    esac
+
+    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+    _LT_TAGVAR(GCC, $1)="$GXX"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+_LT_EOF
+])
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case $p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" ||
+          test $p = "-R"; then
+	 prev=$p
+	 continue
+       else
+	 prev=
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 case $p in
+	 -L* | -R*)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+	   else
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+	 else
+	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+	 fi
+       fi
+       ;;
+
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+	   _LT_TAGVAR(predep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+	 fi
+       else
+	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+	   _LT_TAGVAR(postdep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_TAGVAR(predep_objects,$1)=
+  _LT_TAGVAR(postdep_objects,$1)=
+  _LT_TAGVAR(postdeps,$1)=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+    [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+    [Dependencies to place before and after the objects being linked to
+    create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+    [The library search path used internally by the compiler when linking
+    a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_PROG_F77
+# ------------
+# Since AC_PROG_F77 is broken, in that it returns the empty string
+# if there is no fortran compiler, we have our own version here.
+m4_defun([_LT_PROG_F77],
+[
+pushdef([AC_MSG_ERROR], [_lt_disable_F77=yes])
+AC_PROG_F77
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
+popdef([AC_MSG_ERROR])
+])# _LT_PROG_F77
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([_LT_PROG_F77], [])
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_REQUIRE([_LT_PROG_F77])dnl
+AC_LANG_PUSH(Fortran 77)
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  CC=${F77-"f77"}
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+  GCC=$G77
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$G77"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_PROG_FC
+# -----------
+# Since AC_PROG_FC is broken, in that it returns the empty string
+# if there is no fortran compiler, we have our own version here.
+m4_defun([_LT_PROG_FC],
+[
+pushdef([AC_MSG_ERROR], [_lt_disable_FC=yes])
+AC_PROG_FC
+if test -z "$FC" || test "X$FC" = "Xno"; then
+  _lt_disable_FC=yes
+fi
+popdef([AC_MSG_ERROR])
+])# _LT_PROG_FC
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([_LT_PROG_FC], [])
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_REQUIRE([_LT_PROG_FC])dnl
+AC_LANG_PUSH(Fortran)
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_flag_spec_ld, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  CC=${FC-"f95"}
+  compiler=$CC
+  GCC=$ac_cv_fc_compiler_gnu
+
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC="$lt_save_CC"
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+  :
+  _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC="$lt_save_CC"
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+    [AC_CHECK_TOOL(GCJ, gcj,)
+      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+      AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_XSI_SHELLFNS
+# ---------------------
+# Bourne and XSI compatible variants of some useful shell functions.
+m4_defun([_LT_PROG_XSI_SHELLFNS],
+[case $xsi_shell in
+  yes)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+  case ${1} in
+    */*) func_dirname_result="${1%/*}${2}" ;;
+    *  ) func_dirname_result="${3}" ;;
+  esac
+}
+
+# func_basename file
+func_basename ()
+{
+  func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+  case ${1} in
+    */*) func_dirname_result="${1%/*}${2}" ;;
+    *  ) func_dirname_result="${3}" ;;
+  esac
+  func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+  # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+  # positional parameters, so assign one to ordinary parameter first.
+  func_stripname_result=${3}
+  func_stripname_result=${func_stripname_result#"${1}"}
+  func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+  func_opt_split_opt=${1%%=*}
+  func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+  case ${1} in
+    *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+    *)    func_lo2o_result=${1} ;;
+  esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+  func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+  func_arith_result=$(( $[*] ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+  func_len_result=${#1}
+}
+
+_LT_EOF
+    ;;
+  *) # Bourne compatible functions.
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+  # Extract subdirectory from the argument.
+  func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+  if test "X$func_dirname_result" = "X${1}"; then
+    func_dirname_result="${3}"
+  else
+    func_dirname_result="$func_dirname_result${2}"
+  fi
+}
+
+# func_basename file
+func_basename ()
+{
+  func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+}
+
+dnl func_dirname_and_basename
+dnl A portable version of this function is already defined in general.m4sh
+dnl so there is no need for it here.
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+  case ${2} in
+    .*) func_stripname_result=`$ECHO "X${3}" \
+           | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
+    *)  func_stripname_result=`$ECHO "X${3}" \
+           | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
+  esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[[^=]]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[[^=]]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+  func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
+  func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+  func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+  func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[[^.]]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+  func_arith_result=`expr "$[@]"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+  func_len_result=`expr "$[1]" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+  yes)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+  eval "$[1]+=\$[2]"
+}
+_LT_EOF
+    ;;
+  *)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+  eval "$[1]=\$$[1]\$[2]"
+}
+
+_LT_EOF
+    ;;
+  esac
+])
+
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+#   Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+        _LT_MANGLE_DEFUN([$1], [$2]),
+    [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+	    [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+		      [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME.  If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+    [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+  dnl
+  dnl Simply set some default values (i.e off) if boolean options were not
+  dnl specified:
+  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+  ])
+  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+  ])
+  dnl
+  dnl If no reference was made to various pairs of opposing options, then
+  dnl we run the default mode handler for the pair.  For example, if neither
+  dnl `shared' nor `disable-shared' was passed, we enable building of shared
+  dnl archives by default:
+  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+  		   [_LT_ENABLE_FAST_INSTALL])
+  ])
+])# _LT_SET_OPTIONS
+
+
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-cegcc*)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS],      [0], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [0], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [0], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+	[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+    _LT_DECL([build_libtool_libs], [enable_shared], [0],
+	[Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+	[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+    _LT_DECL([build_old_libs], [enable_static], [0],
+	[Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+	 [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+    [AS_HELP_STRING([--with-pic],
+	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [pic_mode="$withval"],
+    [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+		 [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+		 [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+		 [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+		 [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+		 [m4_define([_LTDL_TYPE], [convenience])])
+
+# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+       [$#], [2], [[$2]],
+       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+       [$#], 1, [],
+       [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+	   m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+	     [m4_foreach([_Lt_suffix],
+		]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+	[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+	  [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+		 [lt_append([$1], [$2], [$3])$4],
+		 [$5])],
+	  [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+	m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+	[$5],
+    [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+  [lt_join(m4_quote(m4_default([$4], [[, ]])),
+           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+		      [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
+
+# ltversion.m4 -- version numbers			-*- Autoconf -*-
+#
+#   Copyright (C) 2004 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# Generated from ltversion.in.
+
+# serial 3017 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.2.6b])
+m4_define([LT_PACKAGE_REVISION], [1.3017])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.2.6b'
+macro_revision='1.3017'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
+
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 4 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else.  This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION],	[AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP],		[AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT],		[AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],	[AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN],		[AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR],		[AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL],	[AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN],		[AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER],	[AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK],		[AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],	[AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],	[AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],	[AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR],		[AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR],		[AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],	[AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC],		[AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU],		[AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG],	[AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD],	[AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS],	[AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP],	[AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP],		[AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED],		[AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME],		[AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE],	[AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE],	[AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL],		[AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP],		[AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN],		[AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],	[AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG],		[AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL],	[AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX],		[AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77],		[AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ],		[AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_RC],		[AC_DEFUN([AC_LIBTOOL_RC])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG],	[AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG],	[AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG],	[AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],	[AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG],	[AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG],		[AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C],	[AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+
+# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.11'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.11.1], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.11.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to `$srcdir/foo'.  In other projects, it is set to
+# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is `.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 9
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ(2.52)dnl
+ ifelse([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+	[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 10
+
+# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "GCJ", or "OBJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+ifelse([$1], CC,   [depcc="$CC"   am_compiler_list=],
+       [$1], CXX,  [depcc="$CXX"  am_compiler_list=],
+       [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+       [$1], UPC,  [depcc="$UPC"  am_compiler_list=],
+       [$1], GCJ,  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                   [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvisualcpp | msvcmsys)
+      # This compiler won't grok `-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE(dependency-tracking,
+[  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+#serial 5
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Autoconf 2.62 quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named `Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running `make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # When using ansi2knr, U may be empty or an underscore; expand it
+    U=`sed -n 's/^U = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each `.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+# 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 16
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.62])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
+ AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
+AM_MISSING_PROG(AUTOCONF, autoconf)
+AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
+AM_MISSING_PROG(AUTOHEADER, autoheader)
+AM_MISSING_PROG(MAKEINFO, makeinfo)
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AM_PROG_MKDIR_P])dnl
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES(CC)],
+		  [define([AC_PROG_CC],
+			  defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES(CXX)],
+		  [define([AC_PROG_CXX],
+			  defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES(OBJC)],
+		  [define([AC_PROG_OBJC],
+			  defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
+])
+_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl
+dnl The `parallel-tests' driver may need to know about EXEEXT, so add the
+dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This macro
+dnl is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+])
+
+dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001, 2003, 2005, 2008  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST(install_sh)])
+
+# Copyright (C) 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2009  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_PROG_CC_C_O
+# --------------
+# Like AC_PROG_CC_C_O, but changed for automake.
+AC_DEFUN([AM_PROG_CC_C_O],
+[AC_REQUIRE([AC_PROG_CC_C_O])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
+eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
+if test "$am_t" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+dnl Make sure AC_PROG_CC is never called again, or it will override our
+dnl setting of CC.
+m4_define([AC_PROG_CC],
+          [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])])
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 6
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it supports --run.
+# If it does, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  AC_MSG_WARN([`missing' script is too old or missing])
+fi
+])
+
+# Copyright (C) 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_MKDIR_P
+# ---------------
+# Check for `mkdir -p'.
+AC_DEFUN([AM_PROG_MKDIR_P],
+[AC_PREREQ([2.60])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+dnl Automake 1.8 to 1.9.6 used to define mkdir_p.  We now use MKDIR_P,
+dnl while keeping a definition of mkdir_p for backward compatibility.
+dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
+dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
+dnl Makefile.ins that do not define MKDIR_P, so we do our own
+dnl adjustment using top_builddir (which is defined more often than
+dnl MKDIR_P).
+AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
+case $mkdir_p in
+  [[\\/$]]* | ?:[[\\/]]*) ;;
+  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001, 2002, 2003, 2005, 2008  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 4
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# ------------------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ----------------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+   if test "$[*]" = "X"; then
+      # -L didn't work.
+      set X `ls -t "$srcdir/configure" conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$[*]" != "X $srcdir/configure conftest.file" \
+      && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+alias in your environment])
+   fi
+
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT(yes)])
+
+# Copyright (C) 2001, 2003, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor `install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in `make install-strip', and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006, 2008  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004, 2005  Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 2
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of `v7', `ustar', or `pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.
+AM_MISSING_PROG([AMTAR], [tar])
+m4_if([$1], [v7],
+     [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
+     [m4_case([$1], [ustar],, [pax],,
+              [m4_fatal([Unknown tar format])])
+AC_MSG_CHECKING([how to create a $1 tar archive])
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+_am_tools=${am_cv_prog_tar_$1-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+  case $_am_tool in
+  gnutar)
+    for _am_tar in tar gnutar gtar;
+    do
+      AM_RUN_LOG([$_am_tar --version]) && break
+    done
+    am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+    am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+    am__untar="$_am_tar -xf -"
+    ;;
+  plaintar)
+    # Must skip GNU tar: if it does not support --format= it doesn't create
+    # ustar tarball either.
+    (tar --version) >/dev/null 2>&1 && continue
+    am__tar='tar chf - "$$tardir"'
+    am__tar_='tar chf - "$tardir"'
+    am__untar='tar xf -'
+    ;;
+  pax)
+    am__tar='pax -L -x $1 -w "$$tardir"'
+    am__tar_='pax -L -x $1 -w "$tardir"'
+    am__untar='pax -r'
+    ;;
+  cpio)
+    am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+    am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+    am__untar='cpio -i -H $1 -d'
+    ;;
+  none)
+    am__tar=false
+    am__tar_=false
+    am__untar=false
+    ;;
+  esac
+
+  # If the value was cached, stop now.  We just wanted to have am__tar
+  # and am__untar set.
+  test -n "${am_cv_prog_tar_$1}" && break
+
+  # tar/untar a dummy directory, and stop if the command works
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  echo GrepMe > conftest.dir/file
+  AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+  rm -rf conftest.dir
+  if test -s conftest.tar; then
+    AM_RUN_LOG([$am__untar <conftest.tar])
+    grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+  fi
+done
+rm -rf conftest.dir
+
+AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..d20be9a
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,8 @@
+#Some path variables
+setenv RELION_HOME $PWD
+setenv PREFIX $RELION_HOME
+autoreconf --install
+fltk_cxx=`fltk-config --cxxflags`
+fltk_ld=`fltk-config --ldflags`
+ ./configure --enable-mpi CPPFLAGS="-I/lmb/home/scheres/app/fftw-3.2.2/include -I$PREFIX/include $fltk_cxx" LDFLAGS="-L/lmb/home/scheres/app/fftw-3.2.2/lib -L$PREFIX/lib $fltk_ld" 
+
diff --git a/compile b/compile
new file mode 100755
index 0000000..c0096a7
--- /dev/null
+++ b/compile
@@ -0,0 +1,143 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2009-10-06.20; # UTC
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009  Free Software
+# Foundation, Inc.
+# Written by Tom Tromey <tromey at cygnus.com>.
+#
+# 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, 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, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake at gnu.org> or send patches to
+# <automake-patches at gnu.org>.
+
+case $1 in
+  '')
+     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+	# configure might choose to run compile as `compile cc -o foo foo.c'.
+	# So we strip `-o arg' only if arg is an object.
+	eat=1
+	case $2 in
+	  *.o | *.obj)
+	    ofile=$2
+	    ;;
+	  *)
+	    set x "$@" -o "$2"
+	    shift
+	    ;;
+	esac
+	;;
+      *.c)
+	cfile=$1
+	set x "$@" "$1"
+	shift
+	;;
+      *)
+	set x "$@" "$1"
+	shift
+	;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no `-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # `.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/config.guess b/config.guess
new file mode 100755
index 0000000..dc84c68
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1501 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+#   Free Software Foundation, Inc.
+
+timestamp='2009-11-20'
+
+# This file is free software; you can 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., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches at gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi at noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+	        os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	exit ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm:riscos:*:*|arm:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+        exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+        echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+        echo m68k-milan-mint${UNAME_RELEASE}
+        exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+        echo m68k-hades-mint${UNAME_RELEASE}
+        exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+        echo m68k-unknown-mint${UNAME_RELEASE}
+        exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+        # DG/UX returns AViiON for all architectures
+        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+ 	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[456])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+                    case "${sc_cpu_version}" in
+                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                      532)                      # CPU_PA_RISC2_0
+                        case "${sc_kernel_bits}" in
+                          32) HP_ARCH="hppa2.0n" ;;
+                          64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                        esac ;;
+                    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^              //' << EOF >$dummy.c
+
+              #define _HPUX_SOURCE
+              #include <stdlib.h>
+              #include <unistd.h>
+
+              int main ()
+              {
+              #if defined(_SC_KERNEL_BITS)
+                  long bits = sysconf(_SC_KERNEL_BITS);
+              #endif
+                  long cpu  = sysconf (_SC_CPU_VERSION);
+
+                  switch (cpu)
+              	{
+              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+              	case CPU_PA_RISC2_0:
+              #if defined(_SC_KERNEL_BITS)
+              	    switch (bits)
+              		{
+              		case 64: puts ("hppa2.0w"); break;
+              		case 32: puts ("hppa2.0n"); break;
+              		default: puts ("hppa2.0"); break;
+              		} break;
+              #else  /* !defined(_SC_KERNEL_BITS) */
+              	    puts ("hppa2.0"); break;
+              #endif
+              	default: puts ("hppa1.0"); break;
+              	}
+                  exit (0);
+              }
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+        exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+        exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+        exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+        exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+        exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+        exit ;;
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	LIBC=gnu
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+        # Unixware is an offshoot of SVR4, but it has its own version
+        # number series starting with 2...
+        # I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+        # Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+        # uname -m prints for DJGPP always 'pc', but it prints nothing about
+        # the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+        exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+          && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel at ccMail.Census.GOV>
+        echo i586-unisys-sysv4
+        exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes at openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf at swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+	        echo mips-nec-sysv${UNAME_RELEASE}
+	else
+	        echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+        exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	case $UNAME_PROCESSOR in
+	    i386)
+		eval $set_cc_for_build
+		if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		  if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		      (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		      grep IS_64BIT_ARCH >/dev/null
+		  then
+		      UNAME_PROCESSOR="x86_64"
+		  fi
+		fi ;;
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NSE-?:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+          "4"
+#else
+	  ""
+#endif
+         ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..efb8a41
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,65 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `fftw3' library (-lfftw3). */
+#undef HAVE_LIBFFTW3
+
+/* Define to 1 if you have the `fftw3_threads' library (-lfftw3_threads). */
+#undef HAVE_LIBFFTW3_THREADS
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Use MPI */
+#undef HAVE_MPI
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
diff --git a/config.sub b/config.sub
new file mode 100755
index 0000000..2a55a50
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1705 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+#   Free Software Foundation, Inc.
+
+timestamp='2009-11-20'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# This file is free software; you can 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., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray | -microblaze)
+		os=
+		basic_machine=$1
+		;;
+        -bluegene*)
+	        os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+ 	-chorusrdb)
+ 		os=-chorusrdb
+		basic_machine=$1
+ 		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+    	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+        cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+        microblaze)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw32)
+		basic_machine=i386-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+        # First match some system type aliases
+        # that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+        -auroraux)
+	        os=-auroraux
+		;;
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+        -os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+        -tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+        score-*)
+		os=-elf
+		;;
+        spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+        c4x-* | tic4x-*)
+        	os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+    	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/configure b/configure
new file mode 100755
index 0000000..754a495
--- /dev/null
+++ b/configure
@@ -0,0 +1,18370 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.63 for relion 1.3.
+#
+# Report bugs to <scheres at mrc-lmb.cam.ac.uk>.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes &&	 (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  case $as_dir in
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+	   done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+	 # Try only shells that exist, to save several forks.
+	 if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		{ ("$as_shell") 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+	       as_have_required=yes
+	       if { "$as_shell" 2> /dev/null <<\_ASEOF
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+	do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+	done
+	export CONFIG_SHELL
+	exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell bug-autoconf at gnu.org about your system,
+  echo including any error possibly output before this message.
+  echo This can help us improve future autoconf versions.
+  echo Configuration will now proceed without shell functions.
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+
+
+# Check that we are running under the correct shell.
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+case X$lt_ECHO in
+X*--fallback-echo)
+  # Remove one level of quotation (which was required for Make).
+  ECHO=`echo "$lt_ECHO" | sed 's,\\\\\$\\$0,'$0','`
+  ;;
+esac
+
+ECHO=${lt_ECHO-echo}
+if test "X$1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X$1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' ; then
+  # Yippee, $ECHO works!
+  :
+else
+  # Restart under the correct shell.
+  exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<_LT_EOF
+$*
+_LT_EOF
+  exit 0
+fi
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+if test -z "$lt_ECHO"; then
+  if test "X${echo_test_string+set}" != Xset; then
+    # find a string as large as possible, as long as the shell can cope with it
+    for cmd in 'sed 50q "$0"' 'sed 20q "$0"' 'sed 10q "$0"' 'sed 2q "$0"' 'echo test'; do
+      # expected sizes: less than 2Kb, 1Kb, 512 bytes, 16 bytes, ...
+      if { echo_test_string=`eval $cmd`; } 2>/dev/null &&
+	 { test "X$echo_test_string" = "X$echo_test_string"; } 2>/dev/null
+      then
+        break
+      fi
+    done
+  fi
+
+  if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+     echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+     test "X$echo_testing_string" = "X$echo_test_string"; then
+    :
+  else
+    # The Solaris, AIX, and Digital Unix default echo programs unquote
+    # backslashes.  This makes it impossible to quote backslashes using
+    #   echo "$something" | sed 's/\\/\\\\/g'
+    #
+    # So, first we look for a working echo in the user's PATH.
+
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for dir in $PATH /usr/ucb; do
+      IFS="$lt_save_ifs"
+      if (test -f $dir/echo || test -f $dir/echo$ac_exeext) &&
+         test "X`($dir/echo '\t') 2>/dev/null`" = 'X\t' &&
+         echo_testing_string=`($dir/echo "$echo_test_string") 2>/dev/null` &&
+         test "X$echo_testing_string" = "X$echo_test_string"; then
+        ECHO="$dir/echo"
+        break
+      fi
+    done
+    IFS="$lt_save_ifs"
+
+    if test "X$ECHO" = Xecho; then
+      # We didn't find a better echo, so look for alternatives.
+      if test "X`{ print -r '\t'; } 2>/dev/null`" = 'X\t' &&
+         echo_testing_string=`{ print -r "$echo_test_string"; } 2>/dev/null` &&
+         test "X$echo_testing_string" = "X$echo_test_string"; then
+        # This shell has a builtin print -r that does the trick.
+        ECHO='print -r'
+      elif { test -f /bin/ksh || test -f /bin/ksh$ac_exeext; } &&
+	   test "X$CONFIG_SHELL" != X/bin/ksh; then
+        # If we have ksh, try running configure again with it.
+        ORIGINAL_CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
+        export ORIGINAL_CONFIG_SHELL
+        CONFIG_SHELL=/bin/ksh
+        export CONFIG_SHELL
+        exec $CONFIG_SHELL "$0" --no-reexec ${1+"$@"}
+      else
+        # Try using printf.
+        ECHO='printf %s\n'
+        if test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t' &&
+	   echo_testing_string=`{ $ECHO "$echo_test_string"; } 2>/dev/null` &&
+	   test "X$echo_testing_string" = "X$echo_test_string"; then
+	  # Cool, printf works
+	  :
+        elif echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+	     test "X$echo_testing_string" = 'X\t' &&
+	     echo_testing_string=`($ORIGINAL_CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+	     test "X$echo_testing_string" = "X$echo_test_string"; then
+	  CONFIG_SHELL=$ORIGINAL_CONFIG_SHELL
+	  export CONFIG_SHELL
+	  SHELL="$CONFIG_SHELL"
+	  export SHELL
+	  ECHO="$CONFIG_SHELL $0 --fallback-echo"
+        elif echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo '\t') 2>/dev/null` &&
+	     test "X$echo_testing_string" = 'X\t' &&
+	     echo_testing_string=`($CONFIG_SHELL "$0" --fallback-echo "$echo_test_string") 2>/dev/null` &&
+	     test "X$echo_testing_string" = "X$echo_test_string"; then
+	  ECHO="$CONFIG_SHELL $0 --fallback-echo"
+        else
+	  # maybe with a smaller string...
+	  prev=:
+
+	  for cmd in 'echo test' 'sed 2q "$0"' 'sed 10q "$0"' 'sed 20q "$0"' 'sed 50q "$0"'; do
+	    if { test "X$echo_test_string" = "X`eval $cmd`"; } 2>/dev/null
+	    then
+	      break
+	    fi
+	    prev="$cmd"
+	  done
+
+	  if test "$prev" != 'sed 50q "$0"'; then
+	    echo_test_string=`eval $prev`
+	    export echo_test_string
+	    exec ${ORIGINAL_CONFIG_SHELL-${CONFIG_SHELL-/bin/sh}} "$0" ${1+"$@"}
+	  else
+	    # Oops.  We lost completely, so just stick with echo.
+	    ECHO=echo
+	  fi
+        fi
+      fi
+    fi
+  fi
+fi
+
+# Copy echo and quote the copy suitably for passing to libtool from
+# the Makefile, instead of quoting the original, which is used later.
+lt_ECHO=$ECHO
+if test "X$lt_ECHO" = "X$CONFIG_SHELL $0 --fallback-echo"; then
+   lt_ECHO="$CONFIG_SHELL \\\$\$0 --fallback-echo"
+fi
+
+
+
+
+exec 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME='relion'
+PACKAGE_TARNAME='relion'
+PACKAGE_VERSION='1.3'
+PACKAGE_STRING='relion 1.3'
+PACKAGE_BUGREPORT='scheres at mrc-lmb.cam.ac.uk'
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_default_prefix=`pwd`
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+HAVE_FLTK_FALSE
+HAVE_FLTK_TRUE
+HAVE_MPI_FALSE
+HAVE_MPI_TRUE
+MPICXX
+CXXCPP
+CPP
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+lt_ECHO
+RANLIB
+AR
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+EGREP
+GREP
+SED
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
+am__fastdepCXX_FALSE
+am__fastdepCXX_TRUE
+CXXDEPMODE
+ac_ct_CXX
+CXXFLAGS
+CXX
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+RELION_API_VERSION
+RELION_SO_VERSION
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_dependency_tracking
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+enable_libtool_lock
+enable_mpi
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CXX
+CXXFLAGS
+CCC
+CPP
+CXXCPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=*)	ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *)	ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2
+   { (exit 1); exit 1; }; }
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) { $as_echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  { $as_echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2
+   { (exit 1); exit 1; }; } ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+    $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  { $as_echo "$as_me: error: working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { $as_echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures relion 1.3 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/relion]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of relion 1.3:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --disable-dependency-tracking  speeds up one-time build
+  --enable-dependency-tracking   do not reject slow dependency extractors
+  --enable-shared[=PKGS]  build shared libraries [default=yes]
+  --enable-static[=PKGS]  build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+  --enable-mpi            compile with MPI support
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-pic              try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CXX         C++ compiler command
+  CXXFLAGS    C++ compiler flags
+  CPP         C preprocessor
+  CXXCPP      C++ preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <scheres at mrc-lmb.cam.ac.uk>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+relion configure 1.3
+generated by GNU Autoconf 2.63
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by relion $as_me 1.3, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  $as_echo "PATH: $as_dir"
+done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$ac_configure_args1 '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      ac_configure_args="$ac_configure_args '$ac_arg'"
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; }
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  ac_site_file1=$CONFIG_SITE
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test -r "$ac_site_file"; then
+    { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special
+  # files actually), so we avoid doing that.
+  if test -f "$cache_file"; then
+    { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:$LINENO:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:$LINENO:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+$as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+am__api_version='1.11'
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+$as_echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+  ./ | .// | /cC/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:$LINENO: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Just in case
+sleep 1
+echo timestamp > conftest.file
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[\\\"\#\$\&\'\`$am_lf]*)
+    { { $as_echo "$as_me:$LINENO: error: unsafe absolute working directory name" >&5
+$as_echo "$as_me: error: unsafe absolute working directory name" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+case $srcdir in
+  *[\\\"\#\$\&\'\`$am_lf\ \	]*)
+    { { $as_echo "$as_me:$LINENO: error: unsafe srcdir value: \`$srcdir'" >&5
+$as_echo "$as_me: error: unsafe srcdir value: \`$srcdir'" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+
+# Do `set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+   if test "$*" = "X"; then
+      # -L didn't work.
+      set X `ls -t "$srcdir/configure" conftest.file`
+   fi
+   rm -f conftest.file
+   if test "$*" != "X $srcdir/configure conftest.file" \
+      && test "$*" != "X conftest.file $srcdir/configure"; then
+
+      # If neither matched, then we have a broken ls.  This can happen
+      # if, for instance, CONFIG_SHELL is bash and it inherits a
+      # broken ls alias from the environment.  This has actually
+      # happened.  Such a system could not be considered "sane".
+      { { $as_echo "$as_me:$LINENO: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" >&5
+$as_echo "$as_me: error: ls -t appears to fail.  Make sure there is not a broken
+alias in your environment" >&2;}
+   { (exit 1); exit 1; }; }
+   fi
+
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   { { $as_echo "$as_me:$LINENO: error: newly created file is older than distributed files!
+Check your system clock" >&5
+$as_echo "$as_me: error: newly created file is older than distributed files!
+Check your system clock" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+{ $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --run true"; then
+  am_missing_run="$MISSING --run "
+else
+  am_missing_run=
+  { $as_echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+
+# Installed binaries are usually stripped using `strip' when the user
+# run `make install-strip'.  However `strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the `STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:$LINENO: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if test "${ac_cv_path_mkdir+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in mkdir gmkdir; do
+	 for ac_exec_ext in '' $ac_executable_extensions; do
+	   { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue
+	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+	     'mkdir (GNU coreutils) '* | \
+	     'mkdir (coreutils) '* | \
+	     'mkdir (fileutils) '4.1*)
+	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+	       break 3;;
+	   esac
+	 done
+       done
+done
+IFS=$as_save_IFS
+
+fi
+
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    test -d ./--version && rmdir ./--version
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+mkdir_p="$MKDIR_P"
+case $mkdir_p in
+  [\\/$]* | ?:[\\/]*) ;;
+  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
+esac
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AWK+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:$LINENO: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    { { $as_echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5
+$as_echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='relion'
+ VERSION='1.3'
+
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.
+
+AMTAR=${AMTAR-"${am_missing_run}tar"}
+
+am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'
+
+
+
+
+
+
+# Define these substitions here to keep all version information in one place.
+# For information on how to properly maintain the library version information,
+# refer to the libtool manual, section "Updating library version information":
+# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+RELION_SO_VERSION=1:3:0
+
+RELION_API_VERSION=1.3
+
+
+# Generate two configuration headers; one for building the library itself with
+# an autogenerated template, and a second one that will be installed alongside
+# the library.
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:$LINENO: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:$LINENO: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { (ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+        if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+
+{ $as_echo "$as_me:$LINENO: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+if test -z "$ac_file"; then
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+{ $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+{ $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if test "${ac_cv_objext+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:$LINENO: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:$LINENO: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+
+
+{ $as_echo "$as_me:$LINENO: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvisualcpp | msvcmsys)
+      # This compiler won't grok `-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+if test "x$CC" != xcc; then
+  { $as_echo "$as_me:$LINENO: checking whether $CC and cc understand -c and -o together" >&5
+$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; }
+else
+  { $as_echo "$as_me:$LINENO: checking whether cc understands -c and -o together" >&5
+$as_echo_n "checking whether cc understands -c and -o together... " >&6; }
+fi
+set dummy $CC; ac_cc=`$as_echo "$2" |
+		      sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+if { as_var=ac_cv_prog_cc_${ac_cc}_c_o; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+# Make sure it works both with $CC and with simple cc.
+# We do the test twice because some compilers refuse to overwrite an
+# existing .o file with -o, though they will create one.
+ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
+rm -f conftest2.*
+if { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+   test -f conftest2.$ac_objext && { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); };
+then
+  eval ac_cv_prog_cc_${ac_cc}_c_o=yes
+  if test "x$CC" != xcc; then
+    # Test first that cc exists at all.
+    if { ac_try='cc -c conftest.$ac_ext >&5'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+      ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
+      rm -f conftest2.*
+      if { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 test -f conftest2.$ac_objext && { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); };
+      then
+	# cc works too.
+	:
+      else
+	# cc exists but doesn't like -o.
+	eval ac_cv_prog_cc_${ac_cc}_c_o=no
+      fi
+    fi
+  fi
+else
+  eval ac_cv_prog_cc_${ac_cc}_c_o=no
+fi
+rm -f core conftest*
+
+fi
+if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then
+  { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define NO_MINUS_C_MINUS_O 1
+_ACEOF
+
+fi
+
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
+if test "$am_t" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:$LINENO: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:$LINENO: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if test "${ac_cv_prog_cxx_g+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cxx_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	CXXFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cxx_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CXX"  am_compiler_list=
+
+{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CXX_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvisualcpp | msvcmsys)
+      # This compiler won't grok `-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CXX_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+  am__fastdepCXX_TRUE=
+  am__fastdepCXX_FALSE='#'
+else
+  am__fastdepCXX_TRUE='#'
+  am__fastdepCXX_FALSE=
+fi
+
+
+case `pwd` in
+  *\ * | *\	*)
+    { $as_echo "$as_me:$LINENO: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.2.6b'
+macro_revision='1.3017'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5
+$as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;}
+   { (exit 1); exit 1; }; }
+
+{ $as_echo "$as_me:$LINENO: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if test "${ac_cv_build+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5
+$as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+   { (exit 1); exit 1; }; }
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5
+$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5
+$as_echo "$as_me: error: invalid value of canonical build" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:$LINENO: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if test "${ac_cv_host+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5
+$as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5
+$as_echo "$as_me: error: invalid value of canonical host" >&2;}
+   { (exit 1); exit 1; }; };;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if test "${ac_cv_path_SED+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     $as_unset ac_script || ac_script=
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    { { $as_echo "$as_me:$LINENO: error: no acceptable sed could be found in \$PATH" >&5
+$as_echo "$as_me: error: no acceptable sed could be found in \$PATH" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:$LINENO: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:$LINENO: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if test "${ac_cv_path_FGREP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+   then ac_cv_path_FGREP="$GREP -F"
+   else
+     if test -z "$FGREP"; then
+  ac_path_FGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_prog in fgrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+      { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+  # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'FGREP' >> "conftest.nl"
+    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    ac_count=`expr $ac_count + 1`
+    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_FGREP="$ac_path_FGREP"
+      ac_path_FGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_FGREP_found && break 3
+    done
+  done
+done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_FGREP"; then
+    { { $as_echo "$as_me:$LINENO: error: no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+$as_echo "$as_me: error: no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+else
+  ac_cv_path_FGREP=$FGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  { $as_echo "$as_me:$LINENO: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if test "${lt_cv_path_LD+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  { $as_echo "$as_me:$LINENO: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && { { $as_echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+$as_echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+   { (exit 1); exit 1; }; }
+{ $as_echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if test "${lt_cv_prog_gnu_ld+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if test "${lt_cv_path_NM+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in "dumpbin -symbols" "link -dump -symbols"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DUMPBIN+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:$LINENO: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in "dumpbin -symbols" "link -dump -symbols"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:$LINENO: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if test "${lt_cv_nm_interface+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:5023: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:5026: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:5029: output\"" >&5)
+  cat conftest.out >&5
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:$LINENO: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:$LINENO: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if test "${lt_cv_sys_max_cmd_len+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+    i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[	 ]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`$SHELL $0 --fallback-echo "X$teststring$teststring" 2>/dev/null` \
+	         = "XX$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+  { $as_echo "$as_me:$LINENO: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:$LINENO: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+{ $as_echo "$as_me:$LINENO: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:$LINENO: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+{ $as_echo "$as_me:$LINENO: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:$LINENO: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if test "${lt_cv_ld_reload_flag+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OBJDUMP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:$LINENO: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:$LINENO: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if test "${lt_cv_deplibs_check_method+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[45]*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  if ( file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - PA-RISC [0-9].[0-9]'
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9].[0-9]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[3-9]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_AR+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AR="${ac_tool_prefix}ar"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:$LINENO: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+  ac_ct_AR=$AR
+  # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_AR+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_AR="ar"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+else
+  AR="$ac_cv_prog_AR"
+fi
+
+test -z "$AR" && AR=ar
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_STRIP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:$LINENO: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:$LINENO: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[ABCDEGRST]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[BCDEGRST]'
+  ;;
+osf*)
+  symcode='[BCDEGQRST]'
+  ;;
+solaris*)
+  symcode='[BDRT]'
+  ;;
+sco3.2v5*)
+  symcode='[DT]'
+  ;;
+sysv4.2uw2*)
+  symcode='[DT]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[ABDT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK '"\
+"     {last_section=section; section=\$ 3};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[	 ]\($symcode$symcode*\)[	 ][	 ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { (eval echo "$as_me:$LINENO: \"$NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist\"") >&5
+  (eval $NM conftest.$ac_objext \| $lt_cv_sys_global_symbol_pipe \> $nlist) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+const struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_save_LIBS="$LIBS"
+	  lt_save_CFLAGS="$CFLAGS"
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+	  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS="$lt_save_LIBS"
+	  CFLAGS="$lt_save_CFLAGS"
+	else
+	  echo "cannot find nm_test_func in $nlist" >&5
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  { $as_echo "$as_me:$LINENO: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then
+  enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line 6235 "configure"' > conftest.$ac_ext
+  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_i386"
+	    ;;
+	  ppc64-*linux*|powerpc64-*linux*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  ppc*-*linux*|powerpc*-*linux*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  { $as_echo "$as_me:$LINENO: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if test "${lt_cv_cc_needs_belf+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+     cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  lt_cv_cc_needs_belf=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	lt_cv_cc_needs_belf=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+     ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+sparc*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*) LD="${LD-ld} -m elf64_sparc" ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+
+  case $host_os in
+    rhapsody* | darwin*)
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_DSYMUTIL+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DSYMUTIL"; then
+  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+  { $as_echo "$as_me:$LINENO: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+  ac_ct_DSYMUTIL=$DSYMUTIL
+  # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DSYMUTIL"; then
+  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DSYMUTIL" = x; then
+    DSYMUTIL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DSYMUTIL=$ac_ct_DSYMUTIL
+  fi
+else
+  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_NMEDIT+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NMEDIT"; then
+  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+  { $as_echo "$as_me:$LINENO: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+  ac_ct_NMEDIT=$NMEDIT
+  # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_NMEDIT"; then
+  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_NMEDIT="nmedit"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_NMEDIT" = x; then
+    NMEDIT=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    NMEDIT=$ac_ct_NMEDIT
+  fi
+else
+  NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_LIPO+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LIPO"; then
+  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+  { $as_echo "$as_me:$LINENO: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+  ac_ct_LIPO=$LIPO
+  # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_LIPO"; then
+  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_LIPO="lipo"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_LIPO" = x; then
+    LIPO=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIPO=$ac_ct_LIPO
+  fi
+else
+  LIPO="$ac_cv_prog_LIPO"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OTOOL+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL"; then
+  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:$LINENO: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+  ac_ct_OTOOL=$OTOOL
+  # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL"; then
+  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_OTOOL="otool"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL" = x; then
+    OTOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL=$ac_ct_OTOOL
+  fi
+else
+  OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OTOOL64+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL64"; then
+  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+  { $as_echo "$as_me:$LINENO: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+  ac_ct_OTOOL64=$OTOOL64
+  # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL64"; then
+  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL64" = x; then
+    OTOOL64=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL64=$ac_ct_OTOOL64
+  fi
+else
+  OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:$LINENO: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if test "${lt_cv_apple_cc_single_mod+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&5
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+    { $as_echo "$as_me:$LINENO: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if test "${lt_cv_ld_exported_symbols_list+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  lt_cv_ld_exported_symbols_list=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	lt_cv_ld_exported_symbols_list=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+	LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+    case $host_os in
+    rhapsody* | darwin1.[012])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[012]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:$LINENO: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+$as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_header_stdc=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then
+  :
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then
+  :
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -rf conftest.dSYM
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+		 $as_echo "$as_val"'`
+	       { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_Header'}
+		 $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+for ac_header in dlfcn.h
+do
+as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $ac_header" >&5
+$as_echo_n "checking for $ac_header... " >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval 'as_val=${'$as_ac_Header'}
+		 $as_echo "$as_val"'`
+	       { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_Header'}
+		 $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+  if test -n "$CCC"; then
+    CXX=$CCC
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_CXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CXX"; then
+  ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+  { $as_echo "$as_me:$LINENO: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CXX" && break
+  done
+fi
+if test -z "$CXX"; then
+  ac_ct_CXX=$CXX
+  for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CXX"; then
+  ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CXX="$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+  { $as_echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CXX" && break
+done
+
+  if test "x$ac_ct_CXX" = x; then
+    CXX="g++"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CXX=$ac_ct_CXX
+  fi
+fi
+
+  fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:$LINENO: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+{ $as_echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if test "${ac_cv_cxx_compiler_gnu+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_compiler_gnu=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GXX=yes
+else
+  GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if test "${ac_cv_prog_cxx_g+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+   ac_cxx_werror_flag=yes
+   ac_cv_prog_cxx_g=no
+   CXXFLAGS="-g"
+   cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cxx_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	CXXFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+	 CXXFLAGS="-g"
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cxx_g=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+  CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+  if test "$GXX" = yes; then
+    CXXFLAGS="-g -O2"
+  else
+    CXXFLAGS="-g"
+  fi
+else
+  if test "$GXX" = yes; then
+    CXXFLAGS="-O2"
+  else
+    CXXFLAGS=
+  fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CXX"  am_compiler_list=
+
+{ $as_echo "$as_me:$LINENO: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CXX_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvisualcpp | msvcmsys)
+      # This compiler won't grok `-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CXX_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+  am__fastdepCXX_TRUE=
+  am__fastdepCXX_FALSE='#'
+else
+  am__fastdepCXX_TRUE='#'
+  am__fastdepCXX_FALSE=
+fi
+
+
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+  if test "${ac_cv_prog_CXXCPP+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CXXCPP needs to be expanded
+    for CXXCPP in "$CXX -E" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  break
+fi
+
+    done
+    ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+  CXXCPP=$ac_cv_prog_CXXCPP
+else
+  ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:$LINENO: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+_lt_caught_CXX_error=yes; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+else
+  _lt_caught_CXX_error=yes
+fi
+
+
+
+
+
+# Set options
+
+
+
+        enable_dlopen=no
+
+
+  enable_win32_dll=no
+
+
+            # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then
+  enableval=$enable_shared; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+  # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then
+  withval=$with_pic; pic_mode="$withval"
+else
+  pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+  # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then
+  enableval=$enable_fast_install; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:$LINENO: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if test "${lt_cv_objdir+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    { $as_echo "$as_me:$LINENO: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/${ac_tool_prefix}file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    { $as_echo "$as_me:$LINENO: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if test "${lt_cv_path_MAGIC_CMD+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:$LINENO: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    MAGIC_CMD=:
+  fi
+fi
+
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+  lt_prog_compiler_no_builtin_flag=' -fno-builtin'
+
+  { $as_echo "$as_me:$LINENO: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:8826: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:8830: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+
+
+
+
+
+  lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+{ $as_echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl='-Wl,'
+    lt_prog_compiler_static='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      else
+	lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-KPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='--shared'
+	lt_prog_compiler_static='--static'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fpic'
+	lt_prog_compiler_static='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static='-non_shared'
+        ;;
+      xl*)
+	# IBM XL C 8.0/Fortran 10.1 on PPC
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-qpic'
+	lt_prog_compiler_static='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)
+	  # Sun C 5.9
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Wl,'
+	  ;;
+	*Sun\ F*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl=''
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95*)
+	lt_prog_compiler_wl='-Qoption ld ';;
+      *)
+	lt_prog_compiler_wl='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl='-Qoption ld '
+      lt_prog_compiler_pic='-PIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	lt_prog_compiler_pic='-Kconform_pic'
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_can_build_shared=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic='-pic'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic=
+    ;;
+  *)
+    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic" >&5
+$as_echo "$lt_prog_compiler_pic" >&6; }
+
+
+
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+  { $as_echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if test "${lt_cv_prog_compiler_pic_works+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:9165: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:9169: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+    case $lt_prog_compiler_pic in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+     esac
+else
+    lt_prog_compiler_pic=
+     lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if test "${lt_cv_prog_compiler_static_works+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+    :
+else
+    lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+  { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:9270: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:9274: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+  { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:9325: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:9329: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:$LINENO: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test "$hard_links" = no; then
+    { $as_echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+
+
+
+  { $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  runpath_var=
+  allow_undefined_flag=
+  always_export_symbols=no
+  archive_cmds=
+  archive_expsym_cmds=
+  compiler_needs_object=no
+  enable_shared_with_static_runtimes=no
+  export_dynamic_flag_spec=
+  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic=no
+  hardcode_direct=no
+  hardcode_direct_absolute=no
+  hardcode_libdir_flag_spec=
+  hardcode_libdir_flag_spec_ld=
+  hardcode_libdir_separator=
+  hardcode_minus_L=no
+  hardcode_shlibpath_var=unsupported
+  inherit_rpath=no
+  link_all_deplibs=unknown
+  module_cmds=
+  module_expsym_cmds=
+  old_archive_from_new_cmds=
+  old_archive_from_expsyms_cmds=
+  thread_safe_flag_spec=
+  whole_archive_flag_spec=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  esac
+
+  ld_shlibs=yes
+  if test "$with_gnu_ld" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    export_dynamic_flag_spec='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      whole_archive_flag_spec=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[3-9]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.9.1, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to modify your PATH
+*** so that a non-GNU linker is found, and then restart.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      allow_undefined_flag=unsupported
+      always_export_symbols=no
+      enable_shared_with_static_runtimes=yes
+      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+      export_dynamic_flag_spec='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95*)	# Portland Group f77 and f90 compilers
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  whole_archive_flag_spec=
+	  tmp_sharedflag='--shared' ;;
+	xl[cC]*)			# IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+	  hardcode_libdir_flag_spec=
+	  hardcode_libdir_flag_spec_ld='-rpath $libdir'
+	  archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        ld_shlibs=no
+      fi
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    ld_shlibs=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs" = no; then
+      runpath_var=
+      hardcode_libdir_flag_spec=
+      export_dynamic_flag_spec=
+      whole_archive_flag_spec=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag=unsupported
+      always_export_symbols=yes
+      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct=unsupported
+      fi
+      ;;
+
+    aix[4-9]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds=''
+      hardcode_direct=yes
+      hardcode_direct_absolute=yes
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      file_list_spec='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[012]|aix4.[012].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  hardcode_direct=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  hardcode_minus_L=yes
+	  hardcode_libdir_flag_spec='-L$libdir'
+	  hardcode_libdir_separator=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      export_dynamic_flag_spec='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+
+lt_aix_libpath_sed='
+    /Import File Strings/,/^$/ {
+	/^0/ {
+	    s/^0  *\(.*\)$/\1/
+	    p
+	}
+    }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag="-z nodefs"
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+
+lt_aix_libpath_sed='
+    /Import File Strings/,/^$/ {
+	/^0/ {
+	    s/^0  *\(.*\)$/\1/
+	    p
+	}
+    }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+	 hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag=' ${wl}-bernotok'
+	  allow_undefined_flag=' ${wl}-berok'
+	  # Exported symbols can be pulled into shared objects from archives
+	  whole_archive_flag_spec='$convenience'
+	  archive_cmds_need_lc=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      hardcode_libdir_flag_spec=' '
+      allow_undefined_flag=unsupported
+      # Tell ltmain to make .lib files, not .a files.
+      libext=lib
+      # Tell ltmain to make .dll files, not .so files.
+      shrext_cmds=".dll"
+      # FIXME: Setting linknames here is a bad hack.
+      archive_cmds='$CC -o $lib $libobjs $compiler_flags `$ECHO "X$deplibs" | $Xsed -e '\''s/ -lc$//'\''` -link -dll~linknames='
+      # The linker will automatically build a .lib file if we build a DLL.
+      old_archive_from_new_cmds='true'
+      # FIXME: Should let the user specify the lib program.
+      old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+      fix_srcfile_path='`cygpath -w "$srcfile"`'
+      enable_shared_with_static_runtimes=yes
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc=no
+  hardcode_direct=no
+  hardcode_automatic=yes
+  hardcode_shlibpath_var=unsupported
+  whole_archive_flag_spec=''
+  link_all_deplibs=yes
+  allow_undefined_flag="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=echo
+    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+  else
+  ld_shlibs=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    freebsd1*)
+      ld_shlibs=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      export_dynamic_flag_spec='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+	archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_flag_spec_ld='+b $libdir'
+	hardcode_libdir_separator=:
+	hardcode_direct=yes
+	hardcode_direct_absolute=yes
+	export_dynamic_flag_spec='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	hardcode_minus_L=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes -a "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  hardcode_direct=no
+	  hardcode_shlibpath_var=no
+	  ;;
+	*)
+	  hardcode_direct=yes
+	  hardcode_direct_absolute=yes
+	  export_dynamic_flag_spec='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+        save_LDFLAGS="$LDFLAGS"
+        LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+        cat >conftest.$ac_ext <<_ACEOF
+int foo(void) {}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+        LDFLAGS="$save_LDFLAGS"
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      inherit_rpath=yes
+      link_all_deplibs=yes
+      ;;
+
+    netbsd*)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    newsos6)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_shlibpath_var=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	hardcode_direct=yes
+	hardcode_shlibpath_var=no
+	hardcode_direct_absolute=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	  export_dynamic_flag_spec='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+	     archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     hardcode_libdir_flag_spec='-R$libdir'
+	     ;;
+	   *)
+	     archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~$ECHO DATA >> $output_objdir/$libname.def~$ECHO " SINGLE NONSHARED" >> $output_objdir/$libname.def~$ECHO EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_separator=:
+      ;;
+
+    solaris*)
+      no_undefined_flag=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_shlibpath_var=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      link_all_deplibs=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds='$CC -r -o $output$reload_objs'
+	  hardcode_direct=no
+        ;;
+	motorola)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag='${wl}-z,text'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      no_undefined_flag='${wl}-z,text'
+      allow_undefined_flag='${wl}-z,nodefs'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-R,$libdir'
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      export_dynamic_flag_spec='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      ld_shlibs=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	export_dynamic_flag_spec='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:$LINENO: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+      $RM conftest*
+      echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$lt_prog_compiler_wl
+	pic_flag=$lt_prog_compiler_pic
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$allow_undefined_flag
+        allow_undefined_flag=
+        if { (eval echo "$as_me:$LINENO: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\"") >&5
+  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+        then
+	  archive_cmds_need_lc=no
+        else
+	  archive_cmds_need_lc=yes
+        fi
+        allow_undefined_flag=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $RM conftest*
+      { $as_echo "$as_me:$LINENO: result: $archive_cmds_need_lc" >&5
+$as_echo "$archive_cmds_need_lc" >&6; }
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+  if $ECHO "$lt_search_path_spec" | $GREP ';' >/dev/null ; then
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED -e 's/;/ /g'`
+  else
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+  fi
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO $lt_tmp_lt_search_path_spec | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[lt_foo]++; }
+  if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+  sys_lib_search_path_spec=`$ECHO $lt_search_path_spec`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[123]*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+interix[3-9]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # Some binutils ld are patched to set DT_RUNPATH
+  save_LDFLAGS=$LDFLAGS
+  save_libdir=$libdir
+  eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+       LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then
+  shlibpath_overrides_runpath=yes
+fi
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$save_LDFLAGS
+  libdir=$save_libdir
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Add ABI-specific directories to the system library path.
+  sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+   test -n "$runpath_var" ||
+   test "X$hardcode_automatic" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+     test "$hardcode_minus_L" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:$LINENO: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+   test "$inherit_rpath" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+  if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    { $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_dl_dlopen=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_dl_dlopen=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+    ;;
+
+  *)
+    { $as_echo "$as_me:$LINENO: checking for shl_load" >&5
+$as_echo_n "checking for shl_load... " >&6; }
+if test "${ac_cv_func_shl_load+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define shl_load to an innocuous variant, in case <limits.h> declares shl_load.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define shl_load innocuous_shl_load
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char shl_load (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef shl_load
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_shl_load || defined __stub___shl_load
+choke me
+#endif
+
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_shl_load=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_func_shl_load=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_shl_load" >&5
+$as_echo "$ac_cv_func_shl_load" >&6; }
+if test "x$ac_cv_func_shl_load" = x""yes; then
+  lt_cv_dlopen="shl_load"
+else
+  { $as_echo "$as_me:$LINENO: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if test "${ac_cv_lib_dld_shl_load+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_dld_shl_load=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_dld_shl_load=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = x""yes; then
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+  { $as_echo "$as_me:$LINENO: checking for dlopen" >&5
+$as_echo_n "checking for dlopen... " >&6; }
+if test "${ac_cv_func_dlopen+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define dlopen to an innocuous variant, in case <limits.h> declares dlopen.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define dlopen innocuous_dlopen
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char dlopen (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef dlopen
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_dlopen || defined __stub___dlopen
+choke me
+#endif
+
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_func_dlopen=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_func_dlopen=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_func_dlopen" >&5
+$as_echo "$ac_cv_func_dlopen" >&6; }
+if test "x$ac_cv_func_dlopen" = x""yes; then
+  lt_cv_dlopen="dlopen"
+else
+  { $as_echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_dl_dlopen=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_dl_dlopen=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = x""yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  { $as_echo "$as_me:$LINENO: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if test "${ac_cv_lib_svld_dlopen+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_svld_dlopen=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_svld_dlopen=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = x""yes; then
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+  { $as_echo "$as_me:$LINENO: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if test "${ac_cv_lib_dld_dld_link+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_dld_dld_link=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_dld_dld_link=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = x""yes; then
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    { $as_echo "$as_me:$LINENO: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if test "${lt_cv_dlopen_self+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line 12128 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      { $as_echo "$as_me:$LINENO: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if test "${lt_cv_dlopen_self_static+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line 12224 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+void fnord() { int i=42;}
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:$LINENO: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+    else
+      { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+    fi
+    ;;
+  *)
+    { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+    ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+  # Report which library types will actually be built
+  { $as_echo "$as_me:$LINENO: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+  { $as_echo "$as_me:$LINENO: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+  { $as_echo "$as_me:$LINENO: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[4-9]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  { $as_echo "$as_me:$LINENO: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+  { $as_echo "$as_me:$LINENO: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  { $as_echo "$as_me:$LINENO: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+archive_cmds_need_lc_CXX=no
+allow_undefined_flag_CXX=
+always_export_symbols_CXX=no
+archive_expsym_cmds_CXX=
+compiler_needs_object_CXX=no
+export_dynamic_flag_spec_CXX=
+hardcode_direct_CXX=no
+hardcode_direct_absolute_CXX=no
+hardcode_libdir_flag_spec_CXX=
+hardcode_libdir_flag_spec_ld_CXX=
+hardcode_libdir_separator_CXX=
+hardcode_minus_L_CXX=no
+hardcode_shlibpath_var_CXX=unsupported
+hardcode_automatic_CXX=no
+inherit_rpath_CXX=no
+module_cmds_CXX=
+module_expsym_cmds_CXX=
+link_all_deplibs_CXX=unknown
+old_archive_cmds_CXX=$old_archive_cmds
+no_undefined_flag_CXX=
+whole_archive_flag_spec_CXX=
+enable_shared_with_static_runtimes_CXX=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+objext_CXX=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+  # save warnings/boilerplate of simple test code
+  ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+  ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  compiler=$CC
+  compiler_CXX=$CC
+  for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "X$cc_temp" | $Xsed -e 's%.*/%%' -e "s%^$host_alias-%%"`
+
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test "$GXX" = yes; then
+      lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+    else
+      lt_prog_compiler_no_builtin_flag_CXX=
+    fi
+
+    if test "$GXX" = yes; then
+      # Set up default GNU C++ configuration
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:$LINENO: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  { $as_echo "$as_me:$LINENO: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:$LINENO: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if test "${lt_cv_path_LD+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  { $as_echo "$as_me:$LINENO: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && { { $as_echo "$as_me:$LINENO: error: no acceptable ld found in \$PATH" >&5
+$as_echo "$as_me: error: no acceptable ld found in \$PATH" >&2;}
+   { (exit 1); exit 1; }; }
+{ $as_echo "$as_me:$LINENO: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if test "${lt_cv_prog_gnu_ld+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test "$with_gnu_ld" = yes; then
+        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        archive_expsym_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+        export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='${wl}'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+        else
+          whole_archive_flag_spec_CXX=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    { $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+    ld_shlibs_CXX=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+      aix[4-9]*)
+        if test "$host_cpu" = ia64; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=""
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # need to do runtime linking.
+          case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        archive_cmds_CXX=''
+        hardcode_direct_CXX=yes
+        hardcode_direct_absolute_CXX=yes
+        hardcode_libdir_separator_CXX=':'
+        link_all_deplibs_CXX=yes
+        file_list_spec_CXX='${wl}-f,'
+
+        if test "$GXX" = yes; then
+          case $host_os in aix4.[012]|aix4.[012].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    hardcode_direct_CXX=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    hardcode_minus_L_CXX=yes
+	    hardcode_libdir_flag_spec_CXX='-L$libdir'
+	    hardcode_libdir_separator_CXX=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag="$shared_flag "'${wl}-G'
+	  fi
+        else
+          # not using gcc
+          if test "$host_cpu" = ia64; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test "$aix_use_runtimelinking" = yes; then
+	      shared_flag='${wl}-G'
+	    else
+	      shared_flag='${wl}-bM:SRE'
+	    fi
+          fi
+        fi
+
+        export_dynamic_flag_spec_CXX='${wl}-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        always_export_symbols_CXX=yes
+        if test "$aix_use_runtimelinking" = yes; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          allow_undefined_flag_CXX='-berok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+
+lt_aix_libpath_sed='
+    /Import File Strings/,/^$/ {
+	/^0/ {
+	    s/^0  *\(.*\)$/\1/
+	    p
+	}
+    }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+          hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+          archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then $ECHO "X${wl}${allow_undefined_flag}" | $Xsed; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+          if test "$host_cpu" = ia64; then
+	    hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
+	    allow_undefined_flag_CXX="-z nodefs"
+	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+
+lt_aix_libpath_sed='
+    /Import File Strings/,/^$/ {
+	/^0/ {
+	    s/^0  *\(.*\)$/\1/
+	    p
+	}
+    }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+  aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+	    hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    no_undefined_flag_CXX=' ${wl}-bernotok'
+	    allow_undefined_flag_CXX=' ${wl}-berok'
+	    # Exported symbols can be pulled into shared objects from archives
+	    whole_archive_flag_spec_CXX='$convenience'
+	    archive_cmds_need_lc_CXX=yes
+	    # This is similar to how AIX traditionally builds its shared
+	    # libraries.
+	    archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  allow_undefined_flag_CXX=unsupported
+	  # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	else
+	  ld_shlibs_CXX=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  ld_shlibs_CXX=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+        # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
+        # as there is no search path for DLLs.
+        hardcode_libdir_flag_spec_CXX='-L$libdir'
+        allow_undefined_flag_CXX=unsupported
+        always_export_symbols_CXX=no
+        enable_shared_with_static_runtimes_CXX=yes
+
+        if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+          archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+          # If the export-symbols file already is a .def file (1st line
+          # is EXPORTS), use it as is; otherwise, prepend...
+          archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    cp $export_symbols $output_objdir/$soname.def;
+          else
+	    echo EXPORTS > $output_objdir/$soname.def;
+	    cat $export_symbols >> $output_objdir/$soname.def;
+          fi~
+          $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+        else
+          ld_shlibs_CXX=no
+        fi
+        ;;
+      darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc_CXX=no
+  hardcode_direct_CXX=no
+  hardcode_automatic_CXX=yes
+  hardcode_shlibpath_var_CXX=unsupported
+  whole_archive_flag_spec_CXX=''
+  link_all_deplibs_CXX=yes
+  allow_undefined_flag_CXX="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=echo
+    archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+       if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+      archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+      archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    fi
+
+  else
+  ld_shlibs_CXX=no
+  fi
+
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      freebsd[12]*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        ld_shlibs_CXX=no
+        ;;
+
+      freebsd-elf*)
+        archive_cmds_need_lc_CXX=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        ld_shlibs_CXX=yes
+        ;;
+
+      gnu*)
+        ;;
+
+      hpux9*)
+        hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+        hardcode_libdir_separator_CXX=:
+        export_dynamic_flag_spec_CXX='${wl}-E'
+        hardcode_direct_CXX=yes
+        hardcode_minus_L_CXX=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            ld_shlibs_CXX=no
+            ;;
+          aCC*)
+            archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+            ;;
+          *)
+            if test "$GXX" = yes; then
+              archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              ld_shlibs_CXX=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; then
+	  hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+	  hardcode_libdir_separator_CXX=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      export_dynamic_flag_spec_CXX='${wl}-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            hardcode_direct_CXX=no
+            hardcode_shlibpath_var_CXX=no
+            ;;
+          *)
+            hardcode_direct_CXX=yes
+            hardcode_direct_absolute_CXX=yes
+            hardcode_minus_L_CXX=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test $with_gnu_ld = no; then
+	        case $host_cpu in
+	          hppa*64*)
+	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      ld_shlibs_CXX=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[3-9]*)
+	hardcode_direct_CXX=no
+	hardcode_shlibpath_var_CXX=no
+	hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	export_dynamic_flag_spec_CXX='${wl}-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test "$with_gnu_ld" = no; then
+	        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	      else
+	        archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` -o $lib'
+	      fi
+	    fi
+	    link_all_deplibs_CXX=yes
+	    ;;
+        esac
+        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+        hardcode_libdir_separator_CXX=:
+        inherit_rpath_CXX=yes
+        ;;
+
+      linux* | k*bsd*-gnu)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+
+	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    archive_cmds_need_lc_CXX=no
+	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+	    whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [1-5]* | *pgcpp\ [1-5]*)
+	      prelink_cmds_CXX='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+		compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
+	      old_archive_cmds_CXX='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
+		$RANLIB $oldlib'
+	      archive_cmds_CXX='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      archive_expsym_cmds_CXX='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 will use weak symbols
+	      archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
+	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+	    whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+	    hardcode_libdir_separator_CXX=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+	    ;;
+	  xl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+	    export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+	    archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    if test "x$supports_anon_versioning" = xyes; then
+	      archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
+		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+		echo "local: *; };" >> $output_objdir/$libname.ver~
+		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      no_undefined_flag_CXX=' -zdefs'
+	      archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	      hardcode_libdir_flag_spec_CXX='-R$libdir'
+	      whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; $ECHO \"$new_convenience\"` ${wl}--no-whole-archive'
+	      compiler_needs_object_CXX=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='echo'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	ld_shlibs_CXX=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  archive_cmds_CXX='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  hardcode_libdir_flag_spec_CXX='-R$libdir'
+	  hardcode_direct_CXX=yes
+	  hardcode_shlibpath_var_CXX=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        ld_shlibs_CXX=yes
+	;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+	ld_shlibs_CXX=no
+	;;
+
+      openbsd*)
+	if test -f /usr/libexec/ld.so; then
+	  hardcode_direct_CXX=yes
+	  hardcode_shlibpath_var_CXX=no
+	  hardcode_direct_absolute_CXX=yes
+	  archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	    archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+	    export_dynamic_flag_spec_CXX='${wl}-E'
+	    whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=echo
+	else
+	  ld_shlibs_CXX=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+	    hardcode_libdir_separator_CXX=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+	        archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && $ECHO "X${wl}-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+	        hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+		;;
+	      *)
+	        allow_undefined_flag_CXX=' -expect_unresolved \*'
+	        archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib'
+	        archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	          echo "-hidden">> $lib.exp~
+	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "X-set_version $verstring" | $Xsed` -update_registry ${output_objdir}/so_locations -o $lib~
+	          $RM $lib.exp'
+	        hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+		;;
+	    esac
+
+	    hardcode_libdir_separator_CXX=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`$ECHO "X$templist" | $Xsed -e "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; $ECHO "X$list" | $Xsed'
+	    ;;
+	  *)
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+	      case $host in
+	        osf3*)
+	          archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "X${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	        *)
+	          archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && $ECHO "${wl}-set_version ${wl}$verstring" | $Xsed` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+	      hardcode_libdir_separator_CXX=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      ld_shlibs_CXX=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            archive_cmds_need_lc_CXX=yes
+	    no_undefined_flag_CXX=' -zdefs'
+	    archive_cmds_CXX='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    hardcode_libdir_flag_spec_CXX='-R$libdir'
+	    hardcode_shlibpath_var_CXX=no
+	    case $host_os in
+	      solaris2.[0-5] | solaris2.[0-5].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands `-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    link_all_deplibs_CXX=yes
+
+	    output_verbose_link_cmd='echo'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	        # platform.
+	        archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP "\-L"'
+	      fi
+
+	      hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
+	      case $host_os in
+		solaris2.[0-5] | solaris2.[0-5].*) ;;
+		*)
+		  whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag_CXX='${wl}-z,text'
+      archive_cmds_need_lc_CXX=no
+      hardcode_shlibpath_var_CXX=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We can NOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	no_undefined_flag_CXX='${wl}-z,text'
+	allow_undefined_flag_CXX='${wl}-z,nodefs'
+	archive_cmds_need_lc_CXX=no
+	hardcode_shlibpath_var_CXX=no
+	hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir'
+	hardcode_libdir_separator_CXX=':'
+	link_all_deplibs_CXX=yes
+	export_dynamic_flag_spec_CXX='${wl}-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	  *)
+	    archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    ld_shlibs_CXX=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        ld_shlibs_CXX=no
+        ;;
+    esac
+
+    { $as_echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+    test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+    GCC_CXX="$GXX"
+    LD_CXX="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    # Dependencies to place before and after the object being linked:
+predep_objects_CXX=
+postdep_objects_CXX=
+predeps_CXX=
+postdeps_CXX=
+compiler_lib_search_path_CXX=
+
+cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case $p in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" ||
+          test $p = "-R"; then
+	 prev=$p
+	 continue
+       else
+	 prev=
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 case $p in
+	 -L* | -R*)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$compiler_lib_search_path_CXX"; then
+	     compiler_lib_search_path_CXX="${prev}${p}"
+	   else
+	     compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$postdeps_CXX"; then
+	   postdeps_CXX="${prev}${p}"
+	 else
+	   postdeps_CXX="${postdeps_CXX} ${prev}${p}"
+	 fi
+       fi
+       ;;
+
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$predep_objects_CXX"; then
+	   predep_objects_CXX="$p"
+	 else
+	   predep_objects_CXX="$predep_objects_CXX $p"
+	 fi
+       else
+	 if test -z "$postdep_objects_CXX"; then
+	   postdep_objects_CXX="$p"
+	 else
+	   postdep_objects_CXX="$postdep_objects_CXX $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling CXX test program"
+fi
+
+$RM -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+case $host_os in
+interix[3-9]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  predep_objects_CXX=
+  postdep_objects_CXX=
+  postdeps_CXX=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    if test "$solaris_use_stlport4" != yes; then
+      postdeps_CXX='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      postdeps_CXX='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+
+
+case " $postdeps_CXX " in
+*" -lc "*) archive_cmds_need_lc_CXX=no ;;
+esac
+ compiler_lib_search_dirs_CXX=
+if test -n "${compiler_lib_search_path_CXX}"; then
+ compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    lt_prog_compiler_wl_CXX=
+lt_prog_compiler_pic_CXX=
+lt_prog_compiler_static_CXX=
+
+{ $as_echo "$as_me:$LINENO: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    lt_prog_compiler_wl_CXX='-Wl,'
+    lt_prog_compiler_static_CXX='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static_CXX='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic_CXX='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic_CXX='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      lt_prog_compiler_pic_CXX=
+      ;;
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic_CXX=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	lt_prog_compiler_pic_CXX='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic_CXX='-fPIC -shared'
+      ;;
+    *)
+      lt_prog_compiler_pic_CXX='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[4-9]*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  lt_prog_compiler_static_CXX='-Bstatic'
+	else
+	  lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+	    if test "$host_cpu" != ia64; then
+	      lt_prog_compiler_pic_CXX='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      lt_prog_compiler_pic_CXX='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    lt_prog_compiler_wl_CXX='--backend -Wl,'
+	    lt_prog_compiler_pic_CXX='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64 which still supported -KPIC.
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-fPIC'
+	    lt_prog_compiler_static_CXX='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-fpic'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    lt_prog_compiler_pic_CXX=
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    ;;
+	  xlc* | xlC*)
+	    # IBM XL 8.0 on PPC
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-qpic'
+	    lt_prog_compiler_static_CXX='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      lt_prog_compiler_pic_CXX='-KPIC'
+	      lt_prog_compiler_static_CXX='-Bstatic'
+	      lt_prog_compiler_wl_CXX='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    lt_prog_compiler_pic_CXX='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd*)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        lt_prog_compiler_pic_CXX='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    lt_prog_compiler_wl_CXX='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    lt_prog_compiler_pic_CXX=
+	    lt_prog_compiler_static_CXX='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    lt_prog_compiler_wl_CXX='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    lt_prog_compiler_pic_CXX='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    lt_prog_compiler_pic_CXX='-pic'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    lt_prog_compiler_pic_CXX='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    lt_prog_compiler_wl_CXX='-Wl,'
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    lt_prog_compiler_static_CXX='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    lt_prog_compiler_pic_CXX='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	lt_prog_compiler_can_build_shared_CXX=no
+	;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic_CXX=
+    ;;
+  *)
+    lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
+    ;;
+esac
+{ $as_echo "$as_me:$LINENO: result: $lt_prog_compiler_pic_CXX" >&5
+$as_echo "$lt_prog_compiler_pic_CXX" >&6; }
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_CXX"; then
+  { $as_echo "$as_me:$LINENO: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
+if test "${lt_cv_prog_compiler_pic_works_CXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works_CXX=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:14244: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:14248: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works_CXX=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then
+    case $lt_prog_compiler_pic_CXX in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
+     esac
+else
+    lt_prog_compiler_pic_CXX=
+     lt_prog_compiler_can_build_shared_CXX=no
+fi
+
+fi
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
+{ $as_echo "$as_me:$LINENO: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if test "${lt_cv_prog_compiler_static_works_CXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works_CXX=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "X$_lt_linker_boilerplate" | $Xsed -e '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works_CXX=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works_CXX=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_static_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then
+    :
+else
+    lt_prog_compiler_static_CXX=
+fi
+
+
+
+
+    { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_CXX=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:14343: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:14347: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o_CXX=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+    { $as_echo "$as_me:$LINENO: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if test "${lt_cv_prog_compiler_c_o_CXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o_CXX=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:14395: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:14399: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "X$_lt_compiler_boilerplate" | $Xsed -e '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o_CXX=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:$LINENO: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:$LINENO: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:$LINENO: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test "$hard_links" = no; then
+    { $as_echo "$as_me:$LINENO: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+    { $as_echo "$as_me:$LINENO: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  case $host_os in
+  aix[4-9]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    else
+      export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    export_symbols_cmds_CXX="$ltdll_cmds"
+  ;;
+  cygwin* | mingw* | cegcc*)
+    export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  *)
+    export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  ;;
+  esac
+  exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+
+{ $as_echo "$as_me:$LINENO: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+with_gnu_ld_CXX=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_CXX" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc_CXX=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds_CXX in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:$LINENO: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+      $RM conftest*
+      echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+      if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } 2>conftest.err; then
+        soname=conftest
+        lib=conftest
+        libobjs=conftest.$ac_objext
+        deplibs=
+        wl=$lt_prog_compiler_wl_CXX
+	pic_flag=$lt_prog_compiler_pic_CXX
+        compiler_flags=-v
+        linker_flags=-v
+        verstring=
+        output_objdir=.
+        libname=conftest
+        lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
+        allow_undefined_flag_CXX=
+        if { (eval echo "$as_me:$LINENO: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\"") >&5
+  (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+        then
+	  archive_cmds_need_lc_CXX=no
+        else
+	  archive_cmds_need_lc_CXX=yes
+        fi
+        allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
+      else
+        cat conftest.err 1>&5
+      fi
+      $RM conftest*
+      { $as_echo "$as_me:$LINENO: result: $archive_cmds_need_lc_CXX" >&5
+$as_echo "$archive_cmds_need_lc_CXX" >&6; }
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:$LINENO: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`$ECHO "X$lib" | $Xsed -e '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$host_os in
+  yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec="/usr/lib /lib/w32api /lib /usr/local/lib"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      sys_lib_search_path_spec=`$CC -print-search-dirs | $GREP "^libraries:" | $SED -e "s/^libraries://" -e "s,=/,/,g"`
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH printed by
+        # mingw gcc, but we are running on Cygwin. Gcc prints its search
+        # path with ; separators, and with drive letters. We can handle the
+        # drive letters (cygwin fileutils understands them), so leave them,
+        # especially as we might pass files found there to a mingw objdump,
+        # which wouldn't understand a cygwinified path. Ahh.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED  -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    ;;
+
+  *)
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    ;;
+  esac
+  dynamic_linker='Win32 ld.exe'
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd1*)
+  dynamic_linker=no
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[123]*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+gnu*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555.
+  postinstall_cmds='chmod 555 $lib'
+  ;;
+
+interix[3-9]*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  # Some binutils ld are patched to set DT_RUNPATH
+  save_LDFLAGS=$LDFLAGS
+  save_libdir=$libdir
+  eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \
+       LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\""
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_cxx_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then
+  shlibpath_overrides_runpath=yes
+fi
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+  LDFLAGS=$save_LDFLAGS
+  libdir=$save_libdir
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Add ABI-specific directories to the system library path.
+  sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib"
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:$LINENO: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:$LINENO: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" ||
+   test -n "$runpath_var_CXX" ||
+   test "X$hardcode_automatic_CXX" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct_CXX" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
+     test "$hardcode_minus_L_CXX" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action_CXX=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action_CXX=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action_CXX=unsupported
+fi
+{ $as_echo "$as_me:$LINENO: result: $hardcode_action_CXX" >&5
+$as_echo "$hardcode_action_CXX" >&6; }
+
+if test "$hardcode_action_CXX" = relink ||
+   test "$inherit_rpath_CXX" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+# Check for mpi headers
+# Check whether --enable-mpi was given.
+if test "${enable_mpi+set}" = set; then
+  enableval=$enable_mpi; if test x$enableval = "xyes"; then
+        for ac_prog in mpic++
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:$LINENO: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_MPICXX+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$MPICXX"; then
+  ac_cv_prog_MPICXX="$MPICXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_MPICXX="$ac_prog"
+    $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+MPICXX=$ac_cv_prog_MPICXX
+if test -n "$MPICXX"; then
+  { $as_echo "$as_me:$LINENO: result: $MPICXX" >&5
+$as_echo "$MPICXX" >&6; }
+else
+  { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$MPICXX" && break
+done
+
+        test -z "$MPICXX" &&  { { $as_echo "$as_me:$LINENO: error: couldn't find mpi library for --enable-mpi" >&5
+$as_echo "$as_me: error: couldn't find mpi library for --enable-mpi" >&2;}
+   { (exit 1); exit 1; }; }
+        enable_mpi=$enableval
+        CXX="$MPICXX"
+        CPPFLAGS="$CPPFLAGS -fpic"
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_MPI 1
+_ACEOF
+
+    fi
+else
+  enable_mpi=no
+fi
+
+ if test "$enable_mpi" = yes; then
+  HAVE_MPI_TRUE=
+  HAVE_MPI_FALSE='#'
+else
+  HAVE_MPI_TRUE='#'
+  HAVE_MPI_FALSE=
+fi
+
+
+# Check for FFTW3
+# Check for header <fftw3.h> AC_CHECK_HEADERS doesnt work, since we must
+# use mpicc to get includes - cpp isnt always the same compiler.
+{ $as_echo "$as_me:$LINENO: checking for fftw3.h" >&5
+$as_echo_n "checking for fftw3.h... " >&6; }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <fftw3.h>
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+# ok, look for library files too
+{ $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+{ $as_echo "$as_me:$LINENO: checking for main in -lfftw3" >&5
+$as_echo_n "checking for main in -lfftw3... " >&6; }
+if test "${ac_cv_lib_fftw3_main+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lfftw3  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+return main ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_fftw3_main=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_fftw3_main=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_fftw3_main" >&5
+$as_echo "$ac_cv_lib_fftw3_main" >&6; }
+if test "x$ac_cv_lib_fftw3_main" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBFFTW3 1
+_ACEOF
+
+  LIBS="-lfftw3 $LIBS"
+
+else
+  { { $as_echo "$as_me:$LINENO: error: Cannot find fftw3 library" >&5
+$as_echo "$as_me: error: Cannot find fftw3 library" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
+{ $as_echo "$as_me:$LINENO: checking for fftw_plan_with_nthreads in -lfftw3_threads" >&5
+$as_echo_n "checking for fftw_plan_with_nthreads in -lfftw3_threads... " >&6; }
+if test "${ac_cv_lib_fftw3_threads_fftw_plan_with_nthreads+set}" = set; then
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lfftw3_threads  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char fftw_plan_with_nthreads ();
+int
+main ()
+{
+return fftw_plan_with_nthreads ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+$as_echo "$ac_try_echo") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 $as_test_x conftest$ac_exeext
+       }; then
+  ac_cv_lib_fftw3_threads_fftw_plan_with_nthreads=yes
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_cv_lib_fftw3_threads_fftw_plan_with_nthreads=no
+fi
+
+rm -rf conftest.dSYM
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:$LINENO: result: $ac_cv_lib_fftw3_threads_fftw_plan_with_nthreads" >&5
+$as_echo "$ac_cv_lib_fftw3_threads_fftw_plan_with_nthreads" >&6; }
+if test "x$ac_cv_lib_fftw3_threads_fftw_plan_with_nthreads" = x""yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBFFTW3_THREADS 1
+_ACEOF
+
+  LIBS="-lfftw3_threads $LIBS"
+
+else
+  { { $as_echo "$as_me:$LINENO: error: Cannot find fftw3_threads library" >&5
+$as_echo "$as_me: error: Cannot find fftw3_threads library" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+ FFT_LIBS="-lfftw3_threads -lfftw3"
+
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+# not ok, echo a warning
+{ { $as_echo "$as_me:$LINENO: error: Cannot find the FFTW3 library. Please install it (with threads enabled) from http://www.fftw.org." >&5
+$as_echo "$as_me: error: Cannot find the FFTW3 library. Please install it (with threads enabled) from http://www.fftw.org." >&2;}
+   { (exit 1); exit 1; }; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+#Check for FLTK
+# as g++ seems needed and not gcc for compilation,
+#just check for presence of fltk-config program
+fltkfile=`pwd`/bin/fltk-config
+as_ac_File=`$as_echo "ac_cv_file_$fltkfile" | $as_tr_sh`
+{ $as_echo "$as_me:$LINENO: checking for $fltkfile" >&5
+$as_echo_n "checking for $fltkfile... " >&6; }
+if { as_var=$as_ac_File; eval "test \"\${$as_var+set}\" = set"; }; then
+  $as_echo_n "(cached) " >&6
+else
+  test "$cross_compiling" = yes &&
+  { { $as_echo "$as_me:$LINENO: error: cannot check for file existence when cross compiling" >&5
+$as_echo "$as_me: error: cannot check for file existence when cross compiling" >&2;}
+   { (exit 1); exit 1; }; }
+if test -r "$fltkfile"; then
+  eval "$as_ac_File=yes"
+else
+  eval "$as_ac_File=no"
+fi
+fi
+ac_res=`eval 'as_val=${'$as_ac_File'}
+		 $as_echo "$as_val"'`
+	       { $as_echo "$as_me:$LINENO: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+as_val=`eval 'as_val=${'$as_ac_File'}
+		 $as_echo "$as_val"'`
+   if test "x$as_val" = x""yes; then
+
+enable_fltk=yes
+
+else
+
+{ $as_echo "$as_me:$LINENO: result: warning: bin/fltk-config was not found" >&5
+$as_echo "warning: bin/fltk-config was not found" >&6; }
+enable_fltk=no
+
+fi
+
+ if test "$enable_fltk" = yes; then
+  HAVE_FLTK_TRUE=
+  HAVE_FLTK_FALSE='#'
+else
+  HAVE_FLTK_TRUE='#'
+  HAVE_FLTK_FALSE=
+fi
+
+
+# If no --prefix is passed to the configure script, relion programs and
+# libraries will be installed under the current directory by default.
+
+
+# The "relion_" string is prepended by default to installed programs.
+# It can be changed using --program-prefix=your_string
+if test "x$program_prefix" = xNONE; then
+  program_transform_name="s,^,relion_,"
+fi
+
+# Override the template file name of the generated .pc file, so that there
+# is no need to rename the template file when the API version changes.
+ac_config_headers="$ac_config_headers config.h"
+
+ac_config_files="$ac_config_files Makefile relion-${RELION_API_VERSION}.pc:relion.pc.in"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) $as_unset $ac_var ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes (double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \).
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    test "x$cache_file" != "x/dev/null" &&
+      { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+ if test -n "$EXEEXT"; then
+  am__EXEEXT_TRUE=
+  am__EXEEXT_FALSE='#'
+else
+  am__EXEEXT_TRUE='#'
+  am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_MPI_TRUE}" && test -z "${HAVE_MPI_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"HAVE_MPI\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"HAVE_MPI\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+if test -z "${HAVE_FLTK_TRUE}" && test -z "${HAVE_FLTK_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"HAVE_FLTK\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"HAVE_FLTK\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+: ${CONFIG_STATUS=./config.status}
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+## --------------------- ##
+## M4sh Initialization.  ##
+## --------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in
+  *posix*) set -o posix ;;
+esac
+
+fi
+
+
+
+
+# PATH needs CR
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+case $0 in
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# Required to use basename.
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  Blame Lee
+  # E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -p'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -p'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -p'
+  fi
+else
+  as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+	test -d "$1/.";
+      else
+	case $1 in
+	-*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+
+# Save the log message, to keep $[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by relion $as_me 1.3, which was
+generated by GNU Autoconf 2.63.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTION]... [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <bug-autoconf at gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_version="\\
+relion config.status 1.3
+configured by $0, generated by GNU Autoconf 2.63,
+  with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2008 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    CONFIG_FILES="$CONFIG_FILES '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    { $as_echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) { $as_echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$ac_config_targets $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "X$macro_version" | $Xsed -e "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "X$macro_revision" | $Xsed -e "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "X$enable_shared" | $Xsed -e "$delay_single_quote_subst"`'
+enable_static='`$ECHO "X$enable_static" | $Xsed -e "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "X$pic_mode" | $Xsed -e "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "X$enable_fast_install" | $Xsed -e "$delay_single_quote_subst"`'
+host_alias='`$ECHO "X$host_alias" | $Xsed -e "$delay_single_quote_subst"`'
+host='`$ECHO "X$host" | $Xsed -e "$delay_single_quote_subst"`'
+host_os='`$ECHO "X$host_os" | $Xsed -e "$delay_single_quote_subst"`'
+build_alias='`$ECHO "X$build_alias" | $Xsed -e "$delay_single_quote_subst"`'
+build='`$ECHO "X$build" | $Xsed -e "$delay_single_quote_subst"`'
+build_os='`$ECHO "X$build_os" | $Xsed -e "$delay_single_quote_subst"`'
+SED='`$ECHO "X$SED" | $Xsed -e "$delay_single_quote_subst"`'
+Xsed='`$ECHO "X$Xsed" | $Xsed -e "$delay_single_quote_subst"`'
+GREP='`$ECHO "X$GREP" | $Xsed -e "$delay_single_quote_subst"`'
+EGREP='`$ECHO "X$EGREP" | $Xsed -e "$delay_single_quote_subst"`'
+FGREP='`$ECHO "X$FGREP" | $Xsed -e "$delay_single_quote_subst"`'
+LD='`$ECHO "X$LD" | $Xsed -e "$delay_single_quote_subst"`'
+NM='`$ECHO "X$NM" | $Xsed -e "$delay_single_quote_subst"`'
+LN_S='`$ECHO "X$LN_S" | $Xsed -e "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "X$max_cmd_len" | $Xsed -e "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "X$ac_objext" | $Xsed -e "$delay_single_quote_subst"`'
+exeext='`$ECHO "X$exeext" | $Xsed -e "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "X$lt_unset" | $Xsed -e "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "X$lt_SP2NL" | $Xsed -e "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "X$lt_NL2SP" | $Xsed -e "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "X$reload_flag" | $Xsed -e "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "X$reload_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "X$OBJDUMP" | $Xsed -e "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "X$deplibs_check_method" | $Xsed -e "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "X$file_magic_cmd" | $Xsed -e "$delay_single_quote_subst"`'
+AR='`$ECHO "X$AR" | $Xsed -e "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "X$AR_FLAGS" | $Xsed -e "$delay_single_quote_subst"`'
+STRIP='`$ECHO "X$STRIP" | $Xsed -e "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "X$RANLIB" | $Xsed -e "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "X$old_postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "X$old_postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "X$old_archive_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+CC='`$ECHO "X$CC" | $Xsed -e "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "X$CFLAGS" | $Xsed -e "$delay_single_quote_subst"`'
+compiler='`$ECHO "X$compiler" | $Xsed -e "$delay_single_quote_subst"`'
+GCC='`$ECHO "X$GCC" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "X$lt_cv_sys_global_symbol_pipe" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "X$lt_cv_sys_global_symbol_to_cdecl" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "X$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`'
+objdir='`$ECHO "X$objdir" | $Xsed -e "$delay_single_quote_subst"`'
+SHELL='`$ECHO "X$SHELL" | $Xsed -e "$delay_single_quote_subst"`'
+ECHO='`$ECHO "X$ECHO" | $Xsed -e "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "X$MAGIC_CMD" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "X$lt_prog_compiler_no_builtin_flag" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "X$lt_prog_compiler_wl" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "X$lt_prog_compiler_pic" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "X$lt_prog_compiler_static" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "X$lt_cv_prog_compiler_c_o" | $Xsed -e "$delay_single_quote_subst"`'
+need_locks='`$ECHO "X$need_locks" | $Xsed -e "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "X$DSYMUTIL" | $Xsed -e "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "X$NMEDIT" | $Xsed -e "$delay_single_quote_subst"`'
+LIPO='`$ECHO "X$LIPO" | $Xsed -e "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "X$OTOOL" | $Xsed -e "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "X$OTOOL64" | $Xsed -e "$delay_single_quote_subst"`'
+libext='`$ECHO "X$libext" | $Xsed -e "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "X$shrext_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "X$extract_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "X$archive_cmds_need_lc" | $Xsed -e "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "X$enable_shared_with_static_runtimes" | $Xsed -e "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "X$export_dynamic_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "X$whole_archive_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "X$compiler_needs_object" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "X$old_archive_from_new_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "X$old_archive_from_expsyms_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "X$archive_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "X$archive_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "X$module_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "X$module_expsym_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "X$with_gnu_ld" | $Xsed -e "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "X$allow_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "X$no_undefined_flag" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "X$hardcode_libdir_flag_spec" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld='`$ECHO "X$hardcode_libdir_flag_spec_ld" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "X$hardcode_libdir_separator" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "X$hardcode_direct" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "X$hardcode_direct_absolute" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "X$hardcode_minus_L" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "X$hardcode_shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "X$hardcode_automatic" | $Xsed -e "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "X$inherit_rpath" | $Xsed -e "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "X$link_all_deplibs" | $Xsed -e "$delay_single_quote_subst"`'
+fix_srcfile_path='`$ECHO "X$fix_srcfile_path" | $Xsed -e "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "X$always_export_symbols" | $Xsed -e "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "X$export_symbols_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "X$exclude_expsyms" | $Xsed -e "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "X$include_expsyms" | $Xsed -e "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "X$prelink_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "X$file_list_spec" | $Xsed -e "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "X$variables_saved_for_relink" | $Xsed -e "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "X$need_lib_prefix" | $Xsed -e "$delay_single_quote_subst"`'
+need_version='`$ECHO "X$need_version" | $Xsed -e "$delay_single_quote_subst"`'
+version_type='`$ECHO "X$version_type" | $Xsed -e "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "X$runpath_var" | $Xsed -e "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "X$shlibpath_var" | $Xsed -e "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "X$shlibpath_overrides_runpath" | $Xsed -e "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "X$libname_spec" | $Xsed -e "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "X$library_names_spec" | $Xsed -e "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "X$soname_spec" | $Xsed -e "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "X$postinstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "X$postuninstall_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "X$finish_cmds" | $Xsed -e "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "X$finish_eval" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "X$hardcode_into_libs" | $Xsed -e "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "X$sys_lib_search_path_spec" | $Xsed -e "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "X$sys_lib_dlsearch_path_spec" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "X$hardcode_action" | $Xsed -e "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "X$enable_dlopen" | $Xsed -e "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "X$enable_dlopen_self" | $Xsed -e "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "X$enable_dlopen_self_static" | $Xsed -e "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "X$old_striplib" | $Xsed -e "$delay_single_quote_subst"`'
+striplib='`$ECHO "X$striplib" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_lib_search_dirs='`$ECHO "X$compiler_lib_search_dirs" | $Xsed -e "$delay_single_quote_subst"`'
+predep_objects='`$ECHO "X$predep_objects" | $Xsed -e "$delay_single_quote_subst"`'
+postdep_objects='`$ECHO "X$postdep_objects" | $Xsed -e "$delay_single_quote_subst"`'
+predeps='`$ECHO "X$predeps" | $Xsed -e "$delay_single_quote_subst"`'
+postdeps='`$ECHO "X$postdeps" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_lib_search_path='`$ECHO "X$compiler_lib_search_path" | $Xsed -e "$delay_single_quote_subst"`'
+LD_CXX='`$ECHO "X$LD_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_cmds_CXX='`$ECHO "X$old_archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_CXX='`$ECHO "X$compiler_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+GCC_CXX='`$ECHO "X$GCC_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "X$lt_prog_compiler_no_builtin_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_CXX='`$ECHO "X$lt_prog_compiler_wl_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_CXX='`$ECHO "X$lt_prog_compiler_pic_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+lt_prog_compiler_static_CXX='`$ECHO "X$lt_prog_compiler_static_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_CXX='`$ECHO "X$lt_cv_prog_compiler_c_o_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+archive_cmds_need_lc_CXX='`$ECHO "X$archive_cmds_need_lc_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_CXX='`$ECHO "X$enable_shared_with_static_runtimes_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_CXX='`$ECHO "X$export_dynamic_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+whole_archive_flag_spec_CXX='`$ECHO "X$whole_archive_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_needs_object_CXX='`$ECHO "X$compiler_needs_object_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_CXX='`$ECHO "X$old_archive_from_new_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_CXX='`$ECHO "X$old_archive_from_expsyms_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+archive_cmds_CXX='`$ECHO "X$archive_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+archive_expsym_cmds_CXX='`$ECHO "X$archive_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+module_cmds_CXX='`$ECHO "X$module_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+module_expsym_cmds_CXX='`$ECHO "X$module_expsym_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+with_gnu_ld_CXX='`$ECHO "X$with_gnu_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+allow_undefined_flag_CXX='`$ECHO "X$allow_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+no_undefined_flag_CXX='`$ECHO "X$no_undefined_flag_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_CXX='`$ECHO "X$hardcode_libdir_flag_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld_CXX='`$ECHO "X$hardcode_libdir_flag_spec_ld_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_libdir_separator_CXX='`$ECHO "X$hardcode_libdir_separator_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_direct_CXX='`$ECHO "X$hardcode_direct_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_direct_absolute_CXX='`$ECHO "X$hardcode_direct_absolute_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_minus_L_CXX='`$ECHO "X$hardcode_minus_L_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_CXX='`$ECHO "X$hardcode_shlibpath_var_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_automatic_CXX='`$ECHO "X$hardcode_automatic_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+inherit_rpath_CXX='`$ECHO "X$inherit_rpath_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+link_all_deplibs_CXX='`$ECHO "X$link_all_deplibs_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+fix_srcfile_path_CXX='`$ECHO "X$fix_srcfile_path_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+always_export_symbols_CXX='`$ECHO "X$always_export_symbols_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+export_symbols_cmds_CXX='`$ECHO "X$export_symbols_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+exclude_expsyms_CXX='`$ECHO "X$exclude_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+include_expsyms_CXX='`$ECHO "X$include_expsyms_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+prelink_cmds_CXX='`$ECHO "X$prelink_cmds_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+file_list_spec_CXX='`$ECHO "X$file_list_spec_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+hardcode_action_CXX='`$ECHO "X$hardcode_action_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_lib_search_dirs_CXX='`$ECHO "X$compiler_lib_search_dirs_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+predep_objects_CXX='`$ECHO "X$predep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+postdep_objects_CXX='`$ECHO "X$postdep_objects_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+predeps_CXX='`$ECHO "X$predeps_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+postdeps_CXX='`$ECHO "X$postdeps_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+compiler_lib_search_path_CXX='`$ECHO "X$compiler_lib_search_path_CXX" | $Xsed -e "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# Quote evaled strings.
+for var in SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+AR \
+AR_FLAGS \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+SHELL \
+ECHO \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_wl \
+lt_prog_compiler_pic \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_flag_spec_ld \
+hardcode_libdir_separator \
+fix_srcfile_path \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+finish_eval \
+old_striplib \
+striplib \
+compiler_lib_search_dirs \
+predep_objects \
+postdep_objects \
+predeps \
+postdeps \
+compiler_lib_search_path \
+LD_CXX \
+compiler_CXX \
+lt_prog_compiler_no_builtin_flag_CXX \
+lt_prog_compiler_wl_CXX \
+lt_prog_compiler_pic_CXX \
+lt_prog_compiler_static_CXX \
+lt_cv_prog_compiler_c_o_CXX \
+export_dynamic_flag_spec_CXX \
+whole_archive_flag_spec_CXX \
+compiler_needs_object_CXX \
+with_gnu_ld_CXX \
+allow_undefined_flag_CXX \
+no_undefined_flag_CXX \
+hardcode_libdir_flag_spec_CXX \
+hardcode_libdir_flag_spec_ld_CXX \
+hardcode_libdir_separator_CXX \
+fix_srcfile_path_CXX \
+exclude_expsyms_CXX \
+include_expsyms_CXX \
+file_list_spec_CXX \
+compiler_lib_search_dirs_CXX \
+predep_objects_CXX \
+postdep_objects_CXX \
+predeps_CXX \
+postdeps_CXX \
+compiler_lib_search_path_CXX; do
+    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec \
+old_archive_cmds_CXX \
+old_archive_from_new_cmds_CXX \
+old_archive_from_expsyms_cmds_CXX \
+archive_cmds_CXX \
+archive_expsym_cmds_CXX \
+module_cmds_CXX \
+module_expsym_cmds_CXX \
+export_symbols_cmds_CXX \
+prelink_cmds_CXX; do
+    case \`eval \\\\\$ECHO "X\\\\\$\$var"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"X\\\$\$var\\" | \\\$Xsed -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Fix-up fallback echo if it was mangled by the above quoting rules.
+case \$lt_ECHO in
+*'\\\$0 --fallback-echo"')  lt_ECHO=\`\$ECHO "X\$lt_ECHO" | \$Xsed -e 's/\\\\\\\\\\\\\\\$0 --fallback-echo"\$/\$0 --fallback-echo"/'\`
+  ;;
+esac
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'
+
+
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "relion-${RELION_API_VERSION}.pc") CONFIG_FILES="$CONFIG_FILES relion-${RELION_API_VERSION}.pc:relion.pc.in" ;;
+
+  *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+$as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   $as_echo "$as_me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr='
'
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\).*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\).*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \
+  || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5
+$as_echo "$as_me: error: could not setup config files machinery" >&2;}
+   { (exit 1); exit 1; }; }
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[	 ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_t=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_t"; then
+    break
+  elif $ac_last_try; then
+    { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5
+$as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5
+$as_echo "$as_me: error: could not setup config headers machinery" >&2;}
+   { (exit 1); exit 1; }; }
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5
+$as_echo "$as_me: error: invalid tag $ac_tag" >&2;}
+   { (exit 1); exit 1; }; };;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+$as_echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      ac_file_inputs="$ac_file_inputs '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:$LINENO: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; } ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  { as_dir="$ac_dir"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+$as_echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+    s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \
+  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&2;}
+
+  rm -f "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out" && rm -f "$tmp/out";;
+  *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";;
+  esac \
+  || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs"
+    } >"$tmp/config.h" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+    if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$tmp/config.h" "$ac_file" \
+	|| { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5
+$as_echo "$as_me: error: could not create $ac_file" >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \
+      || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5
+$as_echo "$as_me: error: could not create -" >&2;}
+   { (exit 1); exit 1; }; }
+  fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$_am_arg" : 'X\(//\)[^/]' \| \
+	 X"$_am_arg" : 'X\(//\)$' \| \
+	 X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+  :C)  { $as_echo "$as_me:$LINENO: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+  # Autoconf 2.62 quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named `Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$mf" : 'X\(//\)[^/]' \| \
+	 X"$mf" : 'X\(//\)$' \| \
+	 X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running `make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # When using ansi2knr, U may be empty or an underscore; expand it
+    U=`sed -n 's/^U = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$file" : 'X\(//\)[^/]' \| \
+	 X"$file" : 'X\(//\)$' \| \
+	 X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      { as_dir=$dirpart/$fdir
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+$as_echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+ ;;
+    "libtool":C)
+
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008 Free Software Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can 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.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that 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 GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags="CXX "
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that does not interpret backslashes.
+ECHO=$lt_ECHO
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking.  This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects
+postdep_objects=$lt_postdep_objects
+predeps=$lt_predeps
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+    || (rm -f "$cfgfile"; exit 1)
+
+  case $xsi_shell in
+  yes)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+  case ${1} in
+    */*) func_dirname_result="${1%/*}${2}" ;;
+    *  ) func_dirname_result="${3}" ;;
+  esac
+}
+
+# func_basename file
+func_basename ()
+{
+  func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+  case ${1} in
+    */*) func_dirname_result="${1%/*}${2}" ;;
+    *  ) func_dirname_result="${3}" ;;
+  esac
+  func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+  # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+  # positional parameters, so assign one to ordinary parameter first.
+  func_stripname_result=${3}
+  func_stripname_result=${func_stripname_result#"${1}"}
+  func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+  func_opt_split_opt=${1%%=*}
+  func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+  case ${1} in
+    *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+    *)    func_lo2o_result=${1} ;;
+  esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+  func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+  func_arith_result=$(( $* ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+  func_len_result=${#1}
+}
+
+_LT_EOF
+    ;;
+  *) # Bourne compatible functions.
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+  # Extract subdirectory from the argument.
+  func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+  if test "X$func_dirname_result" = "X${1}"; then
+    func_dirname_result="${3}"
+  else
+    func_dirname_result="$func_dirname_result${2}"
+  fi
+}
+
+# func_basename file
+func_basename ()
+{
+  func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+}
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+  case ${2} in
+    .*) func_stripname_result=`$ECHO "X${3}" \
+           | $Xsed -e "s%^${1}%%" -e "s%\\\\${2}\$%%"`;;
+    *)  func_stripname_result=`$ECHO "X${3}" \
+           | $Xsed -e "s%^${1}%%" -e "s%${2}\$%%"`;;
+  esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[^=]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+  func_opt_split_opt=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_opt"`
+  func_opt_split_arg=`$ECHO "X${1}" | $Xsed -e "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+  func_lo2o_result=`$ECHO "X${1}" | $Xsed -e "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+  func_xform_result=`$ECHO "X${1}" | $Xsed -e 's/\.[^.]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+  func_arith_result=`expr "$@"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+  func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+  yes)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+  eval "$1+=\$2"
+}
+_LT_EOF
+    ;;
+  *)
+    cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+  eval "$1=\$$1\$2"
+}
+
+_LT_EOF
+    ;;
+  esac
+
+
+  sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+    || (rm -f "$cfgfile"; exit 1)
+
+  mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+
+
+    cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: CXX
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_CXX
+
+# A language specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_CXX
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_CXX
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking.  This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_CXX
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_CXX
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path_CXX
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_CXX
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_CXX
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects_CXX
+postdep_objects=$lt_postdep_objects_CXX
+predeps=$lt_predeps_CXX
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# ### END LIBTOOL TAG CONFIG: CXX
+_LT_EOF
+
+ ;;
+
+  esac
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || { (exit 1); exit 1; }
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..57cbba9
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,84 @@
+## LibRelion
+
+AC_INIT([relion], [1.3], [scheres at mrc-lmb.cam.ac.uk], [relion], [http://www.relion.org])
+AM_INIT_AUTOMAKE([-Wall no-define])
+
+# Define these substitions here to keep all version information in one place.
+# For information on how to properly maintain the library version information,
+# refer to the libtool manual, section "Updating library version information":
+# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
+AC_SUBST([RELION_SO_VERSION], [1:3:0])
+AC_SUBST([RELION_API_VERSION], [1.3])
+
+# Generate two configuration headers; one for building the library itself with
+# an autogenerated template, and a second one that will be installed alongside
+# the library.
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_CXX
+AC_PROG_LIBTOOL
+
+# Check for mpi headers
+AC_ARG_ENABLE([mpi],
+    AC_HELP_STRING([--enable-mpi],
+        [compile with MPI support]),
+    if test x$enableval = "xyes"; then
+        AC_CHECK_PROGS(MPICXX, mpic++,)
+        test -z "$MPICXX" &&  AC_MSG_ERROR([couldn't find mpi library for --enable-mpi])
+        enable_mpi=$enableval
+        CXX="$MPICXX"
+        CPPFLAGS="$CPPFLAGS -fpic"
+        dnl HAVE_MPI=1
+        AC_DEFINE([HAVE_MPI], 1, [Use MPI])
+    fi,
+    [enable_mpi=no])
+AM_CONDITIONAL(HAVE_MPI, test "$enable_mpi" = yes)
+
+# Check for FFTW3
+# Check for header <fftw3.h> AC_CHECK_HEADERS doesnt work, since we must
+# use mpicc to get includes - cpp isnt always the same compiler.
+AC_MSG_CHECKING([for fftw3.h])
+
+AC_COMPILE_IFELSE(
+[AC_LANG_PROGRAM([[#include <fftw3.h>]],)],
+[
+# ok, look for library files too
+AC_MSG_RESULT(yes)
+ AC_CHECK_LIB([fftw3],main,,AC_MSG_ERROR([Cannot find fftw3 library]))
+ AC_CHECK_LIB([fftw3_threads],fftw_plan_with_nthreads,,AC_MSG_ERROR([Cannot find fftw3_threads library]))
+ FFT_LIBS="-lfftw3_threads -lfftw3"
+],[
+# not ok, echo a warning
+AC_MSG_ERROR([Cannot find the FFTW3 library. Please install it (with threads enabled) from http://www.fftw.org.])
+])
+
+#Check for FLTK
+# as g++ seems needed and not gcc for compilation, 
+#just check for presence of fltk-config program 
+[fltkfile=`pwd`/bin/fltk-config]
+AC_CHECK_FILE($fltkfile, 
+[
+enable_fltk=yes
+], 
+[
+AC_MSG_RESULT(warning: bin/fltk-config was not found, so GUI will not be built)
+enable_fltk=no
+])
+AM_CONDITIONAL(HAVE_FLTK, test "$enable_fltk" = yes)
+
+# If no --prefix is passed to the configure script, relion programs and
+# libraries will be installed under the current directory by default.
+AC_PREFIX_DEFAULT(`pwd`)
+
+# The "relion_" string is prepended by default to installed programs.
+# It can be changed using --program-prefix=your_string
+if test "x$program_prefix" = xNONE; then
+  program_transform_name="s,^,relion_,"
+fi
+
+# Override the template file name of the generated .pc file, so that there
+# is no need to rename the template file when the API version changes.
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_FILES([Makefile
+	         relion-${RELION_API_VERSION}.pc:relion.pc.in])
+AC_OUTPUT
diff --git a/depcomp b/depcomp
new file mode 100755
index 0000000..df8eea7
--- /dev/null
+++ b/depcomp
@@ -0,0 +1,630 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009 Free
+# Software Foundation, Inc.
+
+# 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, 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, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva at dcc.unicamp.br>.
+
+case $1 in
+  '')
+     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by `PROGRAMS ARGS'.
+  object      Object file output by `PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputing dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+   # This is just like dashmstdout with a different argument.
+   dashmflag=-xM
+   depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+   # This is just like msvisualcpp but w/o cygpath translation.
+   # Just convert the backslash-escaped backslashes to single forward
+   # slashes to satisfy depend.m4
+   cygpath_u="sed s,\\\\\\\\,/,g"
+   depmode=msvisualcpp
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
+## The second -e expression handles DOS-style file names with drive letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the `deleted header file' problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+  tr ' ' '
+' < "$tmpdepfile" |
+## Some versions of gcc put a space before the `:'.  On the theory
+## that the space means something, we add a space to the output as
+## well.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like `#:fec' to the end of the
+    # dependency line.
+    tr ' ' '
+' < "$tmpdepfile" \
+    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
+    tr '
+' ' ' >> "$depfile"
+    echo >> "$depfile"
+
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' '
+' < "$tmpdepfile" \
+   | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+   >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts `$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form `foo.o: dependent.h'.
+    # Do two passes, one to just change these to
+    # `$object: dependent.h' and one to simply `dependent.h:'.
+    sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+    # That's a tab and a space in the [].
+    sed -e 's,^.*\.[a-z]*:[	 ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+  else
+    # The sourcefile does not contain any dependencies, so just
+    # store a dummy comment line, to avoid errors with the Makefile
+    # "include basename.Plo" scheme.
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+icc)
+  # Intel's C compiler understands `-MD -MF file'.  However on
+  #    icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+  # ICC 7.0 will fill foo.d with something like
+  #    foo.o: sub/foo.c
+  #    foo.o: sub/foo.h
+  # which is wrong.  We want:
+  #    sub/foo.o: sub/foo.c
+  #    sub/foo.o: sub/foo.h
+  #    sub/foo.c:
+  #    sub/foo.h:
+  # ICC 7.1 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using \ :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
+    sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+  test "x$dir" = "x$object" && dir=
+  base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -eq 0; then :
+  else
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add `dependent.h:' lines.
+    sed -ne '2,${
+	       s/^ *//
+	       s/ \\*$//
+	       s/$/:/
+	       p
+	     }' "$tmpdepfile" >> "$depfile"
+  else
+    echo "#dummy" > "$depfile"
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+   # The Tru64 compiler uses -MD to generate dependencies as a side
+   # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+   # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+   # dependencies in `foo.d' instead, so we check for that too.
+   # Subdirectories are respected.
+   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
+   test "x$dir" = "x$object" && dir=
+   base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
+
+   if test "$libtool" = yes; then
+      # With Tru64 cc, shared objects can also be used to make a
+      # static library.  This mechanism is used in libtool 1.4 series to
+      # handle both shared and static libraries in a single compilation.
+      # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
+      #
+      # With libtool 1.5 this exception was removed, and libtool now
+      # generates 2 separate objects for the 2 libraries.  These two
+      # compilations output dependencies in $dir.libs/$base.o.d and
+      # in $dir$base.o.d.  We have to check for both files, because
+      # one of the two compilations can be disabled.  We should prefer
+      # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+      # automatically cleaned when .libs/ is deleted, while ignoring
+      # the former would cause a distcleancheck panic.
+      tmpdepfile1=$dir.libs/$base.lo.d   # libtool 1.4
+      tmpdepfile2=$dir$base.o.d          # libtool 1.5
+      tmpdepfile3=$dir.libs/$base.o.d    # libtool 1.5
+      tmpdepfile4=$dir.libs/$base.d      # Compaq CCC V6.2-504
+      "$@" -Wc,-MD
+   else
+      tmpdepfile1=$dir$base.o.d
+      tmpdepfile2=$dir$base.d
+      tmpdepfile3=$dir$base.d
+      tmpdepfile4=$dir$base.d
+      "$@" -MD
+   fi
+
+   stat=$?
+   if test $stat -eq 0; then :
+   else
+      rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+      exit $stat
+   fi
+
+   for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
+   do
+     test -f "$tmpdepfile" && break
+   done
+   if test -f "$tmpdepfile"; then
+      sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
+      # That's a tab and a space in the [].
+      sed -e 's,^.*\.[a-z]*:[	 ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+   else
+      echo "#dummy" > "$depfile"
+   fi
+   rm -f "$tmpdepfile"
+   ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for `:'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+  "$@" $dashmflag |
+    sed 's:^[  ]*[^: ][^:][^:]*\:[    ]*:'"$object"'\: :' > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  tr ' ' '
+' < "$tmpdepfile" | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  sed '1,2d' "$tmpdepfile" | tr ' ' '
+' | \
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+    sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove `-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E |
+    sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+       -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
+    sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+	set fnord "$@"
+	shift
+	shift
+	;;
+    *)
+	set fnord "$@" "$arg"
+	shift
+	shift
+	;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::	\1 \\:p' >> "$depfile"
+  echo "	" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/external/fftw-3.2.2.tar.gz b/external/fftw-3.2.2.tar.gz
new file mode 100644
index 0000000..244c96f
Binary files /dev/null and b/external/fftw-3.2.2.tar.gz differ
diff --git a/external/fltk-1.3.0.tar.gz b/external/fltk-1.3.0.tar.gz
new file mode 100644
index 0000000..d997742
Binary files /dev/null and b/external/fltk-1.3.0.tar.gz differ
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..6781b98
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,520 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2009-04-28.21; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# 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
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" ""	$nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+  doit_exec=exec
+else
+  doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+  test "$posix_glob" != "?" || {
+    if (set -f) 2>/dev/null; then
+      posix_glob=
+    else
+      posix_glob=:
+    fi
+  }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+	shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+	case $mode in
+	  *' '* | *'	'* | *'
+'*	  | *'*'* | *'?'* | *'['*)
+	    echo "$0: invalid mode: $mode" >&2
+	    exit 1;;
+	esac
+	shift;;
+
+    -o) chowncmd="$chownprog $2"
+	shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t) dst_arg=$2
+	shift;;
+
+    -T) no_target_directory=true;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --)	shift
+	break;;
+
+    -*)	echo "$0: invalid option: $1" >&2
+	exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call `install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  trap '(exit $?); exit' 1 2 13 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names starting with `-'.
+  case $src in
+    -*) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+
+    dst=$dst_arg
+    # Protect names starting with `-'.
+    case $dst in
+      -*) dst=./$dst;;
+    esac
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test -n "$no_target_directory"; then
+	echo "$0: $dst_arg: Is a directory" >&2
+	exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      # Prefer dirname, but fall back on a substitute if dirname fails.
+      dstdir=`
+	(dirname "$dst") 2>/dev/null ||
+	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	     X"$dst" : 'X\(//\)[^/]' \| \
+	     X"$dst" : 'X\(//\)$' \| \
+	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+	echo X"$dst" |
+	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)[^/].*/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\).*/{
+		   s//\1/
+		   q
+		 }
+		 s/.*/./; q'
+      `
+
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+	# Create intermediate dirs using mode 755 as modified by the umask.
+	# This is like FreeBSD 'install' as of 1997-10-28.
+	umask=`umask`
+	case $stripcmd.$umask in
+	  # Optimize common cases.
+	  *[2367][2367]) mkdir_umask=$umask;;
+	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+	  *[0-7])
+	    mkdir_umask=`expr $umask + 22 \
+	      - $umask % 100 % 40 + $umask % 20 \
+	      - $umask % 10 % 4 + $umask % 2
+	    `;;
+	  *) mkdir_umask=$umask,go-w;;
+	esac
+
+	# With -d, create the new directory with the user-specified mode.
+	# Otherwise, rely on $mkdir_umask.
+	if test -n "$dir_arg"; then
+	  mkdir_mode=-m$mode
+	else
+	  mkdir_mode=
+	fi
+
+	posix_mkdir=false
+	case $umask in
+	  *[123567][0-7][0-7])
+	    # POSIX mkdir -p sets u+wx bits regardless of umask, which
+	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+	    ;;
+	  *)
+	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+	    if (umask $mkdir_umask &&
+		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+	    then
+	      if test -z "$dir_arg" || {
+		   # Check for POSIX incompatibilities with -m.
+		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+		   # other-writeable bit of parent directory when it shouldn't.
+		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+		   ls_ld_tmpdir=`ls -ld "$tmpdir"`
+		   case $ls_ld_tmpdir in
+		     d????-?r-*) different_mode=700;;
+		     d????-?--*) different_mode=755;;
+		     *) false;;
+		   esac &&
+		   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+		   }
+		 }
+	      then posix_mkdir=:
+	      fi
+	      rmdir "$tmpdir/d" "$tmpdir"
+	    else
+	      # Remove any dirs left behind by ancient mkdir implementations.
+	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+	    fi
+	    trap '' 0;;
+	esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+	umask $mkdir_umask &&
+	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+	/*) prefix='/';;
+	-*) prefix='./';;
+	*)  prefix='';;
+      esac
+
+      eval "$initialize_posix_glob"
+
+      oIFS=$IFS
+      IFS=/
+      $posix_glob set -f
+      set fnord $dstdir
+      shift
+      $posix_glob set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+	test -z "$d" && continue
+
+	prefix=$prefix$d
+	if test -d "$prefix"; then
+	  prefixes=
+	else
+	  if $posix_mkdir; then
+	    (umask=$mkdir_umask &&
+	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+	    # Don't fail if two instances are running concurrently.
+	    test -d "$prefix" || exit 1
+	  else
+	    case $prefix in
+	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+	      *) qprefix=$prefix;;
+	    esac
+	    prefixes="$prefixes '$qprefix'"
+	  fi
+	fi
+	prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+	# Don't fail if two instances are running concurrently.
+	(umask $mkdir_umask &&
+	 eval "\$doit_exec \$mkdirprog $prefixes") ||
+	  test -d "$dstdir" || exit 1
+	obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"	2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"	2>/dev/null` &&
+
+       eval "$initialize_posix_glob" &&
+       $posix_glob set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       $posix_glob set +f &&
+
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+	# Now remove or move aside any old file at destination location.
+	# We try this two ways since rm can't unlink itself on some
+	# systems and the destination file might be busy for other
+	# reasons.  In this case, the final cleanup might fail but the new
+	# file should still install successfully.
+	{
+	  test ! -f "$dst" ||
+	  $doit $rmcmd -f "$dst" 2>/dev/null ||
+	  { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+	    { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+	  } ||
+	  { echo "$0: cannot unlink or rename $dst" >&2
+	    (exit 1); exit 1
+	  }
+	} &&
+
+	# Now rename the file to the real destination.
+	$doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/ltmain.sh b/ltmain.sh
new file mode 100755
index 0000000..a72f2fd
--- /dev/null
+++ b/ltmain.sh
@@ -0,0 +1,8406 @@
+# Generated from ltmain.m4sh.
+
+# ltmain.sh (GNU libtool) 2.2.6b
+# Written by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007 2008 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can 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.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that 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 GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+#     --config             show all configuration variables
+#     --debug              enable verbose shell tracing
+# -n, --dry-run            display commands without modifying any files
+#     --features           display basic configuration information and exit
+#     --mode=MODE          use operation mode MODE
+#     --preserve-dup-deps  don't remove duplicate dependency libraries
+#     --quiet, --silent    don't print informational messages
+#     --tag=TAG            use configuration variables from tag TAG
+# -v, --verbose            print informational messages (default)
+#     --version            print version information
+# -h, --help               print short or long help message
+#
+# MODE must be one of the following:
+#
+#       clean              remove files from the build directory
+#       compile            compile a source file into a libtool object
+#       execute            automatically set library path, then run a program
+#       finish             complete the installation of libtool libraries
+#       install            install libraries or executables
+#       link               create a library or an executable
+#       uninstall          remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+#       host-triplet:	$host
+#       shell:		$SHELL
+#       compiler:		$LTCC
+#       compiler flags:		$LTCFLAGS
+#       linker:		$LD (gnu? $with_gnu_ld)
+#       $progname:		(GNU libtool) 2.2.6b
+#       automake:		$automake_version
+#       autoconf:		$autoconf_version
+#
+# Report bugs to <bug-libtool at gnu.org>.
+
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=2.2.6b
+TIMESTAMP=""
+package_revision=1.3017
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# NLS nuisances: We save the old values to restore during execute mode.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test \"\${$lt_var+set}\" = set; then
+          save_$lt_var=\$$lt_var
+          $lt_var=C
+	  export $lt_var
+	  lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+	  lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+	fi"
+done
+
+$lt_unset CDPATH
+
+
+
+
+
+: ${CP="cp -f"}
+: ${ECHO="echo"}
+: ${EGREP="/bin/grep -E"}
+: ${FGREP="/bin/grep -F"}
+: ${GREP="/bin/grep"}
+: ${LN_S="ln -s"}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SED="/bin/sed"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" 	$lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+  # Extract subdirectory from the argument.
+  func_dirname_result=`$ECHO "X${1}" | $Xsed -e "$dirname"`
+  if test "X$func_dirname_result" = "X${1}"; then
+    func_dirname_result="${3}"
+  else
+    func_dirname_result="$func_dirname_result${2}"
+  fi
+  func_basename_result=`$ECHO "X${1}" | $Xsed -e "$basename"`
+}
+
+# Generated shell functions inserted here.
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+# The name of this program:
+# In the unlikely event $progname began with a '-', it would play havoc with
+# func_echo (imagine progname=-n), so we prepend ./ in that case:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+case $progname in
+  -*) progname=./$progname ;;
+esac
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=$func_dirname_result
+     progdir=`cd "$progdir" && pwd`
+     progpath="$progdir/$progname"
+     ;;
+  *)
+     save_IFS="$IFS"
+     IFS=:
+     for progdir in $PATH; do
+       IFS="$save_IFS"
+       test -x "$progdir/$progname" && break
+     done
+     IFS="$save_IFS"
+     test -n "$progdir" || progdir=`pwd`
+     progpath="$progdir/$progname"
+     ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same.  If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'.  `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+  s/$bs4/&\\
+/g
+  s/^$bs2$dollar/$bs&/
+  s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+  s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+    $ECHO "$progname${mode+: }$mode: $*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $opt_verbose && func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+    $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2
+
+    # bash bug again:
+    :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    func_error ${1+"$@"}
+    func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information."  ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    my_directory_path="$1"
+    my_dir_list=
+
+    if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+      # Protect directory names starting with `-'
+      case $my_directory_path in
+        -*) my_directory_path="./$my_directory_path" ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$my_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+	# list incase some portion of path contains whitespace.
+        my_dir_list="$my_directory_path:$my_dir_list"
+
+        # If the last portion added has no slash in it, the list is done
+        case $my_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        my_directory_path=`$ECHO "X$my_directory_path" | $Xsed -e "$dirname"`
+      done
+      my_dir_list=`$ECHO "X$my_dir_list" | $Xsed -e 's,:*$,,'`
+
+      save_mkdir_p_IFS="$IFS"; IFS=':'
+      for my_dir in $my_dir_list; do
+	IFS="$save_mkdir_p_IFS"
+        # mkdir can fail with a `File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$my_dir" 2>/dev/null || :
+      done
+      IFS="$save_mkdir_p_IFS"
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$my_directory_path" || \
+        func_fatal_error "Failed to create \`$1'"
+    fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+    my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+    if test "$opt_dry_run" = ":"; then
+      # Return a directory name, but don't create it in dry-run mode
+      my_tmpdir="${my_template}-$$"
+    else
+
+      # If mktemp works, use that first and foremost
+      my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$my_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+        save_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$my_tmpdir"
+        umask $save_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$my_tmpdir" || \
+        func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+    fi
+
+    $ECHO "X$my_tmpdir" | $Xsed
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+    case $1 in
+      *[\\\`\"\$]*)
+	func_quote_for_eval_unquoted_result=`$ECHO "X$1" | $Xsed -e "$sed_quote_subst"` ;;
+      *)
+        func_quote_for_eval_unquoted_result="$1" ;;
+    esac
+
+    case $func_quote_for_eval_unquoted_result in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting, command substitution and and variable
+      # expansion for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+        ;;
+      *)
+        func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+    esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    case $1 in
+      *[\\\`\"]*)
+	my_arg=`$ECHO "X$1" | $Xsed \
+	    -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        my_arg="$1" ;;
+    esac
+
+    case $my_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        my_arg="\"$my_arg\""
+        ;;
+    esac
+
+    func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$my_cmd"
+      my_status=$?
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$lt_user_locale
+	    $my_cmd"
+      my_status=$?
+      eval "$lt_safe_locale"
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+
+
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $SED -n '/^# '$PROGRAM' (GNU /,/# warranty; / {
+        s/^# //
+	s/^# *$//
+        s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+        p
+     }' < "$progpath"
+     exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $SED -n '/^# Usage:/,/# -h/ {
+        s/^# //
+	s/^# *$//
+	s/\$progname/'$progname'/
+	p
+    }' < "$progpath"
+    $ECHO
+    $ECHO "run \`$progname --help | more' for full usage"
+    exit $?
+}
+
+# func_help
+# Echo long help message to standard output and exit.
+func_help ()
+{
+    $SED -n '/^# Usage:/,/# Report bugs to/ {
+        s/^# //
+	s/^# *$//
+	s*\$progname*'$progname'*
+	s*\$host*'"$host"'*
+	s*\$SHELL*'"$SHELL"'*
+	s*\$LTCC*'"$LTCC"'*
+	s*\$LTCFLAGS*'"$LTCFLAGS"'*
+	s*\$LD*'"$LD"'*
+	s/\$with_gnu_ld/'"$with_gnu_ld"'/
+	s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/
+	s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/
+	p
+     }' < "$progpath"
+    exit $?
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    func_error "missing argument for $1"
+    exit_cmd=exit
+}
+
+exit_cmd=:
+
+
+
+
+
+# Check that we have a working $ECHO.
+if test "X$1" = X--no-reexec; then
+  # Discard the --no-reexec flag, and continue.
+  shift
+elif test "X$1" = X--fallback-echo; then
+  # Avoid inline document here, it may be left over
+  :
+elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then
+  # Yippee, $ECHO works!
+  :
+else
+  # Restart under the correct shell, and then maybe $ECHO will work.
+  exec $SHELL "$progpath" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+  # used as fallback echo
+  shift
+  cat <<EOF
+$*
+EOF
+  exit $EXIT_SUCCESS
+fi
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+# $mode is unset
+nonopt=
+execute_dlfiles=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+opt_dry_run=false
+opt_duplicate_deps=false
+opt_silent=false
+opt_debug=:
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func_error ${1+"$@"}
+    func_error "See the $PACKAGE documentation for more information."
+    func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+    $ECHO "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      $ECHO "enable shared libraries"
+    else
+      $ECHO "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      $ECHO "enable static libraries"
+    else
+      $ECHO "disable static libraries"
+    fi
+
+    exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+  # Global variable:
+  tagname="$1"
+
+  re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+  re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+  sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+  # Validate tagname.
+  case $tagname in
+    *[!-_A-Za-z0-9,/]*)
+      func_fatal_error "invalid tag name: $tagname"
+      ;;
+  esac
+
+  # Don't test for the "default" C tag, as we know it's
+  # there but not specially marked.
+  case $tagname in
+    CC) ;;
+    *)
+      if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+	taglist="$taglist $tagname"
+
+	# Evaluate the configuration.  Be careful to quote the path
+	# and the sed script, to avoid splitting on whitespace, but
+	# also don't use non-portable quotes within backquotes within
+	# quotes we have to do it in 2 steps:
+	extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+	eval "$extractedcf"
+      else
+	func_error "ignoring unknown tag $tagname"
+      fi
+      ;;
+  esac
+}
+
+# Parse options once, thoroughly.  This comes as soon as possible in
+# the script to make things like `libtool --version' happen quickly.
+{
+
+  # Shorthand for --mode=foo, only valid as the first argument
+  case $1 in
+  clean|clea|cle|cl)
+    shift; set dummy --mode clean ${1+"$@"}; shift
+    ;;
+  compile|compil|compi|comp|com|co|c)
+    shift; set dummy --mode compile ${1+"$@"}; shift
+    ;;
+  execute|execut|execu|exec|exe|ex|e)
+    shift; set dummy --mode execute ${1+"$@"}; shift
+    ;;
+  finish|finis|fini|fin|fi|f)
+    shift; set dummy --mode finish ${1+"$@"}; shift
+    ;;
+  install|instal|insta|inst|ins|in|i)
+    shift; set dummy --mode install ${1+"$@"}; shift
+    ;;
+  link|lin|li|l)
+    shift; set dummy --mode link ${1+"$@"}; shift
+    ;;
+  uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+    shift; set dummy --mode uninstall ${1+"$@"}; shift
+    ;;
+  esac
+
+  # Parse non-mode specific arguments:
+  while test "$#" -gt 0; do
+    opt="$1"
+    shift
+
+    case $opt in
+      --config)		func_config					;;
+
+      --debug)		preserve_args="$preserve_args $opt"
+			func_echo "enabling shell trace mode"
+			opt_debug='set -x'
+			$opt_debug
+			;;
+
+      -dlopen)		test "$#" -eq 0 && func_missing_arg "$opt" && break
+			execute_dlfiles="$execute_dlfiles $1"
+			shift
+			;;
+
+      --dry-run | -n)	opt_dry_run=:					;;
+      --features)       func_features					;;
+      --finish)		mode="finish"					;;
+
+      --mode)		test "$#" -eq 0 && func_missing_arg "$opt" && break
+			case $1 in
+			  # Valid mode arguments:
+			  clean)	;;
+			  compile)	;;
+			  execute)	;;
+			  finish)	;;
+			  install)	;;
+			  link)		;;
+			  relink)	;;
+			  uninstall)	;;
+
+			  # Catch anything else as an error
+			  *) func_error "invalid argument for $opt"
+			     exit_cmd=exit
+			     break
+			     ;;
+		        esac
+
+			mode="$1"
+			shift
+			;;
+
+      --preserve-dup-deps)
+			opt_duplicate_deps=:				;;
+
+      --quiet|--silent)	preserve_args="$preserve_args $opt"
+			opt_silent=:
+			;;
+
+      --verbose| -v)	preserve_args="$preserve_args $opt"
+			opt_silent=false
+			;;
+
+      --tag)		test "$#" -eq 0 && func_missing_arg "$opt" && break
+			preserve_args="$preserve_args $opt $1"
+			func_enable_tag "$1"	# tagname is set here
+			shift
+			;;
+
+      # Separate optargs to long options:
+      -dlopen=*|--mode=*|--tag=*)
+			func_opt_split "$opt"
+			set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"}
+			shift
+			;;
+
+      -\?|-h)		func_usage					;;
+      --help)		opt_help=:					;;
+      --version)	func_version					;;
+
+      -*)		func_fatal_help "unrecognized option \`$opt'"	;;
+
+      *)		nonopt="$opt"
+			break
+			;;
+    esac
+  done
+
+
+  case $host in
+    *cygwin* | *mingw* | *pw32* | *cegcc*)
+      # don't eliminate duplications in $postdeps and $predeps
+      opt_duplicate_compiler_generated_deps=:
+      ;;
+    *)
+      opt_duplicate_compiler_generated_deps=$opt_duplicate_deps
+      ;;
+  esac
+
+  # Having warned about all mis-specified options, bail out if
+  # anything was wrong.
+  $exit_cmd $EXIT_FAILURE
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+  if test "$package_revision" != "$macro_revision"; then
+    if test "$VERSION" != "$macro_version"; then
+      if test -z "$macro_version"; then
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      fi
+    else
+      cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+    fi
+
+    exit $EXIT_MISMATCH
+  fi
+}
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+$opt_help || {
+  # Sanity checks first:
+  func_check_version_match
+
+  if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+    func_fatal_configuration "not configured to build any kind of library"
+  fi
+
+  test -z "$mode" && func_fatal_error "error: you must specify a MODE."
+
+
+  # Darwin sucks
+  eval std_shrext=\"$shrext_cmds\"
+
+
+  # Only execute mode is allowed to have -dlopen flags.
+  if test -n "$execute_dlfiles" && test "$mode" != execute; then
+    func_error "unrecognized option \`-dlopen'"
+    $ECHO "$help" 1>&2
+    exit $EXIT_FAILURE
+  fi
+
+  # Change the help message to a mode-specific one.
+  generic_help="$help"
+  help="Try \`$progname --help --mode=$mode' for more information."
+}
+
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null \
+        | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+	for lalib_p_l in 1 2 3 4
+	do
+	    read lalib_p_line
+	    case "$lalib_p_line" in
+		\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+	    esac
+	done
+	exec 0<&5 5<&-
+    fi
+    test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_ltwrapper_scriptname_result=""
+    if func_ltwrapper_executable_p "$1"; then
+	func_dirname_and_basename "$1" "" "."
+	func_stripname '' '.exe' "$func_basename_result"
+	func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+    fi
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $opt_debug
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$save_ifs
+      eval cmd=\"$cmd\"
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $opt_debug
+    case $1 in
+    */* | *\\*)	. "$1" ;;
+    *)		. "./$1" ;;
+    esac
+}
+
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $opt_debug
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+        func_quote_for_eval "$arg"
+	CC_quoted="$CC_quoted $func_quote_for_eval_result"
+      done
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	      # Double-quote args containing other shell metacharacters.
+	      func_quote_for_eval "$arg"
+	      CC_quoted="$CC_quoted $func_quote_for_eval_result"
+	    done
+	    case "$@ " in
+	      " $CC "* | "$CC "* | " `$ECHO $CC` "* | "`$ECHO $CC` "* | " $CC_quoted"* | "$CC_quoted "* | " `$ECHO $CC_quoted` "* | "`$ECHO $CC_quoted` "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  func_echo "unable to infer tagged configuration"
+	  func_fatal_error "specify a tag with \`--tag'"
+#	else
+#	  func_verbose "using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=${1}
+    if test "$build_libtool_libs" = yes; then
+      write_lobj=\'${2}\'
+    else
+      write_lobj=none
+    fi
+
+    if test "$build_old_libs" = yes; then
+      write_oldobj=\'${3}\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "${write_libobj}"
+    }
+}
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $opt_debug
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg="$arg"
+	arg_mode=normal
+	;;
+
+      target )
+	libobj="$arg"
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  test -n "$libobj" && \
+	    func_fatal_error "you cannot specify \`-o' more than once"
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-pie | -fpie | -fPIE)
+          pie_flag="$pie_flag $arg"
+	  continue
+	  ;;
+
+	-shared | -static | -prefer-pic | -prefer-non-pic)
+	  later="$later $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  func_stripname '-Wc,' '' "$arg"
+	  args=$func_stripname_result
+	  lastarg=
+	  save_ifs="$IFS"; IFS=','
+	  for arg in $args; do
+	    IFS="$save_ifs"
+	    func_quote_for_eval "$arg"
+	    lastarg="$lastarg $func_quote_for_eval_result"
+	  done
+	  IFS="$save_ifs"
+	  func_stripname ' ' '' "$lastarg"
+	  lastarg=$func_stripname_result
+
+	  # Add the arguments to base_compile.
+	  base_compile="$base_compile $lastarg"
+	  continue
+	  ;;
+
+	*)
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg="$srcfile"
+	  srcfile="$arg"
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_quote_for_eval "$lastarg"
+      base_compile="$base_compile $func_quote_for_eval_result"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with \`-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+	func_basename "$srcfile"
+	libobj="$func_basename_result"
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.obj | *.sx)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from \`$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	continue
+	;;
+
+      -static)
+	build_libtool_libs=no
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
+      && func_warning "libobj name \`$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname="$func_basename_result"
+    xdir="$func_dirname_result"
+    lobj=${xdir}$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$ECHO "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+	$ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+      removelist="$removelist $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    removelist="$removelist $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    if test -n "$fix_srcfile_path"; then
+      eval srcfile=\"$fix_srcfile_path\"
+    fi
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+	command="$base_compile $qsrcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	command="$command -o $lobj"
+      fi
+
+      func_show_eval_locale "$command"	\
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	func_show_eval '$MV "$output_obj" "$lobj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+	suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+	# Don't build PIC code
+	command="$base_compile $qsrcfile$pie_flag"
+      else
+	command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+	command="$command -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      command="$command$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	func_show_eval '$MV "$output_obj" "$obj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test "$need_locks" != no; then
+	removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+test "$mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to building PIC objects only
+  -prefer-non-pic   try to building non-PIC objects only
+  -shared           do not build a \`.o' file suitable for static linking
+  -static           only build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode \`$mode'"
+        ;;
+    esac
+
+    $ECHO
+    $ECHO "Try \`$progname --help' for more information about other modes."
+
+    exit $?
+}
+
+  # Now that we've collected a possible --mode arg, show help if necessary
+  $opt_help && func_mode_help
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $opt_debug
+    # The first argument is the command name.
+    cmd="$nonopt"
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $execute_dlfiles; do
+      test -f "$file" \
+	|| func_fatal_help "\`$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+	func_source "$file"
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && \
+	    func_warning "\`$file' was not linked with \`-export-dynamic'"
+	  continue
+	fi
+
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  dir="$dir/$objdir"
+	else
+	  if test ! -f "$dir/$dlname"; then
+	    func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+	;;
+
+      *)
+	func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -*) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if func_ltwrapper_script_p "$file"; then
+	  func_source "$file"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	elif func_ltwrapper_executable_p "$file"; then
+	  func_ltwrapper_scriptname "$file"
+	  func_source "$func_ltwrapper_scriptname_result"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_quote_for_eval "$file"
+      args="$args $func_quote_for_eval_result"
+    done
+
+    if test "X$opt_dry_run" = Xfalse; then
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+	eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+	      else
+		$lt_unset $lt_var
+	      fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+	$ECHO "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $opt_debug
+    libdirs="$nonopt"
+    admincmds=
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for dir
+      do
+	libdirs="$libdirs $dir"
+      done
+
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $opt_dry_run || eval "$cmds" || admincmds="$admincmds
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_silent && exit $EXIT_SUCCESS
+
+    $ECHO "X----------------------------------------------------------------------" | $Xsed
+    $ECHO "Libraries have been installed in:"
+    for libdir in $libdirs; do
+      $ECHO "   $libdir"
+    done
+    $ECHO
+    $ECHO "If you ever happen to want to link against installed libraries"
+    $ECHO "in a given directory, LIBDIR, you must either use libtool, and"
+    $ECHO "specify the full pathname of the library, or use the \`-LLIBDIR'"
+    $ECHO "flag during linking and do at least one of the following:"
+    if test -n "$shlibpath_var"; then
+      $ECHO "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+      $ECHO "     during execution"
+    fi
+    if test -n "$runpath_var"; then
+      $ECHO "   - add LIBDIR to the \`$runpath_var' environment variable"
+      $ECHO "     during linking"
+    fi
+    if test -n "$hardcode_libdir_flag_spec"; then
+      libdir=LIBDIR
+      eval flag=\"$hardcode_libdir_flag_spec\"
+
+      $ECHO "   - use the \`$flag' linker flag"
+    fi
+    if test -n "$admincmds"; then
+      $ECHO "   - have your system administrator run these commands:$admincmds"
+    fi
+    if test -f /etc/ld.so.conf; then
+      $ECHO "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+    fi
+    $ECHO
+
+    $ECHO "See any operating system documentation about shared libraries for"
+    case $host in
+      solaris2.[6789]|solaris2.1[0-9])
+        $ECHO "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+	$ECHO "pages."
+	;;
+      *)
+        $ECHO "more information, such as the ld(1) and ld.so(8) manual pages."
+        ;;
+    esac
+    $ECHO "X----------------------------------------------------------------------" | $Xsed
+    exit $EXIT_SUCCESS
+}
+
+test "$mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $opt_debug
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       $ECHO "X$nonopt" | $GREP shtool >/dev/null; then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    install_prog="$install_prog$func_quote_for_eval_result"
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    for arg
+    do
+      if test -n "$dest"; then
+	files="$files $dest"
+	dest=$arg
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f)
+	case " $install_prog " in
+	*[\\\ /]cp\ *) ;;
+	*) prev=$arg ;;
+	esac
+	;;
+      -g | -m | -o)
+	prev=$arg
+	;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*)
+	;;
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  prev=
+	else
+	  dest=$arg
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      install_prog="$install_prog $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prev' option requires an argument"
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	func_fatal_help "no file or destination specified"
+      else
+	func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir="$func_dirname_result"
+      destname="$func_basename_result"
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+	func_fatal_help "\`$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  func_fatal_help "\`$destdir' must be an absolute directory name"
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	staticlibs="$staticlibs $file"
+	;;
+
+      *.la)
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$file' is not a valid libtool archive"
+
+	library_names=
+	old_library=
+	relink_command=
+	func_source "$file"
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) current_libdirs="$current_libdirs $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) future_libdirs="$future_libdirs $libdir" ;;
+	  esac
+	fi
+
+	func_dirname "$file" "/" ""
+	dir="$func_dirname_result"
+	dir="$dir$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$ECHO "X$destdir" | $Xsed -e "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  test "$inst_prefix_dir" = "$destdir" && \
+	    func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+	  else
+	    relink_command=`$ECHO "X$relink_command" | $Xsed -e "s%@inst_prefix_dir@%%"`
+	  fi
+
+	  func_warning "relinking \`$file'"
+	  func_show_eval "$relink_command" \
+	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names; shift
+	if test -n "$1"; then
+	  realname="$1"
+	  shift
+
+	  srcname="$realname"
+	  test -n "$relink_command" && srcname="$realname"T
+
+	  # Install the shared library and build the symlinks.
+	  func_show_eval "$install_prog $dir/$srcname $destdir/$realname" \
+	      'exit $?'
+	  tstripme="$stripme"
+	  case $host_os in
+	  cygwin* | mingw* | pw32* | cegcc*)
+	    case $realname in
+	    *.dll.a)
+	      tstripme=""
+	      ;;
+	    esac
+	    ;;
+	  esac
+	  if test -n "$tstripme" && test -n "$striplib"; then
+	    func_show_eval "$striplib $destdir/$realname" 'exit $?'
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    # Try `ln -sf' first, because the `ln' binary might depend on
+	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
+	    # so we also need to try rm && ln -s.
+	    for linkname
+	    do
+	      test "$linkname" != "$realname" \
+		&& func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib="$destdir/$realname"
+	  func_execute_cmds "$postinstall_cmds" 'exit $?'
+	fi
+
+	# Install the pseudo-library for information purposes.
+	func_basename "$file"
+	name="$func_basename_result"
+	instname="$dir/$name"i
+	func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  func_lo2o "$destfile"
+	  staticdest=$func_lo2o_result
+	  ;;
+	*.$objext)
+	  staticdest="$destfile"
+	  destfile=
+	  ;;
+	*)
+	  func_fatal_help "cannot copy a libtool object to \`$destfile'"
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	test -n "$destfile" && \
+	  func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+	# Install the old object if enabled.
+	if test "$build_old_libs" = yes; then
+	  # Deduce the name of the old-style object file.
+	  func_lo2o "$file"
+	  staticobj=$func_lo2o_result
+	  func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=""
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      func_stripname '' '.exe' "$file"
+	      file=$func_stripname_result
+	      stripped_ext=".exe"
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin* | *mingw*)
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      wrapper=$func_ltwrapper_scriptname_result
+	    else
+	      func_stripname '' '.exe' "$file"
+	      wrapper=$func_stripname_result
+	    fi
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if func_ltwrapper_script_p "$wrapper"; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  func_source "$wrapper"
+
+	  # Check the variables that should have been set.
+	  test -z "$generated_by_libtool_version" && \
+	    func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+	  finalize=yes
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      func_source "$lib"
+	    fi
+	    libfile="$libdir/"`$ECHO "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      func_warning "\`$lib' has not been installed in \`$libdir'"
+	      finalize=no
+	    fi
+	  done
+
+	  relink_command=
+	  func_source "$wrapper"
+
+	  outputname=
+	  if test "$fast_install" = no && test -n "$relink_command"; then
+	    $opt_dry_run || {
+	      if test "$finalize" = yes; then
+	        tmpdir=`func_mktempdir`
+		func_basename "$file$stripped_ext"
+		file="$func_basename_result"
+	        outputname="$tmpdir/$file"
+	        # Replace the output file specification.
+	        relink_command=`$ECHO "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+	        $opt_silent || {
+	          func_quote_for_expand "$relink_command"
+		  eval "func_echo $func_quote_for_expand_result"
+	        }
+	        if eval "$relink_command"; then :
+	          else
+		  func_error "error: relink \`$file' with the above command before installing it"
+		  $opt_dry_run || ${RM}r "$tmpdir"
+		  continue
+	        fi
+	        file="$outputname"
+	      else
+	        func_warning "cannot relink \`$file'"
+	      fi
+	    }
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$ECHO "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyway
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    func_stripname '' '.exe' "$destfile"
+	    destfile=$func_stripname_result
+	    ;;
+	  esac
+	  ;;
+	esac
+	func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+	$opt_dry_run || if test -n "$outputname"; then
+	  ${RM}r "$tmpdir"
+	fi
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name="$func_basename_result"
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	func_show_eval "$old_striplib $oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $opt_debug
+    my_outputname="$1"
+    my_originator="$2"
+    my_pic_p="${3-no}"
+    my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	my_dlsyms="${my_outputname}S.c"
+      else
+	func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+	# Discover the nlist of each of the dlfiles.
+	nlist="$output_objdir/${my_outputname}.nm"
+
+	func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+	# Parse the name list into a source file.
+	func_verbose "creating $output_objdir/$my_dlsyms"
+
+	$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+	if test "$dlself" = yes; then
+	  func_verbose "generating symbol list for \`$output'"
+
+	  $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+	  # Add our own program objects to the symbol list.
+	  progfiles=`$ECHO "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+	  for progfile in $progfiles; do
+	    func_verbose "extracting global C symbols from \`$progfile'"
+	    $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -n "$exclude_expsyms"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  if test -n "$export_symbols_regex"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  # Prepare the list of exported symbols
+	  if test -z "$export_symbols"; then
+	    export_symbols="$output_objdir/$outputname.exp"
+	    $opt_dry_run || {
+	      $RM $export_symbols
+	      eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	      case $host in
+	      *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+	        ;;
+	      esac
+	    }
+	  else
+	    $opt_dry_run || {
+	      eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	      case $host in
+	        *cygwin | *mingw* | *cegcc* )
+	          eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+	          eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+	          ;;
+	      esac
+	    }
+	  fi
+	fi
+
+	for dlprefile in $dlprefiles; do
+	  func_verbose "extracting global C symbols from \`$dlprefile'"
+	  func_basename "$dlprefile"
+	  name="$func_basename_result"
+	  $opt_dry_run || {
+	    eval '$ECHO ": $name " >> "$nlist"'
+	    eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	  }
+	done
+
+	$opt_dry_run || {
+	  # Make sure we have at least an empty file.
+	  test -f "$nlist" || : > "$nlist"
+
+	  if test -n "$exclude_expsyms"; then
+	    $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	    $MV "$nlist"T "$nlist"
+	  fi
+
+	  # Try sorting and uniquifying the output.
+	  if $GREP -v "^: " < "$nlist" |
+	      if sort -k 3 </dev/null >/dev/null 2>&1; then
+		sort -k 3
+	      else
+		sort +2
+	      fi |
+	      uniq > "$nlist"S; then
+	    :
+	  else
+	    $GREP -v "^: " < "$nlist" > "$nlist"S
+	  fi
+
+	  if test -f "$nlist"S; then
+	    eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+	  else
+	    $ECHO '/* NONE */' >> "$output_objdir/$my_dlsyms"
+	  fi
+
+	  $ECHO >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+"
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc* )
+	    $ECHO >> "$output_objdir/$my_dlsyms" "\
+/* DATA imports from DLLs on WIN32 con't be const, because
+   runtime relocations are performed -- see ld's documentation
+   on pseudo-relocs.  */"
+	    lt_dlsym_const= ;;
+	  *osf5*)
+	    echo >> "$output_objdir/$my_dlsyms" "\
+/* This system does not cope well with relocations in const data */"
+	    lt_dlsym_const= ;;
+	  *)
+	    lt_dlsym_const=const ;;
+	  esac
+
+	  $ECHO >> "$output_objdir/$my_dlsyms" "\
+extern $lt_dlsym_const lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+$lt_dlsym_const lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+  { \"$my_originator\", (void *) 0 },"
+
+	  case $need_lib_prefix in
+	  no)
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  *)
+	    eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  esac
+	  $ECHO >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	} # !$opt_dry_run
+
+	pic_flag_for_symtable=
+	case "$compile_command " in
+	*" -static "*) ;;
+	*)
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+	  *-*-hpux*)
+	    pic_flag_for_symtable=" $pic_flag"  ;;
+	  *)
+	    if test "X$my_pic_p" != Xno; then
+	      pic_flag_for_symtable=" $pic_flag"
+	    fi
+	    ;;
+	  esac
+	  ;;
+	esac
+	symtab_cflags=
+	for arg in $LTCFLAGS; do
+	  case $arg in
+	  -pie | -fpie | -fPIE) ;;
+	  *) symtab_cflags="$symtab_cflags $arg" ;;
+	  esac
+	done
+
+	# Now compile the dynamic symbol file.
+	func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+	# Clean up the generated files.
+	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+	# Transform the symbol file into the correct name.
+	symfileobj="$output_objdir/${my_outputname}S.$objext"
+	case $host in
+	*cygwin* | *mingw* | *cegcc* )
+	  if test -f "$output_objdir/$my_outputname.def"; then
+	    compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	    finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	  else
+	    compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
+	    finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
+	  fi
+	  ;;
+	*)
+	  compile_command=`$ECHO "X$compile_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
+	  finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$symfileobj%"`
+	  ;;
+	esac
+	;;
+      *)
+	func_fatal_error "unknown suffix for \`$my_dlsyms'"
+	;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+func_win32_libid ()
+{
+  $opt_debug
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+      win32_nmres=`eval $NM -f posix -A $1 |
+	$SED -n -e '
+	    1,100{
+		/ I /{
+		    s,.*,import,
+		    p
+		    q
+		}
+	    }'`
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $opt_debug
+    f_ex_an_ar_dir="$1"; shift
+    f_ex_an_ar_oldlib="$1"
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" 'exit $?'
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $opt_debug
+    my_gentop="$1"; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=""
+    my_xlib=""
+    my_xabs=""
+    my_xdir=""
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+	*) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib="$func_basename_result"
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+	*" $my_xlib_u "*)
+	  func_arith $extracted_serial + 1
+	  extracted_serial=$func_arith_result
+	  my_xlib_u=lt$extracted_serial-$my_xlib ;;
+	*) break ;;
+	esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir="$my_gentop/$my_xlib_u"
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+	func_verbose "Extracting $my_xabs"
+	# Do not bother doing anything if just a dry run
+	$opt_dry_run || {
+	  darwin_orig_dir=`pwd`
+	  cd $my_xdir || exit $?
+	  darwin_archive=$my_xabs
+	  darwin_curdir=`pwd`
+	  darwin_base_archive=`basename "$darwin_archive"`
+	  darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+	  if test -n "$darwin_arches"; then
+	    darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+	    darwin_arch=
+	    func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+	    for darwin_arch in  $darwin_arches ; do
+	      func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+	      cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+	      cd "$darwin_curdir"
+	      $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+	    done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+	    darwin_file=
+	    darwin_files=
+	    for darwin_file in $darwin_filelist; do
+	      darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP`
+	      $LIPO -create -output "$darwin_file" $darwin_files
+	    done # $darwin_filelist
+	    $RM -rf unfat-$$
+	    cd "$darwin_orig_dir"
+	  else
+	    cd $darwin_orig_dir
+	    func_extract_an_archive "$my_xdir" "$my_xabs"
+	  fi # $darwin_arches
+	} # !$opt_dry_run
+	;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+	;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+    done
+
+    func_extract_archives_result="$my_oldobjs"
+}
+
+
+
+# func_emit_wrapper_part1 [arg=no]
+#
+# Emit the first part of a libtool wrapper script on stdout.
+# For more information, see the description associated with
+# func_emit_wrapper(), below.
+func_emit_wrapper_part1 ()
+{
+	func_emit_wrapper_part1_arg1=no
+	if test -n "$1" ; then
+	  func_emit_wrapper_part1_arg1=$1
+	fi
+
+	$ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='${SED} -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    ECHO=\"$qecho\"
+    file=\"\$0\"
+    # Make sure echo works.
+    if test \"X\$1\" = X--no-reexec; then
+      # Discard the --no-reexec flag, and continue.
+      shift
+    elif test \"X\`{ \$ECHO '\t'; } 2>/dev/null\`\" = 'X\t'; then
+      # Yippee, \$ECHO works!
+      :
+    else
+      # Restart under the correct shell, and then maybe \$ECHO will work.
+      exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+    fi
+  fi\
+"
+	$ECHO "\
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+  done
+"
+}
+# end: func_emit_wrapper_part1
+
+# func_emit_wrapper_part2 [arg=no]
+#
+# Emit the second part of a libtool wrapper script on stdout.
+# For more information, see the description associated with
+# func_emit_wrapper(), below.
+func_emit_wrapper_part2 ()
+{
+	func_emit_wrapper_part2_arg1=no
+	if test -n "$1" ; then
+	  func_emit_wrapper_part2_arg1=$1
+	fi
+
+	$ECHO "\
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_part2_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"X\$thisdir\" | \$Xsed -e 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test "$fast_install" = yes; then
+	  $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+	  $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	$ECHO \"\$relink_command_output\" >&2
+	$RM \"\$progdir/\$file\"
+	exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+	else
+	  $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# Export our shlibpath_var if we have one.
+	if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	# fixup the dll searchpath if we need to.
+	if test -n "$dllsearchpath"; then
+	  $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	$ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+"
+	case $host in
+	# Backslashes separate directories on plain windows
+	*-*-mingw | *-*-os2* | *-cegcc*)
+	  $ECHO "\
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+	  ;;
+
+	*)
+	  $ECHO "\
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+	  ;;
+	esac
+	$ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    $ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+# end: func_emit_wrapper_part2
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+	func_emit_wrapper_arg1=no
+	if test -n "$1" ; then
+	  func_emit_wrapper_arg1=$1
+	fi
+
+	# split this up so that func_emit_cwrapperexe_src
+	# can call each part independently.
+	func_emit_wrapper_part1 "${func_emit_wrapper_arg1}"
+	func_emit_wrapper_part2 "${func_emit_wrapper_arg1}"
+}
+
+
+# func_to_host_path arg
+#
+# Convert paths to host format when used with build tools.
+# Intended for use with "native" mingw (where libtool itself
+# is running under the msys shell), or in the following cross-
+# build environments:
+#    $build          $host
+#    mingw (msys)    mingw  [e.g. native]
+#    cygwin          mingw
+#    *nix + wine     mingw
+# where wine is equipped with the `winepath' executable.
+# In the native mingw case, the (msys) shell automatically
+# converts paths for any non-msys applications it launches,
+# but that facility isn't available from inside the cwrapper.
+# Similar accommodations are necessary for $host mingw and
+# $build cygwin.  Calling this function does no harm for other
+# $host/$build combinations not listed above.
+#
+# ARG is the path (on $build) that should be converted to
+# the proper representation for $host. The result is stored
+# in $func_to_host_path_result.
+func_to_host_path ()
+{
+  func_to_host_path_result="$1"
+  if test -n "$1" ; then
+    case $host in
+      *mingw* )
+        lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+        case $build in
+          *mingw* ) # actually, msys
+            # awkward: cmd appends spaces to result
+            lt_sed_strip_trailing_spaces="s/[ ]*\$//"
+            func_to_host_path_tmp1=`( cmd //c echo "$1" |\
+              $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""`
+            func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
+              $SED -e "$lt_sed_naive_backslashify"`
+            ;;
+          *cygwin* )
+            func_to_host_path_tmp1=`cygpath -w "$1"`
+            func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
+              $SED -e "$lt_sed_naive_backslashify"`
+            ;;
+          * )
+            # Unfortunately, winepath does not exit with a non-zero
+            # error code, so we are forced to check the contents of
+            # stdout. On the other hand, if the command is not
+            # found, the shell will set an exit code of 127 and print
+            # *an error message* to stdout. So we must check for both
+            # error code of zero AND non-empty stdout, which explains
+            # the odd construction:
+            func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null`
+            if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then
+              func_to_host_path_result=`echo "$func_to_host_path_tmp1" |\
+                $SED -e "$lt_sed_naive_backslashify"`
+            else
+              # Allow warning below.
+              func_to_host_path_result=""
+            fi
+            ;;
+        esac
+        if test -z "$func_to_host_path_result" ; then
+          func_error "Could not determine host path corresponding to"
+          func_error "  '$1'"
+          func_error "Continuing, but uninstalled executables may not work."
+          # Fallback:
+          func_to_host_path_result="$1"
+        fi
+        ;;
+    esac
+  fi
+}
+# end: func_to_host_path
+
+# func_to_host_pathlist arg
+#
+# Convert pathlists to host format when used with build tools.
+# See func_to_host_path(), above. This function supports the
+# following $build/$host combinations (but does no harm for
+# combinations not listed here):
+#    $build          $host
+#    mingw (msys)    mingw  [e.g. native]
+#    cygwin          mingw
+#    *nix + wine     mingw
+#
+# Path separators are also converted from $build format to
+# $host format. If ARG begins or ends with a path separator
+# character, it is preserved (but converted to $host format)
+# on output.
+#
+# ARG is a pathlist (on $build) that should be converted to
+# the proper representation on $host. The result is stored
+# in $func_to_host_pathlist_result.
+func_to_host_pathlist ()
+{
+  func_to_host_pathlist_result="$1"
+  if test -n "$1" ; then
+    case $host in
+      *mingw* )
+        lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+        # Remove leading and trailing path separator characters from
+        # ARG. msys behavior is inconsistent here, cygpath turns them
+        # into '.;' and ';.', and winepath ignores them completely.
+        func_to_host_pathlist_tmp2="$1"
+        # Once set for this call, this variable should not be
+        # reassigned. It is used in tha fallback case.
+        func_to_host_pathlist_tmp1=`echo "$func_to_host_pathlist_tmp2" |\
+          $SED -e 's|^:*||' -e 's|:*$||'`
+        case $build in
+          *mingw* ) # Actually, msys.
+            # Awkward: cmd appends spaces to result.
+            lt_sed_strip_trailing_spaces="s/[ ]*\$//"
+            func_to_host_pathlist_tmp2=`( cmd //c echo "$func_to_host_pathlist_tmp1" |\
+              $SED -e "$lt_sed_strip_trailing_spaces" ) 2>/dev/null || echo ""`
+            func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\
+              $SED -e "$lt_sed_naive_backslashify"`
+            ;;
+          *cygwin* )
+            func_to_host_pathlist_tmp2=`cygpath -w -p "$func_to_host_pathlist_tmp1"`
+            func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp2" |\
+              $SED -e "$lt_sed_naive_backslashify"`
+            ;;
+          * )
+            # unfortunately, winepath doesn't convert pathlists
+            func_to_host_pathlist_result=""
+            func_to_host_pathlist_oldIFS=$IFS
+            IFS=:
+            for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do
+              IFS=$func_to_host_pathlist_oldIFS
+              if test -n "$func_to_host_pathlist_f" ; then
+                func_to_host_path "$func_to_host_pathlist_f"
+                if test -n "$func_to_host_path_result" ; then
+                  if test -z "$func_to_host_pathlist_result" ; then
+                    func_to_host_pathlist_result="$func_to_host_path_result"
+                  else
+                    func_to_host_pathlist_result="$func_to_host_pathlist_result;$func_to_host_path_result"
+                  fi
+                fi
+              fi
+              IFS=:
+            done
+            IFS=$func_to_host_pathlist_oldIFS
+            ;;
+        esac
+        if test -z "$func_to_host_pathlist_result" ; then
+          func_error "Could not determine the host path(s) corresponding to"
+          func_error "  '$1'"
+          func_error "Continuing, but uninstalled executables may not work."
+          # Fallback. This may break if $1 contains DOS-style drive
+          # specifications. The fix is not to complicate the expression
+          # below, but for the user to provide a working wine installation
+          # with winepath so that path translation in the cross-to-mingw
+          # case works properly.
+          lt_replace_pathsep_nix_to_dos="s|:|;|g"
+          func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\
+            $SED -e "$lt_replace_pathsep_nix_to_dos"`
+        fi
+        # Now, add the leading and trailing path separators back
+        case "$1" in
+          :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result"
+            ;;
+        esac
+        case "$1" in
+          *: ) func_to_host_pathlist_result="$func_to_host_pathlist_result;"
+            ;;
+        esac
+        ;;
+    esac
+  fi
+}
+# end: func_to_host_pathlist
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+	cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+
+   Currently, it simply execs the wrapper *script* "$SHELL $output",
+   but could eventually absorb all of the scripts functionality and
+   exec $objdir/$outputname directly.
+*/
+EOF
+	    cat <<"EOF"
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+# define setmode _setmode
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+#  define HAVE_SETENV
+#  ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+#  endif
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+#ifdef _MSC_VER
+# define S_IXUSR _S_IEXEC
+# define stat _stat
+# ifndef _INTPTR_T_DEFINED
+#  define intptr_t int
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifdef __CYGWIN__
+# define FOPEN_WB "wb"
+#endif
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#undef LTWRAPPER_DEBUGPRINTF
+#if defined DEBUGWRAPPER
+# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args
+static void
+ltwrapper_debugprintf (const char *fmt, ...)
+{
+    va_list args;
+    va_start (args, fmt);
+    (void) vfprintf (stderr, fmt, args);
+    va_end (args);
+}
+#else
+# define LTWRAPPER_DEBUGPRINTF(args)
+#endif
+
+const char *program_name = NULL;
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_opt_process_env_set (const char *arg);
+void lt_opt_process_env_prepend (const char *arg);
+void lt_opt_process_env_append (const char *arg);
+int lt_split_name_value (const char *arg, char** name, char** value);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+
+static const char *script_text_part1 =
+EOF
+
+	    func_emit_wrapper_part1 yes |
+	        $SED -e 's/\([\\"]\)/\\\1/g' \
+	             -e 's/^/  "/' -e 's/$/\\n"/'
+	    echo ";"
+	    cat <<EOF
+
+static const char *script_text_part2 =
+EOF
+	    func_emit_wrapper_part2 yes |
+	        $SED -e 's/\([\\"]\)/\\\1/g' \
+	             -e 's/^/  "/' -e 's/$/\\n"/'
+	    echo ";"
+
+	    cat <<EOF
+const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+	    if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_pathlist "$temp_rpath"
+	      cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_pathlist_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test -n "$dllsearchpath"; then
+              func_to_host_pathlist "$dllsearchpath:"
+	      cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_pathlist_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test "$fast_install" = yes; then
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+	    else
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+	    fi
+
+
+	    cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+#define LTWRAPPER_OPTION_PREFIX_LENGTH  5
+
+static const size_t opt_prefix_len         = LTWRAPPER_OPTION_PREFIX_LENGTH;
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+
+static const size_t env_set_opt_len     = LTWRAPPER_OPTION_PREFIX_LENGTH + 7;
+static const char *env_set_opt          = LTWRAPPER_OPTION_PREFIX "env-set";
+  /* argument is putenv-style "foo=bar", value of foo is set to bar */
+
+static const size_t env_prepend_opt_len = LTWRAPPER_OPTION_PREFIX_LENGTH + 11;
+static const char *env_prepend_opt      = LTWRAPPER_OPTION_PREFIX "env-prepend";
+  /* argument is putenv-style "foo=bar", new value of foo is bar${foo} */
+
+static const size_t env_append_opt_len  = LTWRAPPER_OPTION_PREFIX_LENGTH + 10;
+static const char *env_append_opt       = LTWRAPPER_OPTION_PREFIX "env-append";
+  /* argument is putenv-style "foo=bar", new value of foo is ${foo}bar */
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  intptr_t rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  LTWRAPPER_DEBUGPRINTF (("(main) argv[0]      : %s\n", argv[0]));
+  LTWRAPPER_DEBUGPRINTF (("(main) program_name : %s\n", program_name));
+
+  /* very simple arg parsing; don't want to rely on getopt */
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], dumpscript_opt) == 0)
+	{
+EOF
+	    case "$host" in
+	      *mingw* | *cygwin* )
+		# make stdout use "unix" line endings
+		echo "          setmode(1,_O_BINARY);"
+		;;
+	      esac
+
+	    cat <<"EOF"
+	  printf ("%s", script_text_part1);
+	  printf ("%s", script_text_part2);
+	  return 0;
+	}
+    }
+
+  newargz = XMALLOC (char *, argc + 1);
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal ("Couldn't find %s", argv[0]);
+  LTWRAPPER_DEBUGPRINTF (("(main) found exe (before symlink chase) at : %s\n",
+			  tmp_pathspec));
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  LTWRAPPER_DEBUGPRINTF (("(main) found exe (after symlink chase) at : %s\n",
+			  actual_cwrapper_path));
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup( base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  LTWRAPPER_DEBUGPRINTF (("(main) libtool target name: %s\n",
+			  target_name));
+EOF
+
+	    cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+		    strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+	    cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+	    case $host_os in
+	      mingw*)
+	    cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+	*p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+	*p = '/';
+      }
+  }
+EOF
+	    ;;
+	    esac
+
+	    cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (strncmp (argv[i], env_set_opt, env_set_opt_len) == 0)
+        {
+          if (argv[i][env_set_opt_len] == '=')
+            {
+              const char *p = argv[i] + env_set_opt_len + 1;
+              lt_opt_process_env_set (p);
+            }
+          else if (argv[i][env_set_opt_len] == '\0' && i + 1 < argc)
+            {
+              lt_opt_process_env_set (argv[++i]); /* don't copy */
+            }
+          else
+            lt_fatal ("%s missing required argument", env_set_opt);
+          continue;
+        }
+      if (strncmp (argv[i], env_prepend_opt, env_prepend_opt_len) == 0)
+        {
+          if (argv[i][env_prepend_opt_len] == '=')
+            {
+              const char *p = argv[i] + env_prepend_opt_len + 1;
+              lt_opt_process_env_prepend (p);
+            }
+          else if (argv[i][env_prepend_opt_len] == '\0' && i + 1 < argc)
+            {
+              lt_opt_process_env_prepend (argv[++i]); /* don't copy */
+            }
+          else
+            lt_fatal ("%s missing required argument", env_prepend_opt);
+          continue;
+        }
+      if (strncmp (argv[i], env_append_opt, env_append_opt_len) == 0)
+        {
+          if (argv[i][env_append_opt_len] == '=')
+            {
+              const char *p = argv[i] + env_append_opt_len + 1;
+              lt_opt_process_env_append (p);
+            }
+          else if (argv[i][env_append_opt_len] == '\0' && i + 1 < argc)
+            {
+              lt_opt_process_env_append (argv[++i]); /* don't copy */
+            }
+          else
+            lt_fatal ("%s missing required argument", env_append_opt);
+          continue;
+        }
+      if (strncmp (argv[i], ltwrapper_option_prefix, opt_prefix_len) == 0)
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal ("Unrecognized option in %s namespace: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+  LTWRAPPER_DEBUGPRINTF     (("(main) lt_argv_zero : %s\n", (lt_argv_zero ? lt_argv_zero : "<NULL>")));
+  for (i = 0; i < newargc; i++)
+    {
+      LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d]   : %s\n", i, (newargz[i] ? newargz[i] : "<NULL>")));
+    }
+
+EOF
+
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno));
+      return 127;
+    }
+  return rval;
+EOF
+		;;
+	      *)
+		cat <<"EOF"
+  execv (lt_argv_zero, newargz);
+  return rval; /* =127, but avoids unused variable warning */
+EOF
+		;;
+	    esac
+
+	    cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void *p = (void *) malloc (num);
+  if (!p)
+    lt_fatal ("Memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+			  string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable (const char *path)
+{
+  struct stat st;
+
+  LTWRAPPER_DEBUGPRINTF (("(check_executable)  : %s\n",
+			  path ? (*path ? path : "EMPTY!") : "NULL!"));
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  LTWRAPPER_DEBUGPRINTF (("(make_executable)   : %s\n",
+			  path ? (*path ? path : "EMPTY!") : "NULL!"));
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  int tmp_len;
+  char *concat_name;
+
+  LTWRAPPER_DEBUGPRINTF (("(find_executable)   : %s\n",
+			  wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!"));
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+	return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+	{
+	  concat_name = xstrdup (wrapper);
+	  if (check_executable (concat_name))
+	    return concat_name;
+	  XFREE (concat_name);
+	}
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+	has_slash = 1;
+	break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+	{
+	  for (p = path; *p; p = p_next)
+	    {
+	      const char *q;
+	      size_t p_len;
+	      for (q = p; *q; q++)
+		if (IS_PATH_SEPARATOR (*q))
+		  break;
+	      p_len = q - p;
+	      p_next = (*q == '\0' ? q : q + 1);
+	      if (p_len == 0)
+		{
+		  /* empty path: current directory */
+		  if (getcwd (tmp, LT_PATHMAX) == NULL)
+		    lt_fatal ("getcwd failed");
+		  tmp_len = strlen (tmp);
+		  concat_name =
+		    XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, tmp, tmp_len);
+		  concat_name[tmp_len] = '/';
+		  strcpy (concat_name + tmp_len + 1, wrapper);
+		}
+	      else
+		{
+		  concat_name =
+		    XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, p, p_len);
+		  concat_name[p_len] = '/';
+		  strcpy (concat_name + p_len + 1, wrapper);
+		}
+	      if (check_executable (concat_name))
+		return concat_name;
+	      XFREE (concat_name);
+	    }
+	}
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal ("getcwd failed");
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n",
+			      tmp_pathspec));
+      if (lstat (tmp_pathspec, &s) == 0)
+	{
+	  if (S_ISLNK (s.st_mode) != 0)
+	    {
+	      has_symlinks = 1;
+	      break;
+	    }
+
+	  /* search backwards for last DIR_SEPARATOR */
+	  p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+	  while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    p--;
+	  if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    {
+	      /* no more DIR_SEPARATORS left */
+	      break;
+	    }
+	  *p = '\0';
+	}
+      else
+	{
+	  char *errstr = strerror (errno);
+	  lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr);
+	}
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal ("Could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (strcmp (str, pat) == 0)
+	*str = '\0';
+    }
+  return str;
+}
+
+static void
+lt_error_core (int exit_status, const char *mode,
+	       const char *message, va_list ap)
+{
+  fprintf (stderr, "%s: %s: ", program_name, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+  va_end (ap);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n",
+                          (name ? name : "<NULL>"),
+                          (value ? value : "<NULL>")));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    int len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      int orig_value_len = strlen (orig_value);
+      int add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+int
+lt_split_name_value (const char *arg, char** name, char** value)
+{
+  const char *p;
+  int len;
+  if (!arg || !*arg)
+    return 1;
+
+  p = strchr (arg, (int)'=');
+
+  if (!p)
+    return 1;
+
+  *value = xstrdup (++p);
+
+  len = strlen (arg) - strlen (*value);
+  *name = XMALLOC (char, len);
+  strncpy (*name, arg, len-1);
+  (*name)[len - 1] = '\0';
+
+  return 0;
+}
+
+void
+lt_opt_process_env_set (const char *arg)
+{
+  char *name = NULL;
+  char *value = NULL;
+
+  if (lt_split_name_value (arg, &name, &value) != 0)
+    {
+      XFREE (name);
+      XFREE (value);
+      lt_fatal ("bad argument for %s: '%s'", env_set_opt, arg);
+    }
+
+  lt_setenv (name, value);
+  XFREE (name);
+  XFREE (value);
+}
+
+void
+lt_opt_process_env_prepend (const char *arg)
+{
+  char *name = NULL;
+  char *value = NULL;
+  char *new_value = NULL;
+
+  if (lt_split_name_value (arg, &name, &value) != 0)
+    {
+      XFREE (name);
+      XFREE (value);
+      lt_fatal ("bad argument for %s: '%s'", env_prepend_opt, arg);
+    }
+
+  new_value = lt_extend_str (getenv (name), value, 0);
+  lt_setenv (name, new_value);
+  XFREE (new_value);
+  XFREE (name);
+  XFREE (value);
+}
+
+void
+lt_opt_process_env_append (const char *arg)
+{
+  char *name = NULL;
+  char *value = NULL;
+  char *new_value = NULL;
+
+  if (lt_split_name_value (arg, &name, &value) != 0)
+    {
+      XFREE (name);
+      XFREE (value);
+      lt_fatal ("bad argument for %s: '%s'", env_append_opt, arg);
+    }
+
+  new_value = lt_extend_str (getenv (name), value, 1);
+  lt_setenv (name, new_value);
+  XFREE (new_value);
+  XFREE (name);
+  XFREE (value);
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                          (name ? name : "<NULL>"),
+                          (value ? value : "<NULL>")));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      int len = strlen (new_value);
+      while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[len-1] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                          (name ? name : "<NULL>"),
+                          (value ? value : "<NULL>")));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $opt_debug
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module="${wl}-single_module"
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	break
+	;;
+      -all-static | -static | -static-libtool-libs)
+	case $arg in
+	-all-static)
+	  if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+	    func_warning "complete static linking is impossible in this configuration"
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	-static)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=built
+	  ;;
+	-static-libtool-libs)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	esac
+	build_libtool_libs=no
+	build_old_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  func_append compile_command " @OUTPUT@"
+	  func_append finalize_command " @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	dlfiles|dlprefiles)
+	  if test "$preload" = no; then
+	    # Add the symbol object into the linking commands.
+	    func_append compile_command " @SYMFILE@"
+	    func_append finalize_command " @SYMFILE@"
+	    preload=yes
+	  fi
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test "$dlself" = no; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test "$prev" = dlprefiles; then
+	      dlself=yes
+	    elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test "$prev" = dlfiles; then
+	      dlfiles="$dlfiles $arg"
+	    else
+	      dlprefiles="$dlprefiles $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols="$arg"
+	  test -f "$arg" \
+	    || func_fatal_error "symbol file \`$arg' does not exist"
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	framework)
+	  case $host in
+	    *-*-darwin*)
+	      case "$deplibs " in
+		*" $qarg.ltframework "*) ;;
+		*) deplibs="$deplibs $qarg.ltframework" # this is fixed later
+		   ;;
+	      esac
+	      ;;
+	  esac
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir="$arg"
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat "$save_arg"`
+	    do
+#	      moreargs="$moreargs $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if func_lalib_unsafe_p "$arg"; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		func_source "$arg"
+
+		if test -z "$pic_object" ||
+		   test -z "$non_pic_object" ||
+		   test "$pic_object" = none &&
+		   test "$non_pic_object" = none; then
+		  func_fatal_error "cannot find name of object for \`$arg'"
+		fi
+
+		# Extract subdirectory from the argument.
+		func_dirname "$arg" "/" ""
+		xdir="$func_dirname_result"
+
+		if test "$pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object="$xdir$pic_object"
+
+		  if test "$prev" = dlfiles; then
+		    if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		      dlfiles="$dlfiles $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test "$prev" = dlprefiles; then
+		    # Preload the old-style object.
+		    dlprefiles="$dlprefiles $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  func_append libobjs " $pic_object"
+		  arg="$pic_object"
+		fi
+
+		# Non-PIC object.
+		if test "$non_pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object="$xdir$non_pic_object"
+
+		  # A standard non-PIC object
+		  func_append non_pic_objects " $non_pic_object"
+		  if test -z "$pic_object" || test "$pic_object" = none ; then
+		    arg="$non_pic_object"
+		  fi
+		else
+		  # If the PIC object exists, use it instead.
+		  # $xdir was prepended to $pic_object above.
+		  non_pic_object="$pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if $opt_dry_run; then
+		  # Extract subdirectory from the argument.
+		  func_dirname "$arg" "/" ""
+		  xdir="$func_dirname_result"
+
+		  func_lo2o "$arg"
+		  pic_object=$xdir$objdir/$func_lo2o_result
+		  non_pic_object=$xdir$func_lo2o_result
+		  func_append libobjs " $pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+	        else
+		  func_fatal_error "\`$arg' is not a valid libtool object"
+		fi
+	      fi
+	    done
+	  else
+	    func_fatal_error "link input file \`$arg' does not exist"
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release="-$arg"
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    func_fatal_error "only absolute run-paths are allowed"
+	    ;;
+	  esac
+	  if test "$prev" = rpath; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) rpath="$rpath $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) xrpath="$xrpath $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	shrext)
+	  shrext_cmds="$arg"
+	  prev=
+	  continue
+	  ;;
+	weak)
+	  weak_libs="$weak_libs $arg"
+	  prev=
+	  continue
+	  ;;
+	xcclinker)
+	  linker_flags="$linker_flags $qarg"
+	  compiler_flags="$compiler_flags $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xcompiler)
+	  compiler_flags="$compiler_flags $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  linker_flags="$linker_flags $qarg"
+	  compiler_flags="$compiler_flags $wl$qarg"
+	  prev=
+	  func_append compile_command " $wl$qarg"
+	  func_append finalize_command " $wl$qarg"
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  # See comment for -static flag below, for more details.
+	  func_append compile_command " $link_static_flag"
+	  func_append finalize_command " $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  func_fatal_error "more than one -exported-symbols argument is not allowed"
+	fi
+	if test "X$arg" = "X-export-symbols"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -framework)
+	prev=framework
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	func_stripname '-L' '' "$arg"
+	dir=$func_stripname_result
+	if test -z "$dir"; then
+	  if test "$#" -gt 0; then
+	    func_fatal_error "require no space between \`-L' and \`$1'"
+	  else
+	    func_fatal_error "need path for \`-L' option"
+	  fi
+	fi
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  test -z "$absdir" && \
+	    func_fatal_error "cannot determine absolute directory name of \`$dir'"
+	  dir="$absdir"
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "*) ;;
+	*)
+	  deplibs="$deplibs -L$dir"
+	  lib_search_path="$lib_search_path $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "X$dir" | $Xsed -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  ::) dllsearchpath=$dir;;
+	  *) dllsearchpath="$dllsearchpath:$dir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) dllsearchpath="$dllsearchpath:$testbindir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    deplibs="$deplibs System.ltframework"
+	    continue
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  esac
+	elif test "X$arg" = "X-lc_r"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	deplibs="$deplibs $arg"
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot)
+	compiler_flags="$compiler_flags $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	prev=xcompiler
+	continue
+	;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+	compiler_flags="$compiler_flags $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	case "$new_inherited_linker_flags " in
+	    *" $arg "*) ;;
+	    * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;;
+	esac
+	continue
+	;;
+
+      -multi_module)
+	single_module="${wl}-multi_module"
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # and Darwin in order for the loader to find any dlls it needs.
+	  func_warning "\`-no-install' is ignored for $host"
+	  func_warning "assuming \`-no-fast-install' instead"
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	func_stripname '-R' '' "$arg"
+	dir=$func_stripname_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  func_fatal_error "only absolute run-paths are allowed"
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) xrpath="$xrpath $dir" ;;
+	esac
+	continue
+	;;
+
+      -shared)
+	# The effects of -shared are defined in a previous loop.
+	continue
+	;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -static | -static-libtool-libs)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -weak)
+        prev=weak
+	continue
+	;;
+
+      -Wc,*)
+	func_stripname '-Wc,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  arg="$arg $wl$func_quote_for_eval_result"
+	  compiler_flags="$compiler_flags $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Wl,*)
+	func_stripname '-Wl,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  arg="$arg $wl$func_quote_for_eval_result"
+	  compiler_flags="$compiler_flags $wl$func_quote_for_eval_result"
+	  linker_flags="$linker_flags $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # -msg_* for osf cc
+      -msg_*)
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      # -64, -mips[0-9] enable 64-bit mode on the SGI compiler
+      # -r[0-9][0-9]* specifies the processor on the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler
+      # +DA*, +DD* enable 64-bit mode on the HP compiler
+      # -q* pass through compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* pass through architecture-specific
+      # compiler args for GCC
+      # -F/path gives path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC
+      # @file GCC response files
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        compiler_flags="$compiler_flags $arg"
+        continue
+        ;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      *.$objext)
+	# A standard object.
+	objs="$objs $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if func_lalib_unsafe_p "$arg"; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  func_source "$arg"
+
+	  if test -z "$pic_object" ||
+	     test -z "$non_pic_object" ||
+	     test "$pic_object" = none &&
+	     test "$non_pic_object" = none; then
+	    func_fatal_error "cannot find name of object for \`$arg'"
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  func_dirname "$arg" "/" ""
+	  xdir="$func_dirname_result"
+
+	  if test "$pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    pic_object="$xdir$pic_object"
+
+	    if test "$prev" = dlfiles; then
+	      if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		dlfiles="$dlfiles $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test "$prev" = dlprefiles; then
+	      # Preload the old-style object.
+	      dlprefiles="$dlprefiles $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    func_append libobjs " $pic_object"
+	    arg="$pic_object"
+	  fi
+
+	  # Non-PIC object.
+	  if test "$non_pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object="$xdir$non_pic_object"
+
+	    # A standard non-PIC object
+	    func_append non_pic_objects " $non_pic_object"
+	    if test -z "$pic_object" || test "$pic_object" = none ; then
+	      arg="$non_pic_object"
+	    fi
+	  else
+	    # If the PIC object exists, use it instead.
+	    # $xdir was prepended to $pic_object above.
+	    non_pic_object="$pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if $opt_dry_run; then
+	    # Extract subdirectory from the argument.
+	    func_dirname "$arg" "/" ""
+	    xdir="$func_dirname_result"
+
+	    func_lo2o "$arg"
+	    pic_object=$xdir$objdir/$func_lo2o_result
+	    non_pic_object=$xdir$func_lo2o_result
+	    func_append libobjs " $pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  else
+	    func_fatal_error "\`$arg' is not a valid libtool object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	deplibs="$deplibs $arg"
+	old_deplibs="$old_deplibs $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	if test "$prev" = dlfiles; then
+	  # This library was specified with -dlopen.
+	  dlfiles="$dlfiles $arg"
+	  prev=
+	elif test "$prev" = dlprefiles; then
+	  # The library was specified with -dlpreopen.
+	  dlprefiles="$dlprefiles $arg"
+	  prev=
+	else
+	  deplibs="$deplibs $arg"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prevarg' option requires an argument"
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname="$func_basename_result"
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    func_dirname "$output" "/" ""
+    output_objdir="$func_dirname_result$objdir"
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_duplicate_deps ; then
+	case "$libs " in
+	*" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	esac
+      fi
+      libs="$libs $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+	  esac
+	  pre_post_deps="$pre_post_deps $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+	passes="conv dlpreopen link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=no
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test "$linkmode,$pass" = "lib,link"; then
+	## FIXME: Find the place where the list is rebuilt in the wrong
+	##        order, and fix it there properly
+        tmp_deplibs=
+	for deplib in $deplibs; do
+	  tmp_deplibs="$deplib $tmp_deplibs"
+	done
+	deplibs="$tmp_deplibs"
+      fi
+
+      if test "$linkmode,$pass" = "lib,link" ||
+	 test "$linkmode,$pass" = "prog,scan"; then
+	libs="$deplibs"
+	deplibs=
+      fi
+      if test "$linkmode" = prog; then
+	case $pass in
+	dlopen) libs="$dlfiles" ;;
+	dlpreopen) libs="$dlprefiles" ;;
+	link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+	esac
+      fi
+      if test "$linkmode,$pass" = "lib,dlpreopen"; then
+	# Collect and forward deplibs of preopened libtool libs
+	for lib in $dlprefiles; do
+	  # Ignore non-libtool-libs
+	  dependency_libs=
+	  case $lib in
+	  *.la)	func_source "$lib" ;;
+	  esac
+
+	  # Collect preopened libtool deplibs, except any this library
+	  # has declared as weak libs
+	  for deplib in $dependency_libs; do
+            deplib_base=`$ECHO "X$deplib" | $Xsed -e "$basename"`
+	    case " $weak_libs " in
+	    *" $deplib_base "*) ;;
+	    *) deplibs="$deplibs $deplib" ;;
+	    esac
+	  done
+	done
+	libs="$dlprefiles"
+      fi
+      if test "$pass" = dlopen; then
+	# Collect dlpreopened libraries
+	save_deplibs="$deplibs"
+	deplibs=
+      fi
+
+      for deplib in $libs; do
+	lib=
+	found=no
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    compiler_flags="$compiler_flags $deplib"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test "$linkmode" != lib && test "$linkmode" != prog; then
+	    func_warning "\`-l' is ignored for archives/objects"
+	    continue
+	  fi
+	  func_stripname '-l' '' "$deplib"
+	  name=$func_stripname_result
+	  if test "$linkmode" = lib; then
+	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+	  else
+	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+	  fi
+	  for searchdir in $searchdirs; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib="$searchdir/lib${name}${search_ext}"
+	      if test -f "$lib"; then
+		if test "$search_ext" = ".la"; then
+		  found=yes
+		else
+		  found=no
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if test "$found" != yes; then
+	    # deplib doesn't seem to be a libtool library
+	    if test "$linkmode,$pass" = "prog,link"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  else # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if func_lalib_p "$lib"; then
+		  library_names=
+		  old_library=
+		  func_source "$lib"
+		  for l in $old_library $library_names; do
+		    ll="$l"
+		  done
+		  if test "X$ll" = "X$old_library" ; then # only static version available
+		    found=no
+		    func_dirname "$lib" "" "."
+		    ladir="$func_dirname_result"
+		    lib=$ladir/$old_library
+		    if test "$linkmode,$pass" = "prog,link"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+		;;
+	      *) ;;
+	      esac
+	    fi
+	  fi
+	  ;; # -l
+	*.ltframework)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    deplibs="$deplib $deplibs"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test "$pass" = conv && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    func_stripname '-L' '' "$deplib"
+	    newlib_search_path="$newlib_search_path $func_stripname_result"
+	    ;;
+	  prog)
+	    if test "$pass" = conv; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test "$pass" = scan; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    func_stripname '-L' '' "$deplib"
+	    newlib_search_path="$newlib_search_path $func_stripname_result"
+	    ;;
+	  *)
+	    func_warning "\`-L' is ignored for archives/objects"
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test "$pass" = link; then
+	    func_stripname '-R' '' "$deplib"
+	    dir=$func_stripname_result
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) xrpath="$xrpath $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la) lib="$deplib" ;;
+	*.$libext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    # Linking convenience modules into shared libraries is allowed,
+	    # but linking other static libraries is non-portable.
+	    case " $dlpreconveniencelibs " in
+	    *" $deplib "*) ;;
+	    *)
+	      valid_a_lib=no
+	      case $deplibs_check_method in
+		match_pattern*)
+		  set dummy $deplibs_check_method; shift
+		  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+		  if eval "\$ECHO \"X$deplib\"" 2>/dev/null | $Xsed -e 10q \
+		    | $EGREP "$match_pattern_regex" > /dev/null; then
+		    valid_a_lib=yes
+		  fi
+		;;
+		pass_all)
+		  valid_a_lib=yes
+		;;
+	      esac
+	      if test "$valid_a_lib" != yes; then
+		$ECHO
+		$ECHO "*** Warning: Trying to link with static lib archive $deplib."
+		$ECHO "*** I have the capability to make that library automatically link in when"
+		$ECHO "*** you link to this library.  But I can only do this if you have a"
+		$ECHO "*** shared version of the library, which you do not appear to have"
+		$ECHO "*** because the file extensions .$libext of this argument makes me believe"
+		$ECHO "*** that it is just a static archive that I should not use here."
+	      else
+		$ECHO
+		$ECHO "*** Warning: Linking the shared library $output against the"
+		$ECHO "*** static library $deplib is not portable!"
+		deplibs="$deplib $deplibs"
+	      fi
+	      ;;
+	    esac
+	    continue
+	    ;;
+	  prog)
+	    if test "$pass" != link; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	  elif test "$linkmode" = prog; then
+	    if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      newdlprefiles="$newdlprefiles $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      newdlfiles="$newdlfiles $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=yes
+	  continue
+	  ;;
+	esac # case $deplib
+
+	if test "$found" = yes || test -f "$lib"; then :
+	else
+	  func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+	fi
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$lib" \
+	  || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+	func_dirname "$lib" "" "."
+	ladir="$func_dirname_result"
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	inherited_linker_flags=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+	avoidtemprpath=
+
+
+	# Read the .la file
+	func_source "$lib"
+
+	# Convert "-framework foo" to "foo.ltframework"
+	if test -n "$inherited_linker_flags"; then
+	  tmp_inherited_linker_flags=`$ECHO "X$inherited_linker_flags" | $Xsed -e 's/-framework \([^ $]*\)/\1.ltframework/g'`
+	  for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+	    case " $new_inherited_linker_flags " in
+	      *" $tmp_inherited_linker_flag "*) ;;
+	      *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";;
+	    esac
+	  done
+	fi
+	dependency_libs=`$ECHO "X $dependency_libs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+	if test "$linkmode,$pass" = "lib,link" ||
+	   test "$linkmode,$pass" = "prog,scan" ||
+	   { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+	  test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+	  test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+	fi
+
+	if test "$pass" = conv; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      func_fatal_error "cannot find name of link library for \`$lib'"
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    convenience="$convenience $ladir/$objdir/$old_library"
+	    old_convenience="$old_convenience $ladir/$objdir/$old_library"
+	  elif test "$linkmode" != prog && test "$linkmode" != lib; then
+	    func_fatal_error "\`$lib' is not a convenience library"
+	  fi
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    deplibs="$deplib $deplibs"
+	    if $opt_duplicate_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	      esac
+	    fi
+	    tmp_libs="$tmp_libs $deplib"
+	  done
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	for l in $old_library $library_names; do
+	  linklib="$l"
+	done
+	if test -z "$linklib"; then
+	  func_fatal_error "cannot find name of link library for \`$lib'"
+	fi
+
+	# This library was specified with -dlopen.
+	if test "$pass" = dlopen; then
+	  if test -z "$libdir"; then
+	    func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+	  fi
+	  if test -z "$dlname" ||
+	     test "$dlopen_support" != yes ||
+	     test "$build_libtool_libs" = no; then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    dlprefiles="$dlprefiles $lib $dependency_libs"
+	  else
+	    newdlfiles="$newdlfiles $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    func_warning "cannot determine absolute directory name of \`$ladir'"
+	    func_warning "passing it literally to the linker, although it might fail"
+	    abs_ladir="$ladir"
+	  fi
+	  ;;
+	esac
+	func_basename "$lib"
+	laname="$func_basename_result"
+
+	# Find the relevant object directory and library name.
+	if test "X$installed" = Xyes; then
+	  if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    func_warning "library \`$lib' was moved."
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    libdir="$abs_ladir"
+	  else
+	    dir="$libdir"
+	    absdir="$libdir"
+	  fi
+	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+	else
+	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    # Remove this search path later
+	    notinst_path="$notinst_path $abs_ladir"
+	  else
+	    dir="$ladir/$objdir"
+	    absdir="$abs_ladir/$objdir"
+	    # Remove this search path later
+	    notinst_path="$notinst_path $abs_ladir"
+	  fi
+	fi # $installed = yes
+	func_stripname 'lib' '.la' "$laname"
+	name=$func_stripname_result
+
+	# This library was specified with -dlpreopen.
+	if test "$pass" = dlpreopen; then
+	  if test -z "$libdir" && test "$linkmode" = prog; then
+	    func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+	  fi
+	  # Prefer using a static library (so that no silly _DYNAMIC symbols
+	  # are required to link).
+	  if test -n "$old_library"; then
+	    newdlprefiles="$newdlprefiles $dir/$old_library"
+	    # Keep a list of preopened convenience libraries to check
+	    # that they are being used correctly in the link pass.
+	    test -z "$libdir" && \
+		dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library"
+	  # Otherwise, use the dlname, so that lt_dlopen finds it.
+	  elif test -n "$dlname"; then
+	    newdlprefiles="$newdlprefiles $dir/$dlname"
+	  else
+	    newdlprefiles="$newdlprefiles $dir/$linklib"
+	  fi
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test "$linkmode" = lib; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test "$linkmode" = prog && test "$pass" != link; then
+	  newlib_search_path="$newlib_search_path $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=no
+	  if test "$link_all_deplibs" != no || test -z "$library_names" ||
+	     test "$build_libtool_libs" = no; then
+	    linkalldeplibs=yes
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) func_stripname '-L' '' "$deplib"
+	         newlib_search_path="$newlib_search_path $func_stripname_result"
+		 ;;
+	    esac
+	    # Need to link against all dependency_libs?
+	    if test "$linkalldeplibs" = yes; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if $opt_duplicate_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	      esac
+	    fi
+	    tmp_libs="$tmp_libs $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test "$linkmode,$pass" = "prog,link"; then
+	  if test -n "$library_names" &&
+	     { { test "$prefer_static_libs" = no ||
+	         test "$prefer_static_libs,$installed" = "built,yes"; } ||
+	       test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+	      # Make sure the rpath contains only unique directories.
+	      case "$temp_rpath:" in
+	      *"$absdir:"*) ;;
+	      *) temp_rpath="$temp_rpath$absdir:" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) compile_rpath="$compile_rpath $absdir"
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) finalize_rpath="$finalize_rpath $libdir"
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if test "$alldeplibs" = yes &&
+	     { test "$deplibs_check_method" = pass_all ||
+	       { test "$build_libtool_libs" = yes &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	use_static_libs=$prefer_static_libs
+	if test "$use_static_libs" = built && test "$installed" = yes; then
+	  use_static_libs=no
+	fi
+	if test -n "$library_names" &&
+	   { test "$use_static_libs" = no || test -z "$old_library"; }; then
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc*)
+	      # No point in relinking DLLs because paths are not encoded
+	      notinst_deplibs="$notinst_deplibs $lib"
+	      need_relink=no
+	    ;;
+	  *)
+	    if test "$installed" = no; then
+	      notinst_deplibs="$notinst_deplibs $lib"
+	      need_relink=yes
+	    fi
+	    ;;
+	  esac
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on some
+	  # systems (darwin).  Don't bleat about dlopened modules though!
+	  dlopenmodule=""
+	  for dlpremoduletest in $dlprefiles; do
+	    if test "X$dlpremoduletest" = "X$lib"; then
+	      dlopenmodule="$dlpremoduletest"
+	      break
+	    fi
+	  done
+	  if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+	    $ECHO
+	    if test "$linkmode" = prog; then
+	      $ECHO "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $ECHO "*** $linklib is not portable!"
+	  fi
+	  if test "$linkmode" = lib &&
+	     test "$hardcode_into_libs" = yes; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) compile_rpath="$compile_rpath $absdir"
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) finalize_rpath="$finalize_rpath $libdir"
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    shift
+	    realname="$1"
+	    shift
+	    libname=`eval "\\$ECHO \"$libname_spec\""`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname="$dlname"
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw* | *cegcc*)
+	        func_arith $current - $age
+		major=$func_arith_result
+		versuffix="-$major"
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname="$realname"
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot="$soname"
+	    func_basename "$soroot"
+	    soname="$func_basename_result"
+	    func_stripname 'lib' '.dll' "$soname"
+	    newlib=libimp-$func_stripname_result.a
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      func_verbose "extracting exported symbol list from \`$soname'"
+	      func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      func_verbose "generating import library for \`$soname'"
+	      func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test "$linkmode" = prog || test "$mode" != relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test "$hardcode_direct" = no; then
+		add="$dir/$linklib"
+		case $host in
+		  *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+		  *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+		    *-*-unixware7*) add_dir="-L$dir" ;;
+		  *-*-darwin* )
+		    # if the lib is a (non-dlopened) module then we can not
+		    # link against it, someone is ignoring the earlier warnings
+		    if /usr/bin/file -L $add 2> /dev/null |
+			 $GREP ": [^:]* bundle" >/dev/null ; then
+		      if test "X$dlopenmodule" != "X$lib"; then
+			$ECHO "*** Warning: lib $linklib is a module, not a shared library"
+			if test -z "$old_library" ; then
+			  $ECHO
+			  $ECHO "*** And there doesn't seem to be a static archive available"
+			  $ECHO "*** The link will probably fail, sorry"
+			else
+			  add="$dir/$old_library"
+			fi
+		      elif test -n "$old_library"; then
+			add="$dir/$old_library"
+		      fi
+		    fi
+		esac
+	      elif test "$hardcode_minus_L" = no; then
+		case $host in
+		*-*-sunos*) add_shlibpath="$dir" ;;
+		esac
+		add_dir="-L$dir"
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = no; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test "$hardcode_direct" = yes &&
+	         test "$hardcode_direct_absolute" = no; then
+		add="$dir/$linklib"
+	      elif test "$hardcode_minus_L" = yes; then
+		add_dir="-L$dir"
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case $libdir in
+		    [\\/]*)
+		      add_dir="$add_dir -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = yes; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test "$lib_linked" != yes; then
+	      func_fatal_configuration "unsupported hardcode properties"
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test "$hardcode_direct" != yes &&
+		 test "$hardcode_minus_L" != yes &&
+		 test "$hardcode_shlibpath_var" = yes; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test "$linkmode" = prog || test "$mode" = relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test "$hardcode_direct" = yes &&
+	       test "$hardcode_direct_absolute" = no; then
+	      add="$libdir/$linklib"
+	    elif test "$hardcode_minus_L" = yes; then
+	      add_dir="-L$libdir"
+	      add="-l$name"
+	    elif test "$hardcode_shlibpath_var" = yes; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+	      esac
+	      add="-l$name"
+	    elif test "$hardcode_automatic" = yes; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib" ; then
+		add="$inst_prefix_dir$libdir/$linklib"
+	      else
+		add="$libdir/$linklib"
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir="-L$libdir"
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case $libdir in
+		  [\\/]*)
+		    add_dir="$add_dir -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add="-l$name"
+	    fi
+
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test "$linkmode" = prog; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test "$hardcode_direct" != unsupported; then
+	    test -n "$old_library" && linklib="$old_library"
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test "$build_libtool_libs" = yes; then
+	  # Not a shared library
+	  if test "$deplibs_check_method" != pass_all; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    $ECHO
+	    $ECHO "*** Warning: This system can not link to static lib archive $lib."
+	    $ECHO "*** I have the capability to make that library automatically link in when"
+	    $ECHO "*** you link to this library.  But I can only do this if you have a"
+	    $ECHO "*** shared version of the library, which you do not appear to have."
+	    if test "$module" = yes; then
+	      $ECHO "*** But as you try to build a module library, libtool will still create "
+	      $ECHO "*** a static module, that should work as long as the dlopening application"
+	      $ECHO "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		$ECHO
+		$ECHO "*** However, this would only work if libtool was able to extract symbol"
+		$ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could"
+		$ECHO "*** not find such a program.  So, this module is probably useless."
+		$ECHO "*** \`nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test "$build_old_libs" = no; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test "$linkmode" = lib; then
+	  if test -n "$dependency_libs" &&
+	     { test "$hardcode_into_libs" != yes ||
+	       test "$build_old_libs" = yes ||
+	       test "$link_static" = yes; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) func_stripname '-R' '' "$libdir"
+	           temp_xrpath=$func_stripname_result
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) xrpath="$xrpath $temp_xrpath";;
+		   esac;;
+	      *) temp_deplibs="$temp_deplibs $libdir";;
+	      esac
+	    done
+	    dependency_libs="$temp_deplibs"
+	  fi
+
+	  newlib_search_path="$newlib_search_path $absdir"
+	  # Link against this library
+	  test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    if $opt_duplicate_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+	      esac
+	    fi
+	    tmp_libs="$tmp_libs $deplib"
+	  done
+
+	  if test "$link_all_deplibs" != no; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      -L*) path="$deplib" ;;
+	      *.la)
+	        func_dirname "$deplib" "" "."
+		dir="$func_dirname_result"
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    func_warning "cannot determine absolute directory name of \`$dir'"
+		    absdir="$dir"
+		  fi
+		  ;;
+		esac
+		if $GREP "^installed=no" $deplib > /dev/null; then
+		case $host in
+		*-*-darwin*)
+		  depdepl=
+		  eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names" ; then
+		    for tmp in $deplibrary_names ; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$absdir/$objdir/$depdepl" ; then
+		      depdepl="$absdir/$objdir/$depdepl"
+		      darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`${OTOOL64} -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+		      compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+		      linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}"
+		      path=
+		    fi
+		  fi
+		  ;;
+		*)
+		  path="-L$absdir/$objdir"
+		  ;;
+		esac
+		else
+		  eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  test -z "$libdir" && \
+		    func_fatal_error "\`$deplib' is not a valid libtool archive"
+		  test "$absdir" != "$libdir" && \
+		    func_warning "\`$deplib' seems to be moved"
+
+		  path="-L$absdir"
+		fi
+		;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$path $deplibs" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      if test "$pass" = link; then
+	if test "$linkmode" = "prog"; then
+	  compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+	  finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+	else
+	  compiler_flags="$compiler_flags "`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+	fi
+      fi
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test "$pass" != dlopen; then
+	if test "$pass" != conv; then
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) lib_search_path="$lib_search_path $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	fi
+
+	if test "$linkmode,$pass" != "prog,link"; then
+	  vars="deplibs"
+	else
+	  vars="compile_deplibs finalize_deplibs"
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) tmp_libs="$tmp_libs $deplib" ;;
+	      esac
+	      ;;
+	    *) tmp_libs="$tmp_libs $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=""
+	  ;;
+	esac
+	if test -n "$i" ; then
+	  tmp_libs="$tmp_libs $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+    fi
+    if test "$linkmode" = prog || test "$linkmode" = lib; then
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+	func_warning "\`-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      objs="$objs$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+	func_stripname 'lib' '.la' "$outputname"
+	name=$func_stripname_result
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	test "$module" = no && \
+	  func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+	if test "$need_lib_prefix" != no; then
+	  # Add the "lib" prefix for modules if required
+	  func_stripname '' '.la' "$outputname"
+	  name=$func_stripname_result
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  func_stripname '' '.la' "$outputname"
+	  libname=$func_stripname_result
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test "$deplibs_check_method" != pass_all; then
+	  func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+	else
+	  $ECHO
+	  $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+	  $ECHO "*** objects $objs is not portable!"
+	  libobjs="$libobjs $objs"
+	fi
+      fi
+
+      test "$dlself" != no && \
+	func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test "$#" -gt 1 && \
+	func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+      install_libdir="$1"
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test "$build_libtool_libs" = yes; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a `.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	test -n "$vinfo" && \
+	  func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+	test -n "$release" && \
+	  func_warning "\`-release' is ignored for convenience libraries"
+      else
+
+	# Parse the version information argument.
+	save_ifs="$IFS"; IFS=':'
+	set dummy $vinfo 0 0 0
+	shift
+	IFS="$save_ifs"
+
+	test -n "$7" && \
+	  func_fatal_help "too many parameters to \`-version-info'"
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major="$1"
+	  number_minor="$2"
+	  number_revision="$3"
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # which has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  darwin|linux|osf|windows|none)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_revision"
+	    ;;
+	  freebsd-aout|freebsd-elf|sunos)
+	    current="$number_major"
+	    revision="$number_minor"
+	    age="0"
+	    ;;
+	  irix|nonstopux)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_minor"
+	    lt_irix_increment=no
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current="$1"
+	  revision="$2"
+	  age="$3"
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "CURRENT \`$current' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $revision in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "REVISION \`$revision' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $age in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "AGE \`$age' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  func_error "AGE \`$age' is greater than the current interface number \`$current'"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  # Darwin ld doesn't like 0 for these options...
+	  func_arith $current + 1
+	  minor_current=$func_arith_result
+	  xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+	  ;;
+
+	freebsd-aout)
+	  major=".$current"
+	  versuffix=".$current.$revision";
+	  ;;
+
+	freebsd-elf)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	irix | nonstopux)
+	  if test "X$lt_irix_increment" = "Xno"; then
+	    func_arith $current - $age
+	  else
+	    func_arith $current - $age + 1
+	  fi
+	  major=$func_arith_result
+
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring="$verstring_prefix$major.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test "$loop" -ne 0; do
+	    func_arith $revision - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring_prefix$major.$iface:$verstring"
+	  done
+
+	  # Before this point, $major must not contain `.'.
+	  major=.$major
+	  versuffix="$major.$revision"
+	  ;;
+
+	linux)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  ;;
+
+	osf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=".$current.$age.$revision"
+	  verstring="$current.$age.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test "$loop" -ne 0; do
+	    func_arith $current - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring:${iface}.0"
+	  done
+
+	  # Make executables depend on our current version.
+	  verstring="$verstring:${current}.0"
+	  ;;
+
+	qnx)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	sunos)
+	  major=".$current"
+	  versuffix=".$current.$revision"
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 filesystems.
+	  func_arith $current - $age
+	  major=$func_arith_result
+	  versuffix="-$major"
+	  ;;
+
+	*)
+	  func_fatal_configuration "unknown library version type \`$version_type'"
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring="0.0"
+	    ;;
+	  esac
+	  if test "$need_version" = no; then
+	    versuffix=
+	  else
+	    versuffix=".0.0"
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test "$avoid_version" = yes && test "$need_version" = no; then
+	  major=
+	  versuffix=
+	  verstring=""
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test "$allow_undefined" = yes; then
+	  if test "$allow_undefined_flag" = unsupported; then
+	    func_warning "undefined symbols not allowed in $host shared libraries"
+	    build_libtool_libs=no
+	    build_old_libs=yes
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag="$no_undefined_flag"
+	fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" "yes"
+      libobjs="$libobjs $symfileobj"
+      test "X$libobjs" = "X " && libobjs=
+
+      if test "$mode" != relink; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$ECHO "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext | *.gcno)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+	       if test "X$precious_files_regex" != "X"; then
+		 if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+		 then
+		   continue
+		 fi
+	       fi
+	       removelist="$removelist $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	test -n "$removelist" && \
+	  func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+	oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #	lib_search_path=`$ECHO "X$lib_search_path " | $Xsed -e "s% $path % %g"`
+      #	deplibs=`$ECHO "X$deplibs " | $Xsed -e "s% -L$path % %g"`
+      #	dependency_libs=`$ECHO "X$dependency_libs " | $Xsed -e "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  temp_xrpath="$temp_xrpath -R$libdir"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_rpath="$finalize_rpath $libdir" ;;
+	  esac
+	done
+	if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) dlfiles="$dlfiles $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) dlprefiles="$dlprefiles $lib" ;;
+	esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    deplibs="$deplibs System.ltframework"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    ;;
+	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test "$build_libtool_need_lc" = "yes"; then
+	      deplibs="$deplibs -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=""
+	versuffix=""
+	major=""
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $opt_dry_run || $RM conftest.c
+	  cat > conftest.c <<EOF
+	  int main() { return 0; }
+EOF
+	  $opt_dry_run || $RM conftest
+	  if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+	    ldd_output=`ldd conftest`
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		  case " $predeps $postdeps " in
+		  *" $i "*)
+		    newdeplibs="$newdeplibs $i"
+		    i=""
+		    ;;
+		  esac
+		fi
+		if test -n "$i" ; then
+		  libname=`eval "\\$ECHO \"$libname_spec\""`
+		  deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		  set dummy $deplib_matches; shift
+		  deplib_match=$1
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		    newdeplibs="$newdeplibs $i"
+		  else
+		    droppeddeps=yes
+		    $ECHO
+		    $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		    $ECHO "*** I have the capability to make that library automatically link in when"
+		    $ECHO "*** you link to this library.  But I can only do this if you have a"
+		    $ECHO "*** shared version of the library, which I believe you do not have"
+		    $ECHO "*** because a test_compile did reveal that the linker did not use it for"
+		    $ECHO "*** its dynamic dependency list that programs get resolved with at runtime."
+		  fi
+		fi
+		;;
+	      *)
+		newdeplibs="$newdeplibs $i"
+		;;
+	      esac
+	    done
+	  else
+	    # Error occurred in the first compile.  Let's try to salvage
+	    # the situation: Compile a separate program for each library.
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		$opt_dry_run || $RM conftest
+		if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+		  ldd_output=`ldd conftest`
+		  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		    case " $predeps $postdeps " in
+		    *" $i "*)
+		      newdeplibs="$newdeplibs $i"
+		      i=""
+		      ;;
+		    esac
+		  fi
+		  if test -n "$i" ; then
+		    libname=`eval "\\$ECHO \"$libname_spec\""`
+		    deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		    set dummy $deplib_matches; shift
+		    deplib_match=$1
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		      newdeplibs="$newdeplibs $i"
+		    else
+		      droppeddeps=yes
+		      $ECHO
+		      $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		      $ECHO "*** I have the capability to make that library automatically link in when"
+		      $ECHO "*** you link to this library.  But I can only do this if you have a"
+		      $ECHO "*** shared version of the library, which you do not appear to have"
+		      $ECHO "*** because a test_compile did reveal that the linker did not use this one"
+		      $ECHO "*** as a dynamic dependency that programs can get resolved with at runtime."
+		    fi
+		  fi
+		else
+		  droppeddeps=yes
+		  $ECHO
+		  $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+		  $ECHO "*** make it link in!  You will probably need to install it or some"
+		  $ECHO "*** library that it depends on before this library will be fully"
+		  $ECHO "*** functional.  Installing it before continuing would be even better."
+		fi
+		;;
+	      *)
+		newdeplibs="$newdeplibs $i"
+		;;
+	      esac
+	    done
+	  fi
+	  ;;
+	file_magic*)
+	  set dummy $deplibs_check_method; shift
+	  file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  newdeplibs="$newdeplibs $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null |
+			 $GREP " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib="$potent_lib"
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+			*) potlib=`$ECHO "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+			 $SED -e 10q |
+			 $EGREP "$file_magic_regex" > /dev/null; then
+			newdeplibs="$newdeplibs $a_deplib"
+			a_deplib=""
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		$ECHO
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		$ECHO "*** I have the capability to make that library automatically link in when"
+		$ECHO "*** you link to this library.  But I can only do this if you have a"
+		$ECHO "*** shared version of the library, which you do not appear to have"
+		$ECHO "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      newdeplibs="$newdeplibs $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method; shift
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  newdeplibs="$newdeplibs $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib="$potent_lib" # see symlink-check above in file_magic test
+		    if eval "\$ECHO \"X$potent_lib\"" 2>/dev/null | $Xsed -e 10q | \
+		       $EGREP "$match_pattern_regex" > /dev/null; then
+		      newdeplibs="$newdeplibs $a_deplib"
+		      a_deplib=""
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		$ECHO
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		$ECHO "*** I have the capability to make that library automatically link in when"
+		$ECHO "*** you link to this library.  But I can only do this if you have a"
+		$ECHO "*** shared version of the library, which you do not appear to have"
+		$ECHO "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      newdeplibs="$newdeplibs $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=""
+	  tmp_deplibs=`$ECHO "X $deplibs" | $Xsed \
+	      -e 's/ -lc$//' -e 's/ -[LR][^ ]*//g'`
+	  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	    for i in $predeps $postdeps ; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$ECHO "X $tmp_deplibs" | $Xsed -e "s,$i,,"`
+	    done
+	  fi
+	  if $ECHO "X $tmp_deplibs" | $Xsed -e 's/[	 ]//g' |
+	     $GREP . >/dev/null; then
+	    $ECHO
+	    if test "X$deplibs_check_method" = "Xnone"; then
+	      $ECHO "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      $ECHO "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    $ECHO "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	  fi
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library with the System framework
+	  newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
+	  ;;
+	esac
+
+	if test "$droppeddeps" = yes; then
+	  if test "$module" = yes; then
+	    $ECHO
+	    $ECHO "*** Warning: libtool could not satisfy all declared inter-library"
+	    $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+	    $ECHO "*** a static module, that should work as long as the dlopening"
+	    $ECHO "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      $ECHO
+	      $ECHO "*** However, this would only work if libtool was able to extract symbol"
+	      $ECHO "*** lists from a program, using \`nm' or equivalent, but libtool could"
+	      $ECHO "*** not find such a program.  So, this module is probably useless."
+	      $ECHO "*** \`nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test "$build_old_libs" = no; then
+	      oldlibs="$output_objdir/$libname.$libext"
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    $ECHO "*** The inter-library dependencies that have been dropped here will be"
+	    $ECHO "*** automatically added whenever a program is linked with this library"
+	    $ECHO "*** or is declared to -dlopen it."
+
+	    if test "$allow_undefined" = no; then
+	      $ECHO
+	      $ECHO "*** Since this library must not contain undefined symbols,"
+	      $ECHO "*** because either the platform does not support them or"
+	      $ECHO "*** it was explicitly requested with -no-undefined,"
+	      $ECHO "*** libtool will only create a static version of it."
+	      if test "$build_old_libs" = no; then
+		oldlibs="$output_objdir/$libname.$libext"
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+	*-*-darwin*)
+	  newdeplibs=`$ECHO "X $newdeplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  new_inherited_linker_flags=`$ECHO "X $new_inherited_linker_flags" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  deplibs=`$ECHO "X $deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $deplibs " in
+	  *" -L$path/$objdir "*)
+	    new_libs="$new_libs -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) new_libs="$new_libs $deplib" ;;
+	  esac
+	  ;;
+	*) new_libs="$new_libs $deplib" ;;
+	esac
+      done
+      deplibs="$new_libs"
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+	if test "$hardcode_into_libs" = yes; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath="$finalize_rpath"
+	  test "$mode" != relink && rpath="$compile_rpath$rpath"
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs="$libdir"
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		dep_rpath="$dep_rpath $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) perm_rpath="$perm_rpath $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir="$hardcode_libdirs"
+	    if test -n "$hardcode_libdir_flag_spec_ld"; then
+	      eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
+	    else
+	      eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+	    fi
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      rpath="$rpath$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath="$finalize_shlibpath"
+	test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	shift
+	realname="$1"
+	shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname="$realname"
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib="$output_objdir/$realname"
+	linknames=
+	for link
+	do
+	  linknames="$linknames $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$ECHO "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+	test "X$libobjs" = "X " && libobjs=
+
+	delfiles=
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+	  export_symbols="$output_objdir/$libname.uexp"
+	  delfiles="$delfiles $export_symbols"
+	fi
+
+	orig_export_symbols=
+	case $host_os in
+	cygwin* | mingw* | cegcc*)
+	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+	    # exporting using user supplied symfile
+	    if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+	      # and it's NOT already a .def file. Must figure out
+	      # which of the given symbols are data symbols and tag
+	      # them as such. So, trigger use of export_symbols_cmds.
+	      # export_symbols gets reassigned inside the "prepare
+	      # the list of exported symbols" if statement, so the
+	      # include_expsyms logic still works.
+	      orig_export_symbols="$export_symbols"
+	      export_symbols=
+	      always_export_symbols=yes
+	    fi
+	  fi
+	  ;;
+	esac
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+	    func_verbose "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $opt_dry_run || $RM $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $cmds; do
+	      IFS="$save_ifs"
+	      eval cmd=\"$cmd\"
+	      func_len " $cmd"
+	      len=$func_len_result
+	      if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+		func_show_eval "$cmd" 'exit $?'
+		skipped_export=false
+	      else
+		# The command line is too long to execute in one step.
+		func_verbose "using reloadable object file for export list..."
+		skipped_export=:
+		# Break out early, otherwise skipped_export may be
+		# set to false by a later but shorter cmd.
+		break
+	      fi
+	    done
+	    IFS="$save_ifs"
+	    if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  tmp_export_symbols="$export_symbols"
+	  test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	  $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"'
+	fi
+
+	if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+	  # The given exports_symbols file has to be filtered, so filter it.
+	  func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	  # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	  # 's' commands which not all seds can handle. GNU sed should be fine
+	  # though. Also, the filter scales superlinearly with the number of
+	  # global variables. join(1) would be nice here, but unfortunately
+	  # isn't a blessed tool.
+	  $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	  delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
+	  export_symbols=$output_objdir/$libname.def
+	  $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+	  case " $convenience " in
+	  *" $test_deplib "*) ;;
+	  *)
+	    tmp_deplibs="$tmp_deplibs $test_deplib"
+	    ;;
+	  esac
+	done
+	deplibs="$tmp_deplibs"
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec" &&
+	    test "$compiler_needs_object" = yes &&
+	    test -z "$libobjs"; then
+	    # extract the archives, so we have objects to list.
+	    # TODO: could optimize this to just extract one archive.
+	    whole_archive_flag_spec=
+	  fi
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  else
+	    gentop="$output_objdir/${outputname}x"
+	    generated="$generated $gentop"
+
+	    func_extract_archives $gentop $convenience
+	    libobjs="$libobjs $func_extract_archives_result"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	fi
+
+	if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  linker_flags="$linker_flags $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test "$mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test "$module" = yes && test -n "$module_cmds" ; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    eval test_cmds=\"$archive_expsym_cmds\"
+	    cmds=$archive_expsym_cmds
+	  else
+	    eval test_cmds=\"$archive_cmds\"
+	    cmds=$archive_cmds
+	  fi
+	fi
+
+	if test "X$skipped_export" != "X:" &&
+	   func_len " $test_cmds" &&
+	   len=$func_len_result &&
+	   test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise
+	  # or, if using GNU ld and skipped_export is not :, use a linker
+	  # script.
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+	  output_la=`$ECHO "X$output" | $Xsed -e "$basename"`
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  last_robj=
+	  k=1
+
+	  if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+	    output=${output_objdir}/${output_la}.lnkscript
+	    func_verbose "creating GNU ld script: $output"
+	    $ECHO 'INPUT (' > $output
+	    for obj in $save_libobjs
+	    do
+	      $ECHO "$obj" >> $output
+	    done
+	    $ECHO ')' >> $output
+	    delfiles="$delfiles $output"
+	  elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+	    output=${output_objdir}/${output_la}.lnk
+	    func_verbose "creating linker input file list: $output"
+	    : > $output
+	    set x $save_libobjs
+	    shift
+	    firstobj=
+	    if test "$compiler_needs_object" = yes; then
+	      firstobj="$1 "
+	      shift
+	    fi
+	    for obj
+	    do
+	      $ECHO "$obj" >> $output
+	    done
+	    delfiles="$delfiles $output"
+	    output=$firstobj\"$file_list_spec$output\"
+	  else
+	    if test -n "$save_libobjs"; then
+	      func_verbose "creating reloadable object files..."
+	      output=$output_objdir/$output_la-${k}.$objext
+	      eval test_cmds=\"$reload_cmds\"
+	      func_len " $test_cmds"
+	      len0=$func_len_result
+	      len=$len0
+
+	      # Loop over the list of objects to be linked.
+	      for obj in $save_libobjs
+	      do
+		func_len " $obj"
+		func_arith $len + $func_len_result
+		len=$func_arith_result
+		if test "X$objlist" = X ||
+		   test "$len" -lt "$max_cmd_len"; then
+		  func_append objlist " $obj"
+		else
+		  # The command $test_cmds is almost too long, add a
+		  # command to the queue.
+		  if test "$k" -eq 1 ; then
+		    # The first file doesn't have a previous command to add.
+		    eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+		  else
+		    # All subsequent reloadable object files will link in
+		    # the last one created.
+		    eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj~\$RM $last_robj\"
+		  fi
+		  last_robj=$output_objdir/$output_la-${k}.$objext
+		  func_arith $k + 1
+		  k=$func_arith_result
+		  output=$output_objdir/$output_la-${k}.$objext
+		  objlist=$obj
+		  func_len " $last_robj"
+		  func_arith $len0 + $func_len_result
+		  len=$func_arith_result
+		fi
+	      done
+	      # Handle the remaining objects by creating one last
+	      # reloadable object file.  All subsequent reloadable object
+	      # files will link in the last one created.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+	      if test -n "$last_robj"; then
+	        eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+	      fi
+	      delfiles="$delfiles $output"
+
+	    else
+	      output=
+	    fi
+
+	    if ${skipped_export-false}; then
+	      func_verbose "generating symbol list for \`$libname.la'"
+	      export_symbols="$output_objdir/$libname.exp"
+	      $opt_dry_run || $RM $export_symbols
+	      libobjs=$output
+	      # Append the command to create the export file.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+	      if test -n "$last_robj"; then
+		eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	    fi
+
+	    test -n "$save_libobjs" &&
+	      func_verbose "creating a temporary reloadable object file: $output"
+
+	    # Loop through the commands generated above and execute them.
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $concat_cmds; do
+	      IFS="$save_ifs"
+	      $opt_silent || {
+		  func_quote_for_expand "$cmd"
+		  eval "func_echo $func_quote_for_expand_result"
+	      }
+	      $opt_dry_run || eval "$cmd" || {
+		lt_exit=$?
+
+		# Restore the uninstalled library and exit
+		if test "$mode" = relink; then
+		  ( cd "$output_objdir" && \
+		    $RM "${realname}T" && \
+		    $MV "${realname}U" "$realname" )
+		fi
+
+		exit $lt_exit
+	      }
+	    done
+	    IFS="$save_ifs"
+
+	    if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+
+          if ${skipped_export-false}; then
+	    if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	      tmp_export_symbols="$export_symbols"
+	      test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	      $opt_dry_run || eval '$ECHO "X$include_expsyms" | $Xsed | $SP2NL >> "$tmp_export_symbols"'
+	    fi
+
+	    if test -n "$orig_export_symbols"; then
+	      # The given exports_symbols file has to be filtered, so filter it.
+	      func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	      # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	      # 's' commands which not all seds can handle. GNU sed should be fine
+	      # though. Also, the filter scales superlinearly with the number of
+	      # global variables. join(1) would be nice here, but unfortunately
+	      # isn't a blessed tool.
+	      $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	      delfiles="$delfiles $export_symbols $output_objdir/$libname.filter"
+	      export_symbols=$output_objdir/$libname.def
+	      $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	    fi
+	  fi
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test "$module" = yes && test -n "$module_cmds" ; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	    if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	      cmds=$archive_expsym_cmds
+	    else
+	      cmds=$archive_cmds
+	    fi
+	  fi
+	fi
+
+	if test -n "$delfiles"; then
+	  # Append the command to remove temporary files to $cmds.
+	  eval cmds=\"\$cmds~\$RM $delfiles\"
+	fi
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  generated="$generated $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  libobjs="$libobjs $func_extract_archives_result"
+	  test "X$libobjs" = "X " && libobjs=
+	fi
+
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $opt_silent || {
+	    func_quote_for_expand "$cmd"
+	    eval "func_echo $func_quote_for_expand_result"
+	  }
+	  $opt_dry_run || eval "$cmd" || {
+	    lt_exit=$?
+
+	    # Restore the uninstalled library and exit
+	    if test "$mode" = relink; then
+	      ( cd "$output_objdir" && \
+	        $RM "${realname}T" && \
+		$MV "${realname}U" "$realname" )
+	    fi
+
+	    exit $lt_exit
+	  }
+	done
+	IFS="$save_ifs"
+
+	# Restore the uninstalled library and exit
+	if test "$mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+	  if test -n "$convenience"; then
+	    if test -z "$whole_archive_flag_spec"; then
+	      func_show_eval '${RM}r "$gentop"'
+	    fi
+	  fi
+
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test "$module" = yes || test "$export_dynamic" = yes; then
+	  # On all known operating systems, these are identical.
+	  dlname="$soname"
+	fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for objects"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+	test -n "$objs$old_deplibs" && \
+	  func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+	libobj=$output
+	func_lo2o "$libobj"
+	obj=$func_lo2o_result
+	;;
+      *)
+	libobj=
+	obj="$output"
+	;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec and hope we can get by with
+      # turning comma into space..
+      wl=
+
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+	  reload_conv_objs=$reload_objs\ `$ECHO "X$tmp_whole_archive_flags" | $Xsed -e 's|,| |g'`
+	else
+	  gentop="$output_objdir/${obj}x"
+	  generated="$generated $gentop"
+
+	  func_extract_archives $gentop $convenience
+	  reload_conv_objs="$reload_objs $func_extract_archives_result"
+	fi
+      fi
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$ECHO "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output="$libobj"
+	func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+	func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) func_stripname '' '.exe' "$output"
+	          output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for programs"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for programs"
+
+      test "$preload" = yes \
+        && test "$dlopen_support" = unknown \
+	&& test "$dlopen_self" = unknown \
+	&& test "$dlopen_self_static" = unknown && \
+	  func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
+	finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's/ -lc / System.ltframework /'`
+	;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+	# Don't allow lazy linking, it breaks C++ global constructors
+	# But is supposedly fixed on 10.4 or later (yay!).
+	if test "$tagname" = CXX ; then
+	  case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+	    10.[0123])
+	      compile_command="$compile_command ${wl}-bind_at_load"
+	      finalize_command="$finalize_command ${wl}-bind_at_load"
+	    ;;
+	  esac
+	fi
+	# Time to change all our "foo.ltframework" stuff back to "-framework foo"
+	compile_deplibs=`$ECHO "X $compile_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+	finalize_deplibs=`$ECHO "X $finalize_deplibs" | $Xsed -e 's% \([^ $]*\).ltframework% -framework \1%g'`
+	;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $compile_deplibs " in
+	  *" -L$path/$objdir "*)
+	    new_libs="$new_libs -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $compile_deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) new_libs="$new_libs $deplib" ;;
+	  esac
+	  ;;
+	*) new_libs="$new_libs $deplib" ;;
+	esac
+      done
+      compile_deplibs="$new_libs"
+
+
+      compile_command="$compile_command $compile_deplibs"
+      finalize_command="$finalize_command $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_rpath="$finalize_rpath $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    rpath="$rpath $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) perm_rpath="$perm_rpath $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  ::) dllsearchpath=$libdir;;
+	  *) dllsearchpath="$dllsearchpath:$libdir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) dllsearchpath="$dllsearchpath:$testbindir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    rpath="$rpath $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$ECHO "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+	finalize_command=`$ECHO "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+	func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=yes
+      case $host in
+      *cygwin* | *mingw* )
+        if test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      *cegcc)
+        # Disable wrappers for cegcc, we are cross compiling anyway.
+        wrappers_required=no
+        ;;
+      *)
+        if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      esac
+      if test "$wrappers_required" = no; then
+	# Replace the output file specification.
+	compile_command=`$ECHO "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+	link_command="$compile_command$compile_rpath"
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	exit_status=0
+	func_show_eval "$link_command" 'exit_status=$?'
+
+	# Delete the generated files.
+	if test -f "$output_objdir/${outputname}S.${objext}"; then
+	  func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+	fi
+
+	exit $exit_status
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    rpath="$rpath$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    rpath="$rpath$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test "$no_install" = yes; then
+	# We don't need to create a wrapper script.
+	link_command="$compile_var$compile_command$compile_rpath"
+	# Replace the output file specification.
+	link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$opt_dry_run || $RM $output
+	# Link the executable and exit
+	func_show_eval "$link_command" 'exit $?'
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+	# Fast installation is not supported
+	link_command="$compile_var$compile_command$compile_rpath"
+	relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+	func_warning "this platform does not like uninstalled shared libraries"
+	func_warning "\`$output' will be relinked during installation"
+      else
+	if test "$fast_install" != no; then
+	  link_command="$finalize_var$compile_command$finalize_rpath"
+	  if test "$fast_install" = yes; then
+	    relink_command=`$ECHO "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+	  else
+	    # fast_install is set to needless
+	    relink_command=
+	  fi
+	else
+	  link_command="$compile_var$compile_command$compile_rpath"
+	  relink_command="$finalize_var$finalize_command$finalize_rpath"
+	fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$ECHO "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    func_quote_for_eval "$var_value"
+	    relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+      fi
+
+      # Quote $ECHO for shipping.
+      if test "X$ECHO" = "X$SHELL $progpath --fallback-echo"; then
+	case $progpath in
+	[\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $progpath --fallback-echo";;
+	*) qecho="$SHELL `pwd`/$progpath --fallback-echo";;
+	esac
+	qecho=`$ECHO "X$qecho" | $Xsed -e "$sed_quote_subst"`
+      else
+	qecho=`$ECHO "X$ECHO" | $Xsed -e "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) func_stripname '' '.exe' "$output"
+	         output=$func_stripname_result ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    func_stripname '' '.exe' "$outputname"
+	    outputname=$func_stripname_result ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+	    func_dirname_and_basename "$output" "" "."
+	    output_name=$func_basename_result
+	    output_path=$func_dirname_result
+	    cwrappersource="$output_path/$objdir/lt-$output_name.c"
+	    cwrapper="$output_path/$output_name.exe"
+	    $RM $cwrappersource $cwrapper
+	    trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_cwrapperexe_src > $cwrappersource
+
+	    # The wrapper executable is built using the $host compiler,
+	    # because it contains $host paths and files. If cross-
+	    # compiling, it, like the target executable, must be
+	    # executed on the $host or under an emulation environment.
+	    $opt_dry_run || {
+	      $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+	      $STRIP $cwrapper
+	    }
+
+	    # Now, create the wrapper script for func_source use:
+	    func_ltwrapper_scriptname $cwrapper
+	    $RM $func_ltwrapper_scriptname_result
+	    trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+	    $opt_dry_run || {
+	      # note: this script will not be executed, so do not chmod.
+	      if test "x$build" = "x$host" ; then
+		$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+	      else
+		func_emit_wrapper no > $func_ltwrapper_scriptname_result
+	      fi
+	    }
+	  ;;
+	  * )
+	    $RM $output
+	    trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_wrapper no > $output
+	    chmod +x $output
+	  ;;
+	esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+	oldobjs="$libobjs_save $symfileobj"
+	addlibs="$convenience"
+	build_libtool_libs=no
+      else
+	if test "$build_libtool_libs" = module; then
+	  oldobjs="$libobjs_save"
+	  build_libtool_libs=no
+	else
+	  oldobjs="$old_deplibs $non_pic_objects"
+	  if test "$preload" = yes && test -f "$symfileobj"; then
+	    oldobjs="$oldobjs $symfileobj"
+	  fi
+	fi
+	addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+	gentop="$output_objdir/${outputname}x"
+	generated="$generated $gentop"
+
+	func_extract_archives $gentop $addlibs
+	oldobjs="$oldobjs $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+	cmds=$old_archive_from_new_cmds
+      else
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  generated="$generated $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  oldobjs="$oldobjs $func_extract_archives_result"
+	fi
+
+	# POSIX demands no paths to be encoded in archives.  We have
+	# to avoid creating archives with duplicate basenames if we
+	# might have to extract them afterwards, e.g., when creating a
+	# static archive out of a convenience library, or when linking
+	# the entirety of a libtool archive into another (currently
+	# not supported by libtool).
+	if (for obj in $oldobjs
+	    do
+	      func_basename "$obj"
+	      $ECHO "$func_basename_result"
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	  :
+	else
+	  $ECHO "copying selected object files to avoid basename conflicts..."
+	  gentop="$output_objdir/${outputname}x"
+	  generated="$generated $gentop"
+	  func_mkdir_p "$gentop"
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  counter=1
+	  for obj in $save_oldobjs
+	  do
+	    func_basename "$obj"
+	    objbase="$func_basename_result"
+	    case " $oldobjs " in
+	    " ") oldobjs=$obj ;;
+	    *[\ /]"$objbase "*)
+	      while :; do
+		# Make sure we don't pick an alternate name that also
+		# overlaps.
+		newobj=lt$counter-$objbase
+		func_arith $counter + 1
+		counter=$func_arith_result
+		case " $oldobjs " in
+		*[\ /]"$newobj "*) ;;
+		*) if test ! -f "$gentop/$newobj"; then break; fi ;;
+		esac
+	      done
+	      func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+	      oldobjs="$oldobjs $gentop/$newobj"
+	      ;;
+	    *) oldobjs="$oldobjs $obj" ;;
+	    esac
+	  done
+	fi
+	eval cmds=\"$old_archive_cmds\"
+
+	func_len " $cmds"
+	len=$func_len_result
+	if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  func_verbose "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  eval test_cmds=\"$old_archive_cmds\"
+	  func_len " $test_cmds"
+	  len0=$func_len_result
+	  len=$len0
+	  for obj in $save_oldobjs
+	  do
+	    func_len " $obj"
+	    func_arith $len + $func_len_result
+	    len=$func_arith_result
+	    func_append objlist " $obj"
+	    if test "$len" -lt "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj" ; then
+		RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+	      objlist=
+	      len=$len0
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test "X$oldobjs" = "X" ; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  func_quote_for_eval "$var_value"
+	  relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+      if test "$hardcode_automatic" = yes ; then
+	relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+	for installed in no yes; do
+	  if test "$installed" = yes; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output="$output_objdir/$outputname"i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		func_basename "$deplib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$deplib' is not a valid libtool archive"
+		newdependency_libs="$newdependency_libs $libdir/$name"
+		;;
+	      *) newdependency_libs="$newdependency_libs $deplib" ;;
+	      esac
+	    done
+	    dependency_libs="$newdependency_libs"
+	    newdlfiles=
+
+	    for lib in $dlfiles; do
+	      case $lib in
+	      *.la)
+	        func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		newdlfiles="$newdlfiles $libdir/$name"
+		;;
+	      *) newdlfiles="$newdlfiles $lib" ;;
+	      esac
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+	      *.la)
+		# Only pass preopened files to the pseudo-archive (for
+		# eventual linking with the app. that links it) if we
+		# didn't already link the preopened objects directly into
+		# the library:
+		func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		newdlprefiles="$newdlprefiles $libdir/$name"
+		;;
+	      esac
+	    done
+	    dlprefiles="$newdlprefiles"
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      newdlfiles="$newdlfiles $abs"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      newdlprefiles="$newdlprefiles $abs"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  fi
+	  $RM $output
+	  # place dlname in correct position for cygwin
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+	  esac
+	  $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test "$installed" = no && test "$need_relink" = yes; then
+	    $ECHO >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+{ test "$mode" = link || test "$mode" = relink; } &&
+    func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $opt_debug
+    RM="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) RM="$RM $arg"; rmforce=yes ;;
+      -*) RM="$RM $arg" ;;
+      *) files="$files $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    origobjdir="$objdir"
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir="$func_dirname_result"
+      if test "X$dir" = X.; then
+	objdir="$origobjdir"
+      else
+	objdir="$dir/$origobjdir"
+      fi
+      func_basename "$file"
+      name="$func_basename_result"
+      test "$mode" = uninstall && objdir="$dir"
+
+      # Remember objdir for removal later, being careful to avoid duplicates
+      if test "$mode" = clean; then
+	case " $rmdirs " in
+	  *" $objdir "*) ;;
+	  *) rmdirs="$rmdirs $objdir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+	 { test -h "$file"; } >/dev/null 2>&1 ||
+	 test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif test "$rmforce" = yes; then
+	continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if func_lalib_p "$file"; then
+	  func_source $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    rmfiles="$rmfiles $objdir/$n"
+	  done
+	  test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+
+	  case "$mode" in
+	  clean)
+	    case "  $library_names " in
+	    # "  " in the beginning catches empty $dlname
+	    *" $dlname "*) ;;
+	    *) rmfiles="$rmfiles $objdir/$dlname" ;;
+	    esac
+	    test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+	    ;;
+	  uninstall)
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	    ;;
+	  esac
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if func_lalib_p "$file"; then
+
+	  # Read the .lo file
+	  func_source $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" &&
+	     test "$pic_object" != none; then
+	    rmfiles="$rmfiles $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" &&
+	     test "$non_pic_object" != none; then
+	    rmfiles="$rmfiles $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test "$mode" = clean ; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    func_stripname '' '.exe' "$file"
+	    file=$func_stripname_result
+	    func_stripname '' '.exe' "$name"
+	    noexename=$func_stripname_result
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    rmfiles="$rmfiles $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if func_ltwrapper_p "$file"; then
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      relink_command=
+	      func_source $func_ltwrapper_scriptname_result
+	      rmfiles="$rmfiles $func_ltwrapper_scriptname_result"
+	    else
+	      relink_command=
+	      func_source $dir/$noexename
+	    fi
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+	    if test "$fast_install" = yes && test -n "$relink_command"; then
+	      rmfiles="$rmfiles $objdir/lt-$name"
+	    fi
+	    if test "X$noexename" != "X$name" ; then
+	      rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+    objdir="$origobjdir"
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+{ test "$mode" = uninstall || test "$mode" = clean; } &&
+    func_mode_uninstall ${1+"$@"}
+
+test -z "$mode" && {
+  help="$generic_help"
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode \`$mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
diff --git a/missing b/missing
new file mode 100755
index 0000000..28055d2
--- /dev/null
+++ b/missing
@@ -0,0 +1,376 @@
+#! /bin/sh
+# Common stub for a few missing GNU programs while installing.
+
+scriptversion=2009-04-28.21; # UTC
+
+# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006,
+# 2008, 2009 Free Software Foundation, Inc.
+# Originally by Fran,cois Pinard <pinard at iro.umontreal.ca>, 1996.
+
+# 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, 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, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try \`$0 --help' for more information"
+  exit 1
+fi
+
+run=:
+sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
+sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
+
+# In the cases where this matters, `missing' is being run in the
+# srcdir already.
+if test -f configure.ac; then
+  configure_ac=configure.ac
+else
+  configure_ac=configure.in
+fi
+
+msg="missing on your system"
+
+case $1 in
+--run)
+  # Try to run requested program, and just exit if it succeeds.
+  run=
+  shift
+  "$@" && exit 0
+  # Exit code 63 means version mismatch.  This often happens
+  # when the user try to use an ancient version of a tool on
+  # a file that requires a minimum version.  In this case we
+  # we should proceed has if the program had been absent, or
+  # if --run hadn't been passed.
+  if test $? = 63; then
+    run=:
+    msg="probably too old"
+  fi
+  ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
+error status if there is no known handling for PROGRAM.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+  --run           try to run the given command, and emulate it if it fails
+
+Supported PROGRAM values:
+  aclocal      touch file \`aclocal.m4'
+  autoconf     touch file \`configure'
+  autoheader   touch file \`config.h.in'
+  autom4te     touch the output file, or create a stub one
+  automake     touch all \`Makefile.in' files
+  bison        create \`y.tab.[ch]', if possible, from existing .[ch]
+  flex         create \`lex.yy.c', if possible, from existing .c
+  help2man     touch the output file
+  lex          create \`lex.yy.c', if possible, from existing .c
+  makeinfo     touch the output file
+  tar          try tar, gnutar, gtar, then tar without non-portable flags
+  yacc         create \`y.tab.[ch]', if possible, from existing .[ch]
+
+Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and
+\`g' are ignored when checking the name.
+
+Send bug reports to <bug-automake at gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: Unknown \`$1' option"
+    echo 1>&2 "Try \`$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# normalize program name to check for.
+program=`echo "$1" | sed '
+  s/^gnu-//; t
+  s/^gnu//; t
+  s/^g//; t'`
+
+# Now exit if we have it, but it failed.  Also exit now if we
+# don't have it and --version was passed (most likely to detect
+# the program).  This is about non-GNU programs, so use $1 not
+# $program.
+case $1 in
+  lex*|yacc*)
+    # Not GNU programs, they don't have --version.
+    ;;
+
+  tar*)
+    if test -n "$run"; then
+       echo 1>&2 "ERROR: \`tar' requires --run"
+       exit 1
+    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+       exit 1
+    fi
+    ;;
+
+  *)
+    if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
+       # We have it, but it failed.
+       exit 1
+    elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
+       # Could not run --version or --help.  This is probably someone
+       # running `$TOOL --version' or `$TOOL --help' to check whether
+       # $TOOL exists and not knowing $TOOL uses missing.
+       exit 1
+    fi
+    ;;
+esac
+
+# If it does not exist, or fails to run (possibly an outdated version),
+# try to emulate it.
+case $program in
+  aclocal*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acinclude.m4' or \`${configure_ac}'.  You might want
+         to install the \`Automake' and \`Perl' packages.  Grab them from
+         any GNU archive site."
+    touch aclocal.m4
+    ;;
+
+  autoconf*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`${configure_ac}'.  You might want to install the
+         \`Autoconf' and \`GNU m4' packages.  Grab them from any GNU
+         archive site."
+    touch configure
+    ;;
+
+  autoheader*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`acconfig.h' or \`${configure_ac}'.  You might want
+         to install the \`Autoconf' and \`GNU m4' packages.  Grab them
+         from any GNU archive site."
+    files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
+    test -z "$files" && files="config.h"
+    touch_files=
+    for f in $files; do
+      case $f in
+      *:*) touch_files="$touch_files "`echo "$f" |
+				       sed -e 's/^[^:]*://' -e 's/:.*//'`;;
+      *) touch_files="$touch_files $f.in";;
+      esac
+    done
+    touch $touch_files
+    ;;
+
+  automake*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
+         You might want to install the \`Automake' and \`Perl' packages.
+         Grab them from any GNU archive site."
+    find . -type f -name Makefile.am -print |
+	   sed 's/\.am$/.in/' |
+	   while read f; do touch "$f"; done
+    ;;
+
+  autom4te*)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, but is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.
+         You can get \`$1' as part of \`Autoconf' from any GNU
+         archive site."
+
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -f "$file"; then
+	touch $file
+    else
+	test -z "$file" || exec >$file
+	echo "#! /bin/sh"
+	echo "# Created by GNU Automake missing as a replacement of"
+	echo "#  $ $@"
+	echo "exit 0"
+	chmod +x $file
+	exit 1
+    fi
+    ;;
+
+  bison*|yacc*)
+    echo 1>&2 "\
+WARNING: \`$1' $msg.  You should only need it if
+         you modified a \`.y' file.  You may need the \`Bison' package
+         in order for those modifications to take effect.  You can get
+         \`Bison' from any GNU archive site."
+    rm -f y.tab.c y.tab.h
+    if test $# -ne 1; then
+        eval LASTARG="\${$#}"
+	case $LASTARG in
+	*.y)
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
+	    if test -f "$SRCFILE"; then
+	         cp "$SRCFILE" y.tab.c
+	    fi
+	    SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
+	    if test -f "$SRCFILE"; then
+	         cp "$SRCFILE" y.tab.h
+	    fi
+	  ;;
+	esac
+    fi
+    if test ! -f y.tab.h; then
+	echo >y.tab.h
+    fi
+    if test ! -f y.tab.c; then
+	echo 'main() { return 0; }' >y.tab.c
+    fi
+    ;;
+
+  lex*|flex*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.l' file.  You may need the \`Flex' package
+         in order for those modifications to take effect.  You can get
+         \`Flex' from any GNU archive site."
+    rm -f lex.yy.c
+    if test $# -ne 1; then
+        eval LASTARG="\${$#}"
+	case $LASTARG in
+	*.l)
+	    SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
+	    if test -f "$SRCFILE"; then
+	         cp "$SRCFILE" lex.yy.c
+	    fi
+	  ;;
+	esac
+    fi
+    if test ! -f lex.yy.c; then
+	echo 'main() { return 0; }' >lex.yy.c
+    fi
+    ;;
+
+  help2man*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+	 you modified a dependency of a manual page.  You may need the
+	 \`Help2man' package in order for those modifications to take
+	 effect.  You can get \`Help2man' from any GNU archive site."
+
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -f "$file"; then
+	touch $file
+    else
+	test -z "$file" || exec >$file
+	echo ".ab help2man is required to generate this page"
+	exit $?
+    fi
+    ;;
+
+  makeinfo*)
+    echo 1>&2 "\
+WARNING: \`$1' is $msg.  You should only need it if
+         you modified a \`.texi' or \`.texinfo' file, or any other file
+         indirectly affecting the aspect of the manual.  The spurious
+         call might also be the consequence of using a buggy \`make' (AIX,
+         DU, IRIX).  You might want to install the \`Texinfo' package or
+         the \`GNU make' package.  Grab either from any GNU archive site."
+    # The file to touch is that specified with -o ...
+    file=`echo "$*" | sed -n "$sed_output"`
+    test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
+    if test -z "$file"; then
+      # ... or it is the one specified with @setfilename ...
+      infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
+      file=`sed -n '
+	/^@setfilename/{
+	  s/.* \([^ ]*\) *$/\1/
+	  p
+	  q
+	}' $infile`
+      # ... or it is derived from the source name (dir/f.texi becomes f.info)
+      test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
+    fi
+    # If the file does not exist, the user really needs makeinfo;
+    # let's fail without touching anything.
+    test -f $file || exit 1
+    touch $file
+    ;;
+
+  tar*)
+    shift
+
+    # We have already tried tar in the generic part.
+    # Look for gnutar/gtar before invocation to avoid ugly error
+    # messages.
+    if (gnutar --version > /dev/null 2>&1); then
+       gnutar "$@" && exit 0
+    fi
+    if (gtar --version > /dev/null 2>&1); then
+       gtar "$@" && exit 0
+    fi
+    firstarg="$1"
+    if shift; then
+	case $firstarg in
+	*o*)
+	    firstarg=`echo "$firstarg" | sed s/o//`
+	    tar "$firstarg" "$@" && exit 0
+	    ;;
+	esac
+	case $firstarg in
+	*h*)
+	    firstarg=`echo "$firstarg" | sed s/h//`
+	    tar "$firstarg" "$@" && exit 0
+	    ;;
+	esac
+    fi
+
+    echo 1>&2 "\
+WARNING: I can't seem to be able to run \`tar' with the given arguments.
+         You may want to install GNU tar or Free paxutils, or check the
+         command line arguments."
+    exit 1
+    ;;
+
+  *)
+    echo 1>&2 "\
+WARNING: \`$1' is needed, and is $msg.
+         You might have modified some files without having the
+         proper tools for further handling them.  Check the \`README' file,
+         it often tells you about the needed prerequisites for installing
+         this package.  You may also peek at any GNU archive site, in case
+         some other package would contain this missing \`$1' program."
+    exit 1
+    ;;
+esac
+
+exit 0
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/relion.h b/relion.h
new file mode 100644
index 0000000..907bd19
--- /dev/null
+++ b/relion.h
@@ -0,0 +1,55 @@
+#ifndef RELION_H_
+#define RELION_H_
+
+//This is a main header - it includes everything else.
+
+
+#include <external/Healpix_2.15a/arr.h>
+#include <external/Healpix_2.15a/cxxutils.h>
+#include <external/Healpix_2.15a/datatypes.h>
+#include <external/Healpix_2.15a/geom_utils.h>
+#include <external/Healpix_2.15a/healpix_base.h>
+#include <external/Healpix_2.15a/lsconstants.h>
+#include <external/Healpix_2.15a/message_error.h>
+#include <external/Healpix_2.15a/openmp_support.h>
+#include <external/Healpix_2.15a/pointing.h>
+#include <external/Healpix_2.15a/vec3.h>
+#include <src/args.h>
+#include <src/backprojector.h>
+#include <src/blobs.h>
+#include <src/ctf.h>
+#include <src/error.h>
+#include <src/euler.h>
+#include <src/exp_model.h>
+#include <src/fftw.h>
+#include <src/filename.h>
+#include <src/funcs.h>
+#include <src/gcc_version.h>
+#include <src/healpix_map.h>
+#include <src/healpix_sampling.h>
+#include <src/image.h>
+#include <src/macros.h>
+#include <src/matrix1d.h>
+#include <src/matrix2d.h>
+#include <src/memory.h>
+#include <src/metadata_container.h>
+#include <src/metadata_label.h>
+#include <src/metadata_table.h>
+#include <src/ml_model.h>
+#include <src/ml_optimiser.h>
+#include <src/ml_optimiser_mpi.h>
+#include <src/mpi.h>
+#include <src/multidim_array.h>
+#include <src/numerical_recipes.h>
+#include <src/parallel.h>
+#include <src/projector.h>
+#include <src/rwIMAGIC.h>
+#include <src/rwMRC.h>
+#include <src/rwSPIDER.h>
+#include <src/strings.h>
+#include <src/symmetries.h>
+#include <src/timer.h>
+#include <src/transformations.h>
+#include <src/util.h>
+
+#endif // RELION_H_
diff --git a/relion.pc.in b/relion.pc.in
new file mode 100644
index 0000000..98f0326
--- /dev/null
+++ b/relion.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE_NAME@
+Description: relion C++ library.
+Version: @PACKAGE_VERSION@
+URL: @PACKAGE_URL@
+Libs: -L${libdir} -lrelion- at RELION_API_VERSION@
+Cflags: -I${includedir}/relion- at RELION_API_VERSION@ -I${libdir}/relion- at RELION_API_VERSION@/include
diff --git a/scripts/qsub.csh b/scripts/qsub.csh
new file mode 100644
index 0000000..0679207
--- /dev/null
+++ b/scripts/qsub.csh
@@ -0,0 +1,12 @@
+#!/bin/tcsh
+#$ -pe XXXqueueXXX XXXmpinodesXXX
+#$ -l dedicated=XXXthreadsXXX 
+#$ -e XXXerrfileXXX
+#$ -o XXXoutfileXXX
+#$ -cwd
+#$ -S /bin/tcsh
+
+# Environment
+source ~/.cshrc
+
+mpiexec -n XXXmpinodesXXX  XXXcommandXXX
diff --git a/scripts/star_datablock_ctfdat b/scripts/star_datablock_ctfdat
new file mode 100755
index 0000000..058a4a6
--- /dev/null
+++ b/scripts/star_datablock_ctfdat
@@ -0,0 +1,24 @@
+#!/bin/bash
+if [ $# != 0 ]; then
+ while read line; do
+  # Get image name from first column
+  image=`echo $line | awk '{print $1}'`
+  # Get ctfparam name from second column
+  ctfparam=`echo $line | awk '{print $2}'`
+  # Strip directories from ctfparam and remove "_Periodogramavg.ctfparam" to get micrograph name
+  micro=`echo $ctfparam | awk -F"/" '{print $NF}' | sed 's|_Periodogramavg.ctfparam||'`
+  # Get metadata from the ctfparam, reverse sign for defocusU, defocusV and Q0
+  metadata=`awk '{if ($1~"defocus" || $1~"Q0") {printf "%s%s", -$2," "} else if ($1~"sampling" || $1~"K=") {} else {printf "%s%s", $2," "} } END {printf "\n"}' <$ctfparam `
+  echo $image $micro $metadata
+ done < $1
+else
+ echo " === Usage: === "
+ echo " ${0} <xmippctfdatfile> "
+ echo " "
+ echo " === Purpose: === "
+ echo " This (bash) script generates the STAR datablock for all images in an xmipp-format CTFDAT file"
+ echo " Note that the sign for XMIPP's defocusU, defocusV and Q0 values is reversed "
+ echo " "
+ echo " === Example: ==="
+ echo " ${0} all_images.ctfdat "
+fi
diff --git a/scripts/star_datablock_singlefiles b/scripts/star_datablock_singlefiles
new file mode 100755
index 0000000..71eaecd
--- /dev/null
+++ b/scripts/star_datablock_singlefiles
@@ -0,0 +1,29 @@
+#!/bin/bash
+if [ $# != 0 ]; then
+ for i in ${1}
+  do
+     echo -n ${i}" "
+     for (( c=2; c<=$#; c++ ))
+     do
+       echo -n ${!c}" "
+     done
+     echo ""
+ done
+else
+ echo " === Usage: === "
+ echo " ${0} \"*.spi\" <value1> <value2> ..."
+ echo " "
+ echo " === Purpose: === "
+ echo " This (bash) script generates the datablock for all images represented by the wildcard in the first argument"
+ echo " Other (optional) data values are in value1, value2, etc. "
+ echo " "
+ echo " === Example: ==="
+ echo " ${0} \"tmp/*\" 10000 10500 0.0 200 2 0.1"
+ echo " yields: "
+ echo " tmp/t1.spi 10000 10500 0.0 200 2 0.1" 
+ echo " tmp/t2.spi 10000 10500 0.0 200 2 0.1" 
+ echo " tmp/t3.spi 10000 10500 0.0 200 2 0.1" 
+fi
+
+
+
diff --git a/scripts/star_datablock_stack b/scripts/star_datablock_stack
new file mode 100755
index 0000000..6f9fda5
--- /dev/null
+++ b/scripts/star_datablock_stack
@@ -0,0 +1,29 @@
+#!/bin/bash
+if [ $# != 0 ]; then
+ for i in `seq 1 ${1}`
+  do
+     printf "%06i%1s%s%s" ${i} "@" ${2}  " "
+     for (( c=3; c<=$#; c++ ))
+     do
+       echo -n ${!c}" "
+     done
+     echo ""
+ done
+else
+ echo " === Usage: === "
+ echo " ${0} <N> <stackname> <value1> <value2> ..."
+ echo " "
+ echo " === Purpose: === "
+ echo " This (bash) script generates the datablock for N images in a stack named stackname"
+ echo " Other (optional) data values are in value1, value2, etc. "
+ echo " "
+ echo " === Example: ==="
+ echo " ${0} 3 my_images.mrcs 10000 10500 0.0 200 2 0.1"
+ echo " yields: "
+ echo " 000001 at my_images.mrcs 10000 10500 0.0 200 2 0.1" 
+ echo " 000002 at my_images.mrcs 10000 10500 0.0 200 2 0.1" 
+ echo " 000003 at my_images.mrcs 10000 10500 0.0 200 2 0.1" 
+fi
+
+
+
diff --git a/scripts/star_loopheader b/scripts/star_loopheader
new file mode 100755
index 0000000..f5c2178
--- /dev/null
+++ b/scripts/star_loopheader
@@ -0,0 +1,31 @@
+#!/bin/bash -f
+if [ $# != 0 ]; then
+ echo "data_"
+ echo "loop_"
+ for i;
+ do
+  echo "_"${i}
+ done;
+else
+ echo " === Usage: === "
+ echo " ${0} <label1> <label2> ..."
+ echo " "
+ echo " === Purpose: === "
+ echo " This (bash) script generates the header of STAR-file with the given labels"
+ echo " "
+ echo " === Example: ==="
+ echo " ${0} rlnImageName rlnDefocusU rlnDefocusV rlnDefocusAngle rlnVoltage rlnSphericalAberration rlnAmplitudeContrast"
+ echo " yields: "
+ echo " data_"
+ echo " loop_"
+ echo " _rlnImageName"
+ echo " _rlnDefocusU"
+ echo " _rlnDefocusV"
+ echo " _rlnDefocusAngle"
+ echo " _rlnVoltage"
+ echo " _rlnSphericalAberration"
+ echo " _rlnAmplitudeContrast"
+fi
+
+
+
diff --git a/scripts/star_plottable b/scripts/star_plottable
new file mode 100644
index 0000000..041d95b
--- /dev/null
+++ b/scripts/star_plottable
@@ -0,0 +1,29 @@
+#!/bin/bash
+if [ $# != 0 ]; then
+ echo " set title '${2}'" > gnuplot.plt
+ echo " set ylabel '${3}'" >> gnuplot.plt
+ if [ $# == 4 ]; then
+  relion_star_printtable ${1} ${2} ${4} ${3} > ${1}-${2}-${3}.dat
+  echo " set xlabel '${4}'" >> gnuplot.plt
+ else
+  relion_star_printtable ${1} ${2} ${3} > ${1}-${2}-${3}.dat
+  echo " set xlabel 'index'" >> gnuplot.plt
+ fi
+ echo " plot '${1}-${2}-${3}.dat' w l " >> gnuplot.plt
+ echo " ** Written datafile: " ${1}-${2}-${3}.dat
+ echo " ** Running: gnuplot -persist gnuplot.plt " 
+ echo " ** Alternatively, inside an interactive gnuplot session type: load \"gnuplot.plt\""
+ gnuplot -persist gnuplot.plt
+else
+ echo " === Usage: === "
+ echo " ${0} <starfile> <tablename> <yaxis-label> <xaxis-label>"
+ echo " "
+ echo " === Purpose: === "
+ echo " This (bash) script uses gnuplot to plot content from a datablock (with name <tablename>) in <starfile>"
+ echo " It will make a plot of the values given for <yaxis-label> against those of <xaxis-label>"
+ echo " If <xaxis-label> is not given, the values of <yaxis-label> will be plotted linearly"
+ echo " "
+ echo " === Example: ==="
+ echo " ${0} run3_it024_model.star run3_it024_model.star data_model_class_1 rlnSsnrMap rlnResolution"
+fi
+
diff --git a/scripts/star_printtable b/scripts/star_printtable
new file mode 100755
index 0000000..cdc3518
--- /dev/null
+++ b/scripts/star_printtable
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+if [ $# != 0 ]; then
+ cat ${1} | awk -v"tab=${2}" 'BEGIN {a=0} {if ($0 ~ tab) {a = 22}; if (a==22) {if ($0 ~ "loop") a+=1} if (a==23) {if (length($0) < 2 || $1 ~ "data_") {exit} else {print $0} }}'  |grep -v "loop_" > tmp.dat
+ if [ $# == 2 ]; then
+    awk '{if (index($1,"_")!= 1) print; }' < tmp.dat
+ else
+  awk '{if (index($1,"_")!= 1) {j++; print j;} }' < tmp.dat > tmp1.dat
+  for (( c=3; c<=$#; c++ ))
+   do
+    awk -v"label=${!c}" '{i++; if ($1 ~ label) {col = i}; if (index($1,"_")!= 1) { j++; print j, $col} }' < tmp.dat >tmp2.dat
+    join tmp1.dat tmp2.dat > tmp3.dat
+    mv -f tmp3.dat tmp1.dat
+   done
+   awk '{for (i=2; i<=NF;i++) printf("%s%s", $i,(i==NF) ? "\n" : OFS)}' <tmp1.dat
+ fi
+ rm -f tmp.dat tmp1.dat tmp2.dat tmp3.dat
+else
+ echo " === Usage: === "
+ echo " ${0} <starfile> <tablename> <label1> <label2> ..."
+ echo " "
+ echo " === Purpose: === "
+ echo " This (bash) script prints the contents of a datablock (with name tablename) from a starfile"
+ echo " If any labels are given, then only those will be printed "
+ echo " "
+ echo " === Example: === "
+ echo " ${0} run3_it024_model.star data_model_class_1 _rlnResolution _rlnSsnrMap"
+fi
+
diff --git a/src/Healpix_2.15a/arr.h b/src/Healpix_2.15a/arr.h
new file mode 100644
index 0000000..95c9730
--- /dev/null
+++ b/src/Healpix_2.15a/arr.h
@@ -0,0 +1,447 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*! \file src/Healpix_2.15a/cxxsupport/arr.h
+ *  Various high-performance array classes used by the Planck LevelS package.
+ *
+ *  Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Max-Planck-Society
+ *  \author Martin Reinecke
+ */
+
+#ifndef PLANCK_ARR_H
+#define PLANCK_ARR_H
+
+#include "src/Healpix_2.15a/cxxutils.h"
+#include <algorithm>
+
+/*! \defgroup arraygroup Array classes */
+/*! \{ */
+
+/*! An array whose size is known at compile time. Very useful for storing
+    small arrays on the stack, without need for \a new and \a delete(). */
+template <typename T, unsigned int sz> class fix_arr
+  {
+  private:
+    T d[sz];
+
+  public:
+    /*! Returns the size of the array. */
+    long size() const { return sz; }
+
+    /*! Returns a reference to element \a #n */
+    template<typename T2> T &operator[] (T2 n) {return d[n];}
+    /*! Returns a constant reference to element \a #n */
+    template<typename T2> const T &operator[] (T2 n) const {return d[n];}
+  };
+
+
+/*! One-dimensional array type. */
+template <typename T> class arr
+  {
+  private:
+    long s;
+    T *d;
+    bool own;
+
+#if defined(PLANCK_CHECKS)
+    void check_range(long n) const
+      {
+      if ((n<0) || (n>=s)) throw Message_error
+        ("arr: index "+dataToString(n)+" is out of range. Max index is "
+         +dataToString(s-1));
+      }
+#endif
+
+    void reset()
+      { s=0; d=0; own=true; }
+
+  public:
+    /*! Creates a zero-sized array. */
+    arr() : s(0), d(0), own(true) {}
+    /*! Creates an array with \a sz entries. */
+    arr(long sz) : s(sz), d (s>0 ? new T[s] : 0), own(true) {}
+    /*! Creates an array with \a sz entries, and initializes them with
+        \a inival. */
+    arr(long sz, const T &inival) : s(sz), d (s>0 ? new T[s] : 0), own(true)
+      { fill(inival); }
+    /*! Creates an array with \a sz entries, which uses the memory pointed
+        to by \a ptr.
+        \note \a ptr will <i>not</i> be deallocated by the destructor.
+        \warning Only use this if you REALLY know what you are doing.
+        In particular, this is only safely usable if
+          <ul>
+          <li>\a T is a POD type</li>
+          <li>\a ptr survives during the lifetime of the array object</li>
+          <li>\a ptr is not subject to garbage collection</li>
+          </ul>
+        Other restrictions may apply. You have been warned. */
+    arr (T *ptr, long sz): s(sz), d(ptr), own(false) {}
+    /*! Creates an array which is a copy of \a orig. The data in \a orig
+        is duplicated. */
+    arr (const arr &orig): s(orig.s), d (s>0 ? new T[s] : 0), own(true)
+      { for (long m=0; m<s; ++m) d[m] = orig.d[m]; }
+    /*! Frees the memory allocated by the object. */
+    ~arr() { if (own) delete[] d; }
+
+    /*! Returns the current array size. */
+    long size() const { return s; }
+
+    /*! Allocates space for \a sz elements. The content of the array is
+        undefined on exit. \a sz can be 0. If \a sz is the
+        same as the current size, no reallocation is performed. */
+    void alloc (long sz)
+      {
+      if (sz==s) return;
+      if (own) delete[] d;
+      s = sz;
+      d = s>0 ? new T[sz] : 0;
+      own = true;
+      }
+    /*! Deallocates the memory held by the array, and sets the array size
+        to 0. */
+    void dealloc () {if (own) delete[] d; reset();}
+
+    /*! Writes \a val into every element of the array. */
+    void fill (const T &val)
+      { for (long m=0; m<s; ++m) d[m]=val; }
+
+    /*! Changes the array to be a copy of \a orig. */
+    arr &operator= (const arr &orig)
+      {
+      if (this==&orig) return *this;
+      alloc (orig.s);
+      for (long m=0; m<s; ++m) d[m] = orig.d[m];
+      return *this;
+      }
+
+#if defined (PLANCK_CHECKS)
+    template<typename T2> T &operator[] (T2 n) {check_range(n); return d[n];}
+    template<typename T2> const T &operator[] (T2 n) const
+      {check_range(n); return d[n];}
+#else
+    /*! Returns a reference to element \a #n */
+    template<typename T2> T &operator[] (T2 n) {return d[n];}
+    /*! Returns a constant reference to element \a #n */
+    template<typename T2> const T &operator[] (T2 n) const {return d[n];}
+#endif
+
+    T *begin() { return d; }
+    T *end() { return d+s; }
+
+    /*! Sorts the elements in the array, in ascending order. */
+    void sort()
+      { std::sort (d,d+s); }
+
+    /*! Returns the minimum and maximum entry in \a minv and \a maxv,
+        respectively. Throws an exception if the array is zero-sized. */
+    void minmax (T &minv, T &maxv) const
+      {
+      planck_assert(s>0,"trying to find min and max of a zero-sized array");
+      minv=maxv=d[0];
+      for (int m=1; m<s; ++m)
+        {
+        if (d[m]<minv) minv=d[m];
+        else if (d[m]>maxv) maxv=d[m];
+        }
+      }
+
+    /*! Assigns the contents and size of \a other to the array. On exit,
+        \a other is yero-sized. */
+    void transfer (arr &other)
+      { if (own) delete[] d; d=other.d; s=other.s; own=other.own; other.reset(); }
+    /*! Swaps contents and size with \a other. */
+    void swap (arr &other)
+      { std::swap(d,other.d); std::swap(s,other.s); std::swap(own,other.own);}
+  };
+
+/*! Two-dimensional array type. The storage ordering is the same as in C.
+    An entry is located by address arithmetic, not by double dereferencing.
+    The indices start at zero. */
+template <typename T> class arr2
+  {
+  private:
+    long s1, s2;
+    arr<T> d;
+
+#if defined (PLANCK_CHECKS)
+    void check_range(long n) const
+      {
+      if ((n<0) || (n>=s1)) throw Message_error
+        ("arr2: index "+dataToString(n)+" is out of range. Max index is "
+         +dataToString(s1-1));
+      }
+#endif
+
+  public:
+    /*! Creates a zero-sized array. */
+    arr2() : s1(0), s2(0) {}
+    /*! Creates an array with the dimensions \a sz1 and \a sz2. */
+    arr2(long sz1, long sz2)
+      : s1(sz1), s2(sz2), d(s1*s2) {}
+    /*! Creates the array as a copy of \a orig. */
+    arr2(const arr2 &orig)
+      : s1(orig.s1), s2(orig.s2), d(orig.d) {}
+    /*! Frees the memory associated with the array. */
+    ~arr2() {}
+
+    /*! Returns the first array dimension. */
+    long size1() const { return s1; }
+    /*! Returns the second array dimension. */
+    long size2() const { return s2; }
+    /*! Returns the total array size, i.e. the product of both dimensions. */
+    long size () const { return s1*s2; }
+
+    /*! Allocates space for an array with \a sz1*sz2 elements.
+        The content of the array is undefined on exit.
+        \a sz1 or \a sz2 can be 0. If \a sz1*sz2 is the same as the
+        currently allocated space, no reallocation is performed. */
+    void alloc (long sz1, long sz2)
+      {
+      if (sz1*sz2 != d.size())
+        d.alloc(sz1*sz2);
+      s1=sz1; s2=sz2;
+      }
+    /*! Allocates space for an array with \a sz1*sz2 elements.
+        The content of the array is undefined on exit.
+        \a sz1 or \a sz2 can be 0. If \a sz1*sz2 is smaller than the
+        currently allocated space, no reallocation is performed. */
+    void fast_alloc (long sz1, long sz2)
+      {
+      if (sz1*sz2<=d.size())
+        { s1=sz1; s2=sz2; }
+      else
+        alloc(sz1,sz2);
+      }
+    /*! Deallocates the space and makes the array zero-sized. */
+    void dealloc () {d.dealloc(); s1=0; s2=0;}
+
+    /*! Sets all array elements to \a val. */
+    void fill (const T &val)
+      { d.fill(val); }
+
+    /*! Changes the array to be a copy of \a orig. */
+    arr2 &operator= (const arr2 &orig)
+      {
+      if (this==&orig) return *this;
+      alloc (orig.s1, orig.s2);
+      d = orig.d;
+      return *this;
+      }
+
+#if defined (PLANCK_CHECKS)
+    template<typename T2> T *operator[] (T2 n)
+      {check_range(n);return &d[n*s2];}
+    template<typename T2> const T *operator[] (T2 n) const
+      {check_range(n);return &d[n*s2];}
+#else
+    /*! Returns a pointer to the beginning of slice \a #n. */
+    template<typename T2> T *operator[] (T2 n) {return &d[n*s2];}
+    /*! Returns a constant pointer to the beginning of slice \a #n. */
+    template<typename T2> const T *operator[] (T2 n) const {return &d[n*s2];}
+#endif
+
+    /*! Returns the minimum and maximum entry in \a minv and \a maxv,
+        respectively. Throws an exception if the array is zero-sized. */
+    void minmax (T &minv, T &maxv) const
+      {
+      planck_assert(s1*s2>0,
+        "trying to find min and max of a zero-sized array");
+      minv=maxv=d[0];
+      for (int m=1; m<s1*s2; ++m)
+        {
+        if (d[m]<minv) minv=d[m];
+        if (d[m]>maxv) maxv=d[m];
+        }
+      }
+
+    /*! Swaps contents and sizes with \a other. */
+    void swap (arr2 &other)
+      {
+      d.swap(other.d);
+      std::swap(s1,other.s1);
+      std::swap(s2,other.s2);
+      }
+  };
+
+/*! Two-dimensional array type. An entry is located by double dereferencing,
+    i.e. via an array of pointers. The indices start at zero. */
+template <typename T> class arr2b
+  {
+  private:
+    long s1, s2;
+    arr<T> d;
+    arr<T *> d1;
+
+#if defined (PLANCK_CHECKS)
+    void check_range(long n) const
+      {
+      if ((n<0) || (n>=s1)) throw Message_error
+        ("arr: index "+dataToString(n)+" is out of range. Max index is "
+         +dataToString(s1-1));
+      }
+#endif
+
+    void fill_d1()
+      { for (long m=0; m<s1; ++m) d1[m] = &d[m*s2]; }
+
+  public:
+    /*! Creates a zero-sized array. */
+    arr2b() : s1(0), s2(0), d(0), d1(0) {}
+    /*! Creates an array with the dimensions \a sz1 and \a sz2. */
+    arr2b(long sz1, long sz2)
+      : s1(sz1), s2(sz2), d(s1*s2), d1(s1)
+      { fill_d1(); }
+    /*! Creates the array as a copy of \a orig. */
+    arr2b(const arr2b &orig)
+      : s1(orig.s1), s2(orig.s2), d(orig.d), d1(s1)
+      { fill_d1(); }
+    /*! Frees the memory associated with the array. */
+    ~arr2b() {}
+
+    /*! Returns the first array dimension. */
+    long size1() const { return s1; }
+    /*! Returns the second array dimension. */
+    long size2() const { return s2; }
+    /*! Returns the total array size, i.e. the product of both dimensions. */
+    long size () const { return s1*s2; }
+
+    /*! Allocates space for an array with \a sz1*sz2 elements.
+        The content of the array is undefined on exit. */
+    void alloc (long sz1, long sz2)
+      {
+      if ((s1==sz1) && (s2==sz2)) return;
+      s1=sz1; s2=sz2;
+      d.alloc(s1*s2);
+      d1.alloc(s1);
+      fill_d1();
+      }
+    /*! Deallocates the space and makes the array zero-sized. */
+    void dealloc () {d.dealloc(); d1.dealloc(); s1=0; s2=0;}
+
+    /*! Sets all array elements to \a val. */
+    void fill (const T &val)
+      { d.fill(val); }
+
+    /*! Changes the array to be a copy of \a orig. */
+    arr2b &operator= (const arr2b &orig)
+      {
+      if (this==&orig) return *this;
+      alloc (orig.s1, orig.s2);
+      for (long m=0; m<s1*s2; ++m) d[m] = orig.d[m];
+      return *this;
+      }
+
+#if defined (PLANCK_CHECKS)
+    template<typename T2> T *operator[] (T2 n) {check_range(n); return d1[n];}
+    template<typename T2> const T *operator[] (T2 n) const
+      {check_range(n); return d1[n];}
+#else
+    /*! Returns a pointer to the beginning of slice \a #n. */
+    template<typename T2> T *operator[] (T2 n) {return d1[n];}
+    /*! Returns a constant pointer to the beginning of slice \a #n. */
+    template<typename T2> const T *operator[] (T2 n) const {return d1[n];}
+#endif
+    /*! Returns a pointer to the beginning of the pointer array. */
+    T **p0() {return &d1[0];}
+  };
+
+
+/*! Three-dimensional array type. The storage ordering is the same as in C.
+    An entry is located by address arithmetic, not by multiple dereferencing.
+    The indices start at zero. */
+template <typename T> class arr3
+  {
+  private:
+    long s1, s2, s3, s2s3;
+    arr<T> d;
+
+  public:
+    /*! Creates a zero-sized array. */
+    arr3() : s1(0), s2(0), s3(0), s2s3(0), d(0) {}
+    /*! Creates an array with the dimensions \a sz1, \a sz2 and \a sz3. */
+    arr3(long sz1, long sz2, long sz3)
+      : s1(sz1), s2(sz2), s3(sz3), s2s3(s2*s3), d(s1*s2*s3) {}
+    /*! Creates the array as a copy of \a orig. */
+    arr3(const arr3 &orig)
+      : s1(orig.s1), s2(orig.s2), s3(orig.s3), s2s3(orig.s2s3), d(orig.d) {}
+    /*! Frees the memory associated with the array. */
+    ~arr3() {}
+
+    /*! Returns the first array dimension. */
+    long size1() const { return s1; }
+    /*! Returns the second array dimension. */
+    long size2() const { return s2; }
+    /*! Returns the third array dimension. */
+    long size3() const { return s3; }
+    /*! Returns the total array size, i.e. the product of all dimensions. */
+    long size () const { return s1*s2*s3; }
+
+    /*! Allocates space for an array with \a sz1*sz2*sz3 elements.
+        The content of the array is undefined on exit. */
+    void alloc (long sz1, long sz2, long sz3)
+      {
+      d.alloc(sz1*sz2*sz3);
+      s1=sz1; s2=sz2; s3=sz3; s2s3=s2*s3;
+      }
+    /*! Deallocates the space and makes the array zero-sized. */
+    void dealloc () {d.dealloc(); s1=0; s2=0; s3=0; s2s3=0;}
+
+    /*! Sets all array elements to \a val. */
+    void fill (const T &val)
+      { d.fill(val); }
+
+    /*! Changes the array to be a copy of \a orig. */
+    arr3 &operator= (const arr3 &orig)
+      {
+      if (this==&orig) return *this;
+      alloc (orig.s1, orig.s2, orig.s3);
+      d = orig.d;
+      return *this;
+      }
+
+    /*! Returns a reference to the element with the indices
+        \a n1, \a n2 and \a n3. */
+    template<typename T2> T &operator() (T2 n1, T2 n2, T2 n3)
+      {return d[n1*s2s3 + n2*s3 + n3];}
+    /*! Returns a constant reference to the element with the indices
+        \a n1, \a n2 and \a n3. */
+    template<typename T2> const T &operator() (T2 n1, T2 n2, T2 n3) const
+      {return d[n1*s2s3 + n2*s3 + n3];}
+
+    /*! Swaps contents and sizes with \a other. */
+    void swap (arr3 &other)
+      {
+      d.swap(other.d);
+      std::swap(s1,other.s1);
+      std::swap(s2,other.s2);
+      std::swap(s3,other.s3);
+      std::swap(s2s3,other.s2s3);
+      }
+  };
+
+/*! \} */
+
+#endif
diff --git a/src/Healpix_2.15a/cxxutils.cc b/src/Healpix_2.15a/cxxutils.cc
new file mode 100644
index 0000000..32b61d8
--- /dev/null
+++ b/src/Healpix_2.15a/cxxutils.cc
@@ -0,0 +1,297 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*
+ *  This file contains the implementation of various convenience functions
+ *  used by the Planck LevelS package.
+ *
+ *  Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Max-Planck-Society
+ *  Authors: Martin Reinecke, Reinhard Hell
+ */
+
+// if we are using g++, check for version 3.0 or higher
+#ifdef __GNUC__
+#if (__GNUC__<3)
+#error your C++ compiler is too old. g++ version 3.0 or higher is required.
+#endif
+#endif
+
+#include <fstream>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <cstdio>
+#include <cctype>
+#include "src/Healpix_2.15a/cxxutils.h"
+#include "src/Healpix_2.15a/datatypes.h"
+#include "src/Healpix_2.15a/openmp_support.h"
+
+using namespace std;
+
+bool file_present (const string &filename)
+  {
+  ifstream dummy(filename.c_str());
+  return dummy;
+  }
+
+void assert_present (const string &filename)
+  {
+  if (file_present(filename)) return;
+  throw Message_error ("Error: file " + filename + " does not exist!");
+  }
+
+void assert_not_present (const string &filename)
+  {
+  if (!file_present(filename)) return;
+  throw Message_error ("Error: file " + filename + " already exists!");
+  }
+
+void remove_file (const string &filename)
+  {
+  remove (filename.c_str());
+  }
+
+string trim (const string &orig)
+  {
+  string::size_type p1=orig.find_first_not_of(" \t");
+  if (p1==string::npos) return "";
+  string::size_type p2=orig.find_last_not_of(" \t");
+  return orig.substr(p1,p2-p1+1);
+  }
+
+template<typename T> string dataToString (const T &x)
+  {
+  ostringstream strstrm;
+  strstrm << x;
+  return trim(strstrm.str());
+  }
+
+template<> string dataToString (const bool &x)
+  { return x ? "T" : "F"; }
+template<> string dataToString (const string &x)
+  { return trim(x); }
+template<> string dataToString (const float &x)
+  {
+  ostringstream strstrm;
+  strstrm << setprecision(8) << x;
+  return trim(strstrm.str());
+  }
+template<> string dataToString (const double &x)
+  {
+  ostringstream strstrm;
+  strstrm << setprecision(16) << x;
+  return trim(strstrm.str());
+  }
+
+template string dataToString (const signed char &x);
+template string dataToString (const unsigned char &x);
+template string dataToString (const short &x);
+template string dataToString (const unsigned short &x);
+template string dataToString (const int &x);
+template string dataToString (const unsigned int &x);
+template string dataToString (const long &x);
+template string dataToString (const unsigned long &x);
+template string dataToString (const long long &x);
+template string dataToString (const unsigned long long &x);
+
+string intToString(int x, int width)
+  {
+  ostringstream strstrm;
+  strstrm << setw(width) << setfill('0') << x;
+  return trim(strstrm.str());
+  }
+
+template<typename T> void stringToData (const string &x, T &value)
+  {
+  string error = string("conversion error in stringToData<")
+               + type2typename<T>()
+               +">(\""+x+"\")";
+  istringstream strstrm(x);
+  strstrm >> value;
+  if (!strstrm)
+    throw Message_error(error);
+
+  string rest;
+  strstrm >> rest;
+//  rest=trim(rest);
+  if (rest.length()>0) throw Message_error(error);
+  }
+
+template<> void stringToData (const string &x, string &value)
+  { value = trim(x); }
+
+template<> void stringToData (const string &x, bool &value)
+  {
+  if ( x=="F" || x=="f" || x=="n" || x=="N" || x=="false" || x==".false."
+       || x=="FALSE" || x==".FALSE.")
+    value=false;
+  else if (x=="T" || x=="t" || x=="y" || x=="Y" || x=="true" || x==".true."
+       || x=="TRUE" || x==".TRUE.")
+    value=true;
+  else
+    {
+    string error = string("conversion error in stringToData<bool>(\"")+x+"\")";
+    throw Message_error (error);
+    }
+  }
+
+template void stringToData (const string &x, signed char &value);
+template void stringToData (const string &x, unsigned char &value);
+template void stringToData (const string &x, short &value);
+template void stringToData (const string &x, unsigned short &value);
+template void stringToData (const string &x, int &value);
+template void stringToData (const string &x, unsigned int &value);
+template void stringToData (const string &x, long &value);
+template void stringToData (const string &x, unsigned long &value);
+template void stringToData (const string &x, long long &value);
+template void stringToData (const string &x, unsigned long long &value);
+template void stringToData (const string &x, float &value);
+template void stringToData (const string &x, double &value);
+
+bool equal_nocase (const string &a, const string &b)
+  {
+  if (a.size()!=b.size()) return false;
+  for (unsigned int m=0; m<a.size(); ++m)
+    if (tolower(a[m])!=tolower(b[m])) return false;
+  return true;
+  }
+
+string tolower(const string &input)
+  {
+  string result=input;
+  for (unsigned int m=0; m<result.size(); ++m)
+    result[m]=char(tolower(result[m]));
+  return result;
+  }
+
+// FIXME: this should be configurable from outside
+#define SILENT
+#ifdef SILENT
+
+void announce_progress (int, int) {}
+void announce_progress (double, double, double) {}
+void end_announce_progress () {}
+
+#else
+
+void announce_progress (int now, int total)
+  {
+  if ((now%(max(total/100,1)))==0)
+    cout << "\r " << setw(3) << planck_nint ((now*100.)/total)
+         << "% done\r" << flush;
+  }
+
+void announce_progress (double now, double last, double total)
+  {
+  int lastpercent = int((last/total)*100),
+      nowpercent  = int(( now/total)*100);
+  if (nowpercent>lastpercent)
+    cout << "\r " << setw(3) << nowpercent << "% done\r" << flush;
+  }
+
+void end_announce_progress ()
+  { cout << endl; }
+
+#endif
+
+static void openmp_status()
+  {
+  if (openmp_enabled())
+    {
+    cout << "Application was compiled with OpenMP support," << endl;
+    if (openmp_max_threads() == 1)
+      cout << "but running with one process only." << endl;
+    else
+      cout << "running with up to " << openmp_max_threads()
+           << " processes." << endl;
+    }
+  else
+    cout << "Application was compiled without OpenMP support;" << endl
+         << "running in scalar mode." << endl;
+  }
+
+void announce (const string &name)
+  {
+  cout << endl << "+-";
+  for (unsigned int m=0; m<name.length(); ++m) cout << "-";
+  cout << "-+" << endl;
+  cout << "| " << name << " |" << endl;
+  cout << "+-";
+  for (unsigned int m=0; m<name.length(); ++m) cout << "-";
+  cout << "-+" << endl << endl;
+  openmp_status();
+  cout << endl;
+  }
+
+void module_startup (const string &name, int argc, const char **,
+  int argc_expected, const string &argv_expected)
+  {
+  announce (name);
+  if (argc==argc_expected) return;
+  cerr << "Usage: " << name << " " << argv_expected << endl;
+  throw Message_error();
+  }
+
+void parse_file (const string &filename, map<string,string> &dict)
+  {
+  int lineno=0;
+  dict.clear();
+  ifstream inp(filename.c_str());
+  planck_assert (inp,"Could not open parameter file "+filename);
+  while (inp)
+    {
+    string line;
+    getline(inp, line);
+    ++lineno;
+    // remove potential carriage returns at the end of the line
+    line=line.substr(0,line.find_first_of("\r"));
+    line=line.substr(0,line.find_first_of("#"));
+    line=trim(line);
+    if (line.size()>0)
+      {
+      string::size_type eqpos=line.find("=");
+      if (eqpos!=string::npos)
+        {
+        string key=trim(line.substr(0,eqpos)),
+               value=trim(line.substr(eqpos+1,string::npos));
+        if (key=="")
+          cerr << "Warning: empty key in " << filename << ", line "
+               << lineno << endl;
+        else
+          {
+          if (dict.find(key)!=dict.end())
+            cerr << "Warning: key " << key << " multiply defined in "
+                 << filename << ", line " << lineno << endl;
+          dict[key]=value;
+          }
+        }
+      else
+        cerr << "Warning: unrecognized format in " << filename << ", line "
+             << lineno << ":\n" << line << endl;
+      }
+    }
+  }
diff --git a/src/Healpix_2.15a/cxxutils.h b/src/Healpix_2.15a/cxxutils.h
new file mode 100644
index 0000000..73a71cc
--- /dev/null
+++ b/src/Healpix_2.15a/cxxutils.h
@@ -0,0 +1,268 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*! \file src/Healpix_2.15a/cxxsupport/cxxutils.h
+ *  Various convenience functions used by the Planck LevelS package.
+ *
+ *  Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Max-Planck-Society
+ *  \author Martin Reinecke \author Reinhard Hell
+ */
+
+#ifndef PLANCK_CXXUTILS_H
+#define PLANCK_CXXUTILS_H
+
+#include <algorithm>
+#include <string>
+#include <map>
+#include <cmath>
+#include "src/Healpix_2.15a/message_error.h"
+#include "src/Healpix_2.15a/lsconstants.h"
+
+/*! \defgroup mathutilsgroup Mathematical helper functions */
+/*! \{ */
+
+//! Returns \e true if | \a a-b | < \a epsilon * | \a b |, else \e false.
+template<typename F> inline bool approx (F a, F b, F epsilon=1e-5)
+  {
+  using namespace std;
+  return abs(a-b) < (epsilon*abs(b));
+  }
+
+//! Returns \e true if | \a a-b | < \a epsilon, else \e false.
+template<typename F> inline bool abs_approx (F a, F b, F epsilon=1e-5)
+  {
+  using namespace std;
+  return abs(a-b) < epsilon;
+  }
+
+//! Returns the largest integer which is smaller than (or equal to) \a arg.
+template<typename I, typename F> inline I ifloor (F arg)
+  {
+  return (arg>=0) ? I(arg) : I(arg)-1;
+  }
+
+//! Returns the integer which is nearest to \a arg.
+template<typename I, typename F> inline I nearest (F arg)
+  {
+  arg += 0.5;
+  return (arg>=0) ? I(arg) : I(arg)-1;
+  }
+
+//! Returns \a v1+v2 if \a v1<0, \a v1-v2 if \a v1>=v2, else \a v1.
+/*! \a v1 can be positive or negative; \a v2 must be positive. */
+template<typename T> inline T weak_modulo (T v1, T v2)
+  { return (v1>=0) ? ((v1<v2) ? v1 : (v1-v2)) : (v1+v2); }
+
+//! Returns the remainder of the division \a v1/v2.
+/*! The result is non-negative.
+    \a v1 can be positive or negative; \a v2 must be positive. */
+inline double fmodulo (double v1, double v2)
+  {
+  using namespace std;
+  return (v1>=0) ? ((v1<v2) ? v1 : fmod(v1,v2)) : (fmod(v1,v2)+v2);
+  }
+
+//! Returns the remainder of the division \a v1/v2.
+/*! The result is non-negative.
+    \a v1 can be positive or negative; \a v2 must be positive. */
+template<typename I> inline I imodulo (I v1, I v2)
+  { return (v1>=0) ? ((v1<v2) ? v1 : (v1%v2)) : ((v1%v2)+v2); }
+
+//! Returns -1 if \a signvalue is negative, else +1.
+template<typename T> inline T sign (const T& signvalue)
+  { return (signvalue>=0) ? 1 : -1; }
+
+//! Returns the integer \a n, which fulfills \a n*n<=arg<(n+1)*(n+1).
+template<typename I> inline unsigned int isqrt (I arg)
+  {
+  using namespace std;
+  if (sizeof(I)<=4)
+    return unsigned (sqrt(arg+0.5));
+  long double arg2 = arg;
+  return unsigned (sqrt(arg2+0.5));
+  }
+
+//! Returns the largest integer \a n that fulfills \a 2^n<=arg.
+template<typename I> inline unsigned int ilog2 (I arg)
+  {
+  unsigned int res=0;
+  while (arg > 0x0000FFFF) { res+=16; arg>>=16; }
+  if (arg > 0x000000FF) { res|=8; arg>>=8; }
+  if (arg > 0x0000000F) { res|=4; arg>>=4; }
+  if (arg > 0x00000003) { res|=2; arg>>=2; }
+  if (arg > 0x00000001) { res|=1; }
+  return res;
+  }
+
+//! Returns \a atan2(y,x) if \a x!=0 or \a y!=0; else returns 0.
+inline double safe_atan2 (double y, double x)
+  {
+  using namespace std;
+  return ((x==0.) && (y==0.)) ? 0.0 : atan2(y,x);
+  }
+
+//! Returns an index to the left of two interpolation values.
+/*! \a begin points to an array containing a sequence of values
+    sorted in ascending order. The length of the array is \a len.
+    If \a val is lower than the first element, 0 is returned.
+    If \a val is higher than the last element, \a len-2
+    is returned. Else, the index of the largest element smaller
+    than \a val is returned. */
+template<typename T> inline int interpol_left
+  (const T *begin, int len, const T &val)
+  {
+  const T *end = begin+len;
+  const T *iter = std::lower_bound (begin, end, val);
+  if (iter==begin) return 0;
+  if (iter==end) return len-2;
+  return (iter-begin)-1;
+  }
+
+//! Returns an index to the nearest interpolation value.
+/*! \a begin points to an array containing a sequence of values
+    sorted in ascending order. The length of the array is \a len.
+    If \a val is lower than the first element, 0 is returned.
+    If \a val is higher than the last element, \a len-1 is returned.
+    Else, the index of the nearest element within the sequence of
+    values is returned. */
+template<typename T> inline int interpol_nearest
+  (const T *begin, int len, const T &val)
+  {
+  int left = interpol_left(begin, len, val);
+  T delleft = val-(*(begin+left));
+  T delright = (*(begin+left+1))-val;
+  if (delright<0) return left+1;
+  return (delright<delleft) ? (left+1) : left;
+  }
+
+/*! \} */
+
+/*! \defgroup fileutilsgroup File-handling helper functions */
+/*! \{ */
+
+//! If the file \a filename is present, return \p true, else \p false.
+bool file_present (const std::string &filename);
+
+//! Removes the file \a filename
+void remove_file (const std::string &filename);
+
+/*! \} */
+
+/*! \defgroup assertgroup Assertions */
+/*! \{ */
+
+//! Throws a Message_error containing \a msg if \a testval is false.
+inline void planck_assert (bool testval, const std::string &msg)
+  {
+  if (testval) return;
+  throw Message_error ("Assertion failed: "+msg);
+  }
+//! Throws a Message_error containing \a msg if \a testval is false.
+inline void planck_assert (bool testval, const char *msg)
+  {
+  if (testval) return;
+  throw Message_error ("Assertion failed: "+std::string(msg));
+  }
+
+//! Checks the presence of the file \a filename.
+/*! If the file is not present, a Message_error is thrown. */
+void assert_present (const std::string &filename);
+
+//! Checks the absence of the file \a filename.
+/*! If the file is present, a Message_error is thrown. */
+void assert_not_present (const std::string &filename);
+
+/*! \} */
+
+/*! \defgroup stringutilsgroup String handling helper functions */
+/*! \{ */
+
+//! Returns the string \a orig without leading and trailing whitespace.
+std::string trim (const std::string &orig);
+
+//! Returns a string containing the text representation of \a x.
+/*! Care is taken that no information is lost in the conversion. */
+template<typename T> std::string dataToString(const T &x);
+template<> std::string dataToString (const bool &x);
+template<> std::string dataToString (const std::string &x);
+template<> std::string dataToString (const float &x);
+template<> std::string dataToString (const double &x);
+
+/*! Returns a string containing the text representation of \a x, padded
+    with leading zeroes to \a width characters. */
+std::string intToString(int x, int width);
+
+//! Reads a value of a given datatype from a string
+template<typename T> void stringToData (const std::string &x, T &value);
+template<> void stringToData (const std::string &x, std::string &value);
+template<> void stringToData (const std::string &x, bool &value);
+
+//! Reads a value of a given datatype from a string
+template<typename T> inline T stringToData (const std::string &x)
+  { T result; stringToData(x,result); return result; }
+
+//! Parses the file \a filename and returns the key/value pairs in \a dict.
+void parse_file (const std::string &filename,
+  std::map<std::string,std::string> &dict);
+
+//! Case-insensitive string comparison
+/*! Returns \a true, if \a a and \a b differ only in capitalisation,
+    else \a false. */
+bool equal_nocase (const std::string &a, const std::string &b);
+
+//! Returns lowercase version of \a input.
+std::string tolower(const std::string &input);
+
+/*! \} */
+
+//! Indicates progress by printing the percentage of \a now/total.
+/*! A message is only printed if it has changed since \a now-1/total.
+    The output is followed by a carriage return, not a newline. */
+void announce_progress (int now, int total);
+//! Indicates progress by printing the percentage of \a now/total.
+/*! A message is only printed if it has changed since \a last/total.
+    The output is followed by a carriage return, not a newline. */
+void announce_progress (double now, double last, double total);
+/*! This function should be called after a sequence of announce_progress()
+    calls has finished. */
+void end_announce_progress ();
+
+//! Prints a banner containing \a name. Useful for displaying program names.
+void announce (const std::string &name);
+
+/*! Prints a banner containing \a name and checks if \a argc==argc_expected.
+    If not, a usage description is given and the program is terminated. */
+void module_startup (const std::string &name, int argc, const char **argv,
+  int argc_expected, const std::string &argv_expected);
+
+//! Returns an appropriate FITS repetition count for a map with \a npix pixels.
+inline unsigned int healpix_repcount (int npix)
+  {
+  if (npix<1024) return 1;
+  if ((npix%1024)==0) return 1024;
+  return isqrt (npix/12);
+  }
+#endif
diff --git a/src/Healpix_2.15a/datatypes.h b/src/Healpix_2.15a/datatypes.h
new file mode 100644
index 0000000..134bde4
--- /dev/null
+++ b/src/Healpix_2.15a/datatypes.h
@@ -0,0 +1,224 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*
+ *  This file defines various platform-independent data types.
+ *  If any of the requested types is not available, compilation aborts
+ *  with an error (unfortunately a rather obscure one).
+ *
+ *  Copyright (C) 2004 Max-Planck-Society
+ *  Author: Martin Reinecke
+ */
+
+#ifndef PLANCK_DATATYPES_H
+#define PLANCK_DATATYPES_H
+
+#include <string>
+#include "src/Healpix_2.15a/message_error.h"
+
+// Template magic to select the proper data types. These templates
+// should not be used outside this file.
+
+template <typename T, bool equalSize> struct sizeChooserHelper
+  { typedef void TYPE; };
+
+template <typename T> struct sizeChooserHelper<T,true>
+  { typedef T TYPE; };
+
+template <typename T1, typename T2, typename T3> struct sizeChooserHelper2
+  { typedef T1 TYPE; };
+
+template <typename T2, typename T3> struct sizeChooserHelper2 <void, T2, T3>
+  { typedef T2 TYPE; };
+
+template <typename T3> struct sizeChooserHelper2 <void, void, T3>
+  { typedef T3 TYPE; };
+
+template <> struct sizeChooserHelper2 <void, void, void>
+  { };
+
+template <int sz, typename T1, typename T2=char, typename T3=char>
+  struct sizeChooser
+  {
+  typedef typename sizeChooserHelper2
+    <typename sizeChooserHelper<T1,sizeof(T1)==sz>::TYPE,
+     typename sizeChooserHelper<T2,sizeof(T2)==sz>::TYPE,
+     typename sizeChooserHelper<T3,sizeof(T3)==sz>::TYPE >::TYPE TYPE;
+  };
+
+typedef signed char int8;
+typedef unsigned char uint8;
+
+typedef sizeChooser<2, short, int>::TYPE
+  int16;
+typedef sizeChooser<2, unsigned short, unsigned int>::TYPE
+  uint16;
+
+typedef sizeChooser<4, int, long, short>::TYPE
+  int32;
+typedef sizeChooser<4, unsigned int, unsigned long, unsigned short>::TYPE
+  uint32;
+
+typedef sizeChooser<8, long, long long>::TYPE
+  int64;
+typedef sizeChooser<8, unsigned long, unsigned long long>::TYPE
+  uint64;
+
+typedef sizeChooser<4, float, double>::TYPE
+  float32;
+typedef sizeChooser<8, double, long double>::TYPE
+  float64;
+
+// mapping of types to integer constants
+enum { PLANCK_INT8    =  0,
+       PLANCK_UINT8   =  1,
+       PLANCK_INT16   =  2,
+       PLANCK_UINT16  =  3,
+       PLANCK_INT32   =  4,
+       PLANCK_UINT32  =  5,
+       PLANCK_INT64   =  6,
+       PLANCK_UINT64  =  7,
+       PLANCK_FLOAT32 =  8,
+       PLANCK_FLOAT64 =  9,
+       PLANCK_BOOL    = 10,
+       PLANCK_STRING  = 11 };
+
+template<typename T> struct typehelper {};
+
+template<> struct typehelper<int8>
+  { enum { id=PLANCK_INT8 }; };
+template<> struct typehelper<uint8>
+  { enum { id=PLANCK_UINT8 }; };
+template<> struct typehelper<int16>
+  { enum { id=PLANCK_INT16 }; };
+template<> struct typehelper<uint16>
+  { enum { id=PLANCK_UINT16 }; };
+template<> struct typehelper<int32>
+  { enum { id=PLANCK_INT32 }; };
+template<> struct typehelper<uint32>
+  { enum { id=PLANCK_UINT32 }; };
+template<> struct typehelper<int64>
+  { enum { id=PLANCK_INT64 }; };
+template<> struct typehelper<uint64>
+  { enum { id=PLANCK_UINT64 }; };
+template<> struct typehelper<float32>
+  { enum { id=PLANCK_FLOAT32 }; };
+template<> struct typehelper<float64>
+  { enum { id=PLANCK_FLOAT64 }; };
+template<> struct typehelper<bool>
+  { enum { id=PLANCK_BOOL }; };
+template<> struct typehelper<std::string>
+  { enum { id=PLANCK_STRING }; };
+
+inline int type2size (int type)
+  {
+  switch (type)
+    {
+    case PLANCK_INT8   : return 1;
+    case PLANCK_UINT8  : return 1;
+    case PLANCK_INT16  : return 2;
+    case PLANCK_UINT16 : return 2;
+    case PLANCK_INT32  : return 4;
+    case PLANCK_UINT32 : return 4;
+    case PLANCK_INT64  : return 8;
+    case PLANCK_UINT64 : return 8;
+    case PLANCK_FLOAT32: return 4;
+    case PLANCK_FLOAT64: return 8;
+    case PLANCK_BOOL   : return 1;
+    case PLANCK_STRING : return 1;
+    default: throw Message_error ("unsupported data type");
+    }
+  }
+
+inline int string2type(const std::string &type)
+  {
+  if (type=="FLOAT64") return PLANCK_FLOAT64;
+  if (type=="FLOAT32") return PLANCK_FLOAT32;
+  if (type=="INT8")    return PLANCK_INT8;
+  if (type=="UINT8")   return PLANCK_UINT8;
+  if (type=="INT16")   return PLANCK_INT16;
+  if (type=="UINT16")  return PLANCK_UINT16;
+  if (type=="INT32")   return PLANCK_INT32;
+  if (type=="UINT32")  return PLANCK_UINT32;
+  if (type=="INT64")   return PLANCK_INT64;
+  if (type=="UINT64")  return PLANCK_UINT64;
+  if (type=="BOOL")    return PLANCK_BOOL;
+  if (type=="STRING")  return PLANCK_STRING;
+  throw Message_error ("unknown data type "+type);
+  }
+
+inline const char *type2string (int type)
+  {
+  switch (type)
+    {
+    case PLANCK_INT8   : return "INT8";
+    case PLANCK_UINT8  : return "UINT8";
+    case PLANCK_INT16  : return "INT16";
+    case PLANCK_UINT16 : return "UINT16";
+    case PLANCK_INT32  : return "INT32";
+    case PLANCK_UINT32 : return "UINT32";
+    case PLANCK_INT64  : return "INT64";
+    case PLANCK_UINT64 : return "UINT64";
+    case PLANCK_FLOAT32: return "FLOAT32";
+    case PLANCK_FLOAT64: return "FLOAT64";
+    case PLANCK_BOOL   : return "BOOL";
+    case PLANCK_STRING : return "STRING";
+    default: throw Message_error ("unsupported data type");
+    }
+  }
+
+template<typename T> inline const char *type2typename ()
+  { return "unknown type"; }
+template<> inline const char *type2typename<signed char> ()
+  { return "signed char"; }
+template<> inline const char *type2typename<unsigned char> ()
+  { return "unsigned char"; }
+template<> inline const char *type2typename<short> ()
+  { return "short"; }
+template<> inline const char *type2typename<unsigned short> ()
+  { return "unsigned short"; }
+template<> inline const char *type2typename<int> ()
+  { return "int"; }
+template<> inline const char *type2typename<unsigned int> ()
+  { return "unsigned int"; }
+template<> inline const char *type2typename<long> ()
+  { return "long"; }
+template<> inline const char *type2typename<unsigned long> ()
+  { return "unsigned long"; }
+template<> inline const char *type2typename<long long> ()
+  { return "long long"; }
+template<> inline const char *type2typename<unsigned long long> ()
+  { return "unsigned long long"; }
+template<> inline const char *type2typename<float> ()
+  { return "float"; }
+template<> inline const char *type2typename<double> ()
+  { return "double"; }
+template<> inline const char *type2typename<bool> ()
+  { return "bool"; }
+template<> inline const char *type2typename<std::string> ()
+  { return "std::string"; }
+
+#endif
diff --git a/src/Healpix_2.15a/geom_utils.h b/src/Healpix_2.15a/geom_utils.h
new file mode 100644
index 0000000..b3c96aa
--- /dev/null
+++ b/src/Healpix_2.15a/geom_utils.h
@@ -0,0 +1,64 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*! \file src/Healpix_2.15a/cxxsupport/geom_utils.h
+ *  Geometric utility functions.
+ *
+ *  Copyright (C) 2003, 2006 Max-Planck-Society
+ *  \author Martin Reinecke
+ *  \author Reinhard Hell
+ */
+
+#include "src/Healpix_2.15a/cxxutils.h"
+#include "src/Healpix_2.15a/vec3.h"
+
+/*! Returns the orientation when looking from point \a loc on the unit
+    sphere in the direction \a dir. \a loc must be normalized. The result
+    ranges from -pi to pi, is 0 for North and pi/2 for West, i.e. the angle
+    is given in mathematically positive sense.
+
+    If \a loc is the North or South pole, the returned angle is
+    \a atan2(dir.y,dir.x). */
+inline double orientation (const vec3 &loc, const vec3 &dir)
+  {
+// FIXME: here is still optimization potential
+  if (loc.x==0 && loc.y==0)
+    {
+    if (loc.z>0) return safe_atan2(dir.y,-dir.x);
+    else return safe_atan2(dir.y,dir.x);
+    }
+  vec3 east (-loc.y, loc.x, 0);
+  vec3 north = crossprod(loc,east);
+  double y = dotprod(dir,east);
+  double x = dotprod(dir,north);
+  return safe_atan2(-y,x);
+  }
+
+/*! Returns the angle between \a v1 and \a v2 in radians. */
+inline double v_angle (const vec3 &v1, const vec3 &v2)
+  {
+  return atan2 (crossprod(v1,v2).Length(), dotprod(v1,v2));
+  }
diff --git a/src/Healpix_2.15a/healpix_base.cc b/src/Healpix_2.15a/healpix_base.cc
new file mode 100644
index 0000000..91c594d
--- /dev/null
+++ b/src/Healpix_2.15a/healpix_base.cc
@@ -0,0 +1,784 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*
+ *  Copyright (C) 2003, 2004, 2005, 2006 Max-Planck-Society
+ *  Author: Martin Reinecke
+ */
+
+#include "src/Healpix_2.15a/healpix_base.h"
+#include "src/Healpix_2.15a/cxxutils.h"
+#include "src/Healpix_2.15a/pointing.h"
+#include "src/Healpix_2.15a/arr.h"
+#include "src/Healpix_2.15a/geom_utils.h"
+
+using namespace std;
+
+short Healpix_Base::ctab[];
+short Healpix_Base::utab[];
+
+const nside_dummy SET_NSIDE=nside_dummy();
+
+Healpix_Base::Tablefiller::Tablefiller()
+  {
+  for (int m=0; m<0x100; ++m)
+    {
+    ctab[m] =
+         (m&0x1 )       | ((m&0x2 ) << 7) | ((m&0x4 ) >> 1) | ((m&0x8 ) << 6)
+      | ((m&0x10) >> 2) | ((m&0x20) << 5) | ((m&0x40) >> 3) | ((m&0x80) << 4);
+    utab[m] =
+         (m&0x1 )       | ((m&0x2 ) << 1) | ((m&0x4 ) << 2) | ((m&0x8 ) << 3)
+      | ((m&0x10) << 4) | ((m&0x20) << 5) | ((m&0x40) << 6) | ((m&0x80) << 7);
+    }
+  }
+
+Healpix_Base::Tablefiller Healpix_Base::Filler;
+
+const int Healpix_Base::jrll[] = { 2,2,2,2,3,3,3,3,4,4,4,4 };
+const int Healpix_Base::jpll[] = { 1,3,5,7,0,2,4,6,1,3,5,7 };
+
+int Healpix_Base::npix2nside (int npix)
+  {
+  int res=isqrt(npix/12);
+  planck_assert (npix==res*res*12, "npix2nside: invalid argument");
+  return res;
+  }
+
+int Healpix_Base::ring_above (double z) const
+  {
+  double az=abs(z);
+  if (az>twothird) // polar caps
+    {
+    int iring = int(nside_*sqrt(3*(1-az)));
+    return (z>0) ? iring : 4*nside_-iring-1;
+    }
+  else // ----- equatorial region ---------
+    return int(nside_*(2-1.5*z));
+  }
+
+void Healpix_Base::in_ring(int iz, double phi0, double dphi,
+  vector<int> &listir) const
+  {
+  int nr, ir, ipix1;
+  double shift=0.5;
+
+  if (iz<nside_) // north pole
+    {
+    ir = iz;
+    nr = ir*4;
+    ipix1 = 2*ir*(ir-1);        //    lowest pixel number in the ring
+    }
+  else if (iz>(3*nside_)) // south pole
+    {
+    ir = 4*nside_ - iz;
+    nr = ir*4;
+    ipix1 = npix_ - 2*ir*(ir+1); // lowest pixel number in the ring
+    }
+  else // equatorial region
+    {
+    ir = iz - nside_ + 1;           //    within {1, 2*nside + 1}
+    nr = nside_*4;
+    if ((ir&1)==0) shift = 0;
+    ipix1 = ncap_ + (ir-1)*nr; // lowest pixel number in the ring
+    }
+
+  int ipix2 = ipix1 + nr - 1;       //    highest pixel number in the ring
+
+   // ----------- constructs the pixel list --------------
+  if (dphi > (pi-1e-7))
+    for (int i=ipix1; i<=ipix2; ++i) listir.push_back(i);
+  else
+    {
+    int ip_lo = ifloor<int>(nr*inv_twopi*(phi0-dphi) - shift)+1;
+    int ip_hi = ifloor<int>(nr*inv_twopi*(phi0+dphi) - shift);
+    int pixnum = ip_lo+ipix1;
+    if (pixnum<ipix1) pixnum += nr;
+    for (int i=ip_lo; i<=ip_hi; ++i, ++pixnum)
+      {
+      if (pixnum>ipix2) pixnum -= nr;
+      listir.push_back(pixnum);
+      }
+    }
+  }
+
+void Healpix_Base::nest2xyf (int pix, int &ix, int &iy, int &face_num) const
+  {
+  face_num = pix>>(2*order_);
+  pix &= (npface_-1);
+  int raw = (pix&0x5555) | ((pix&0x55550000)>>15);
+  ix = ctab[raw&0xff] | (ctab[raw>>8]<<4);
+  pix >>= 1;
+  raw = (pix&0x5555) | ((pix&0x55550000)>>15);
+  iy = ctab[raw&0xff] | (ctab[raw>>8]<<4);
+  }
+
+int Healpix_Base::xyf2nest (int ix, int iy, int face_num) const
+  {
+  return (face_num<<(2*order_)) +
+      (utab[ix&0xff] | (utab[ix>>8]<<16)
+    | (utab[iy&0xff]<<1) | (utab[iy>>8]<<17));
+  }
+
+void Healpix_Base::ring2xyf (int pix, int &ix, int &iy, int &face_num) const
+  {
+  int iring, iphi, kshift, nr;
+
+  int nl2 = 2*nside_;
+
+  if (pix<ncap_) // North Polar cap
+    {
+    iring = int(0.5*(1+isqrt(1+2*pix))); //counted from North pole
+    iphi  = (pix+1) - 2*iring*(iring-1);
+    kshift = 0;
+    nr = iring;
+    face_num=0;
+    int tmp = iphi-1;
+    if (tmp>=(2*iring))
+      {
+      face_num=2;
+      tmp-=2*iring;
+      }
+    if (tmp>=iring) ++face_num;
+    }
+  else if (pix<(npix_-ncap_)) // Equatorial region
+    {
+    int ip = pix - ncap_;
+    if (order_>=0)
+      {
+      iring = (ip>>(order_+2)) + nside_; // counted from North pole
+      iphi  = (ip&(4*nside_-1)) + 1;
+      }
+    else
+      {
+      iring = (ip/(4*nside_)) + nside_; // counted from North pole
+      iphi  = (ip%(4*nside_)) + 1;
+      }
+    kshift = (iring+nside_)&1;
+    nr = nside_;
+    unsigned int ire = iring-nside_+1;
+    unsigned int irm = nl2+2-ire;
+    int ifm, ifp;
+    if (order_>=0)
+      {
+      ifm = (iphi - ire/2 + nside_ -1) >> order_;
+      ifp = (iphi - irm/2 + nside_ -1) >> order_;
+      }
+    else
+      {
+      ifm = (iphi - ire/2 + nside_ -1) / nside_;
+      ifp = (iphi - irm/2 + nside_ -1) / nside_;
+      }
+    if (ifp == ifm) // faces 4 to 7
+      face_num = (ifp==4) ? 4 : ifp+4;
+    else if (ifp<ifm) // (half-)faces 0 to 3
+      face_num = ifp;
+    else // (half-)faces 8 to 11
+      face_num = ifm + 8;
+    }
+  else // South Polar cap
+    {
+    int ip = npix_ - pix;
+    iring = int(0.5*(1+isqrt(2*ip-1))); //counted from South pole
+    iphi  = 4*iring + 1 - (ip - 2*iring*(iring-1));
+    kshift = 0;
+    nr = iring;
+    iring = 2*nl2-iring;
+    face_num=8;
+    int tmp = iphi-1;
+    if (tmp>=(2*nr))
+      {
+      face_num=10;
+      tmp-=2*nr;
+      }
+    if (tmp>=nr) ++face_num;
+    }
+
+  int irt = iring - (jrll[face_num]*nside_) + 1;
+  int ipt = 2*iphi- jpll[face_num]*nr - kshift -1;
+  if (ipt>=nl2) ipt-=8*nside_;
+
+  ix =  (ipt-irt) >>1;
+  iy =(-(ipt+irt))>>1;
+  }
+
+int Healpix_Base::xyf2ring (int ix, int iy, int face_num) const
+  {
+  int nl4 = 4*nside_;
+  int jr = (jrll[face_num]*nside_) - ix - iy  - 1;
+
+  int nr, kshift, n_before;
+  if (jr<nside_)
+    {
+    nr = jr;
+    n_before = 2*nr*(nr-1);
+    kshift = 0;
+    }
+  else if (jr > 3*nside_)
+    {
+    nr = nl4-jr;
+    n_before = npix_ - 2*(nr+1)*nr;
+    kshift = 0;
+    }
+  else
+    {
+    nr = nside_;
+    n_before = ncap_ + (jr-nside_)*nl4;
+    kshift = (jr-nside_)&1;
+    }
+
+  int jp = (jpll[face_num]*nr + ix - iy + 1 + kshift) / 2;
+  if (jp>nl4)
+    jp-=nl4;
+  else
+    if (jp<1) jp+=nl4;
+
+  return n_before + jp - 1;
+  }
+
+double Healpix_Base::ring2z (int ring) const
+  {
+  if (ring<nside_)
+    return 1 - ring*ring*fact2_;
+  if (ring <=3*nside_)
+    return (2*nside_-ring)*fact1_;
+  ring=4*nside_ - ring;
+  return ring*ring*fact2_ - 1;
+  }
+
+int Healpix_Base::pix2ring (int pix) const
+  {
+  if (scheme_==RING)
+    {
+    if (pix<ncap_) // North Polar cap
+      return int(0.5*(1+isqrt(1+2*pix))); //counted from North pole
+    else if (pix<(npix_-ncap_)) // Equatorial region
+      {
+      int ip  = pix - ncap_;
+      return ip/(4*nside_) + nside_; // counted from North pole
+      }
+    else // South Polar cap
+      {
+      int ip = npix_ - pix;
+      return 4*nside_ - int(0.5*(1+isqrt(2*ip-1))); //counted from South pole
+      }
+    }
+  else
+    {
+    int face_num, ix, iy;
+    nest2xyf(pix,ix,iy,face_num);
+    return (jrll[face_num]<<order_) - ix - iy - 1;
+    }
+  }
+
+int Healpix_Base::nest2ring (int pix) const
+  {
+  planck_assert(order_>=0, "nest2ring: need hierarchical map");
+  int ix, iy, face_num;
+  nest2xyf (pix, ix, iy, face_num);
+  return xyf2ring (ix, iy, face_num);
+  }
+
+int Healpix_Base::ring2nest (int pix) const
+  {
+  planck_assert(order_>=0, "ring2nest: need hierarchical map");
+  int ix, iy, face_num;
+  ring2xyf (pix, ix, iy, face_num);
+  return xyf2nest (ix, iy, face_num);
+  }
+
+int Healpix_Base::nest2peano (int pix) const
+  {
+  static const unsigned char subpix[8][4] = {
+    { 0, 1, 3, 2 }, { 3, 0, 2, 1 }, { 2, 3, 1, 0 }, { 1, 2, 0, 3 },
+    { 0, 3, 1, 2 }, { 1, 0, 2, 3 }, { 2, 1, 3, 0 }, { 3, 2, 0, 1 } };
+  const unsigned char subpath[8][4] = {
+    { 4, 0, 6, 0 }, { 7, 5, 1, 1 }, { 2, 4, 2, 6 }, { 3, 3, 7, 5 },
+    { 0, 2, 4, 4 }, { 5, 1, 5, 3 }, { 6, 6, 0, 2 }, { 1, 7, 3, 7 } };
+  static const unsigned char face2path[12] = {
+    2, 5, 2, 5, 3, 6, 3, 6, 2, 3, 2, 3 };
+  static const unsigned char face2peanoface[12] = {
+    0, 5, 6, 11, 10, 1, 4, 7, 2, 3, 8, 9 };
+
+  int face = pix>>(2*order_);
+  unsigned char path = face2path[face];
+  int result = 0;
+
+  for (int shift=2*order_-2; shift>=0; shift-=2)
+    {
+    unsigned char spix = (pix>>shift) & 0x3;
+    result <<= 2;
+    result |= subpix[path][spix];
+    path=subpath[path][spix];
+    }
+
+  return result + (int(face2peanoface[face])<<(2*order_));
+  }
+
+int Healpix_Base::peano2nest (int pix) const
+  {
+  static const unsigned char subpix[8][4] = {
+    { 0, 1, 3, 2 }, { 1, 3, 2, 0 }, { 3, 2, 0, 1 }, { 2, 0, 1, 3 },
+    { 0, 2, 3, 1 }, { 1, 0, 2, 3 }, { 3, 1, 0, 2 }, { 2, 3, 1, 0 } };
+  static const unsigned char subpath[8][4] = {
+    { 4, 0, 0, 6 }, { 5, 1, 1, 7 }, { 6, 2, 2, 4 }, { 7, 3, 3, 5 },
+    { 0, 4, 4, 2 }, { 1, 5, 5, 3 }, { 2, 6, 6, 0 }, { 3, 7, 7, 1 } };
+  static const unsigned char face2path[12] = {
+    2, 6, 2, 3, 3, 5, 2, 6, 2, 3, 3, 5 };
+  static const unsigned char peanoface2face[12] = {
+    0, 5, 8, 9, 6, 1, 2, 7, 10, 11, 4, 3 };
+
+  int face = pix>>(2*order_);
+  unsigned char path = face2path[face];
+  int result = 0;
+
+  for (int shift=2*order_-2; shift>=0; shift-=2)
+    {
+    unsigned char spix = (pix>>shift) & 0x3;
+    result <<= 2;
+    result |= subpix[path][spix];
+    path=subpath[path][spix];
+    }
+
+  return result + (int(peanoface2face[face])<<(2*order_));
+  }
+
+int Healpix_Base::ang2pix_z_phi (double z, double phi) const
+  {
+  double za = abs(z);
+  double tt = fmodulo(phi,twopi) * inv_halfpi; // in [0,4)
+
+  if (scheme_==RING)
+    {
+    if (za<=twothird) // Equatorial region
+      {
+      double temp1 = nside_*(0.5+tt);
+      double temp2 = nside_*z*0.75;
+      int jp = int(temp1-temp2); // index of  ascending edge line
+      int jm = int(temp1+temp2); // index of descending edge line
+
+      // ring number counted from z=2/3
+      int ir = nside_ + 1 + jp - jm; // in {1,2n+1}
+      int kshift = 1-(ir&1); // kshift=1 if ir even, 0 otherwise
+
+      int ip = (jp+jm-nside_+kshift+1)/2; // in {0,4n-1}
+      ip = imodulo(ip,4*nside_);
+
+      return ncap_ + (ir-1)*4*nside_ + ip;
+      }
+    else  // North & South polar caps
+      {
+      double tp = tt-int(tt);
+      double tmp = nside_*sqrt(3*(1-za));
+
+      int jp = int(tp*tmp); // increasing edge line index
+      int jm = int((1.0-tp)*tmp); // decreasing edge line index
+
+      int ir = jp+jm+1; // ring number counted from the closest pole
+      int ip = int(tt*ir); // in {0,4*ir-1}
+      ip = imodulo(ip,4*ir);
+
+      if (z>0)
+        return 2*ir*(ir-1) + ip;
+      else
+        return npix_ - 2*ir*(ir+1) + ip;
+      }
+    }
+  else // scheme_ == NEST
+    {
+    int face_num, ix, iy;
+
+    if (za<=twothird) // Equatorial region
+      {
+      double temp1 = nside_*(0.5+tt);
+      double temp2 = nside_*(z*0.75);
+      int jp = int(temp1-temp2); // index of  ascending edge line
+      int jm = int(temp1+temp2); // index of descending edge line
+      int ifp = jp >> order_;  // in {0,4}
+      int ifm = jm >> order_;
+      if (ifp == ifm)           // faces 4 to 7
+        face_num = (ifp==4) ? 4: ifp+4;
+      else if (ifp < ifm)       // (half-)faces 0 to 3
+        face_num = ifp;
+      else                      // (half-)faces 8 to 11
+        face_num = ifm + 8;
+
+      ix = jm & (nside_-1);
+      iy = nside_ - (jp & (nside_-1)) - 1;
+      }
+    else // polar region, za > 2/3
+      {
+      int ntt = int(tt);
+      if (ntt>=4) ntt=3;
+      double tp = tt-ntt;
+      double tmp = nside_*sqrt(3*(1-za));
+
+      int jp = int(tp*tmp); // increasing edge line index
+      int jm = int((1.0-tp)*tmp); // decreasing edge line index
+      if (jp>=nside_) jp = nside_-1; // for points too close to the boundary
+      if (jm>=nside_) jm = nside_-1;
+      if (z >= 0)
+        {
+        face_num = ntt;  // in {0,3}
+        ix = nside_ - jm - 1;
+        iy = nside_ - jp - 1;
+        }
+      else
+        {
+        face_num = ntt + 8; // in {8,11}
+        ix =  jp;
+        iy =  jm;
+        }
+      }
+
+    return xyf2nest(ix,iy,face_num);
+    }
+  }
+
+void Healpix_Base::pix2ang_z_phi (int pix, double &z, double &phi) const
+  {
+  if (scheme_==RING)
+    {
+    if (pix<ncap_) // North Polar cap
+      {
+      int iring = int(0.5*(1+isqrt(1+2*pix))); //counted from North pole
+      int iphi  = (pix+1) - 2*iring*(iring-1);
+
+      z = 1.0 - (iring*iring)*fact2_;
+      phi = (iphi-0.5) * halfpi/iring;
+      }
+    else if (pix<(npix_-ncap_)) // Equatorial region
+      {
+      int ip  = pix - ncap_;
+      int iring = ip/(4*nside_) + nside_; // counted from North pole
+      int iphi  = ip%(4*nside_) + 1;
+      // 1 if iring+nside is odd, 1/2 otherwise
+      double fodd = ((iring+nside_)&1) ? 1 : 0.5;
+
+      int nl2 = 2*nside_;
+      z = (nl2-iring)*fact1_;
+      phi = (iphi-fodd) * pi/nl2;
+      }
+    else // South Polar cap
+      {
+      int ip = npix_ - pix;
+      int iring = int(0.5*(1+isqrt(2*ip-1))); //counted from South pole
+      int iphi  = 4*iring + 1 - (ip - 2*iring*(iring-1));
+
+      z = -1.0 + (iring*iring)*fact2_;
+      phi = (iphi-0.5) * halfpi/iring;
+      }
+    }
+  else
+    {
+    int nl4 = nside_*4;
+
+    int face_num, ix, iy;
+    nest2xyf(pix,ix,iy,face_num);
+
+    int jr = (jrll[face_num]<<order_) - ix - iy - 1;
+
+    int nr, kshift;
+    if (jr<nside_)
+      {
+      nr = jr;
+      z = 1 - nr*nr*fact2_;
+      kshift = 0;
+      }
+    else if (jr > 3*nside_)
+      {
+      nr = nl4-jr;
+      z = nr*nr*fact2_ - 1;
+      kshift = 0;
+      }
+    else
+      {
+      nr = nside_;
+      z = (2*nside_-jr)*fact1_;
+      kshift = (jr-nside_)&1;
+      }
+
+    int jp = (jpll[face_num]*nr + ix -iy + 1 + kshift) / 2;
+    if (jp>nl4) jp-=nl4;
+    if (jp<1) jp+=nl4;
+
+    phi = (jp-(kshift+1)*0.5)*(halfpi/nr);
+    }
+  }
+
+void Healpix_Base::query_disc (const pointing &ptg, double radius,
+  vector<int>& listpix) const
+  {
+  listpix.clear();
+
+  double dth1 = fact2_;
+  double dth2 = fact1_;
+  double cosang = cos(radius);
+
+  double z0 = cos(ptg.theta);
+  double xa = 1./sqrt((1-z0)*(1+z0));
+
+  double rlat1  = ptg.theta - radius;
+  double zmax = cos(rlat1);
+  int irmin = ring_above (zmax)+1;
+
+  if (rlat1<=0) // north pole in the disc
+    for (int m=1; m<irmin; ++m) // rings completely in the disc
+      in_ring (m, 0, pi, listpix);
+
+  double rlat2  = ptg.theta + radius;
+  double zmin = cos(rlat2);
+  int irmax = ring_above (zmin);
+
+// ------------- loop on ring number ---------------------
+  for (int iz=irmin; iz<=irmax; ++iz) // rings partially in the disc
+    {
+    double z;
+    if (iz<nside_) // north polar cap
+      z = 1.0 - iz*iz*dth1;
+    else if (iz <= (3*nside_)) // tropical band + equat.
+      z = (2*nside_-iz) * dth2;
+    else
+      z = -1.0 + (4*nside_-iz)*(4*nside_-iz)*dth1;
+
+// --------- phi range in the disc for each z ---------
+    double x = (cosang-z*z0)*xa;
+    double ysq = 1-z*z-x*x;
+    planck_assert(ysq>=0, "error in query_disc()");
+    double dphi=atan2(sqrt(ysq),x);
+    in_ring (iz, ptg.phi, dphi, listpix);
+    }
+
+  if (rlat2>=pi) // south pole in the disc
+    for (int m=irmax+1; m<(4*nside_); ++m)  // rings completely in the disc
+      in_ring (m, 0, pi, listpix);
+
+  if (scheme_==NEST)
+    for (unsigned int m=0; m<listpix.size(); ++m)
+      listpix[m] = ring2nest(listpix[m]);
+  }
+
+void Healpix_Base::get_ring_info (int ring, int &startpix, int &ringpix,
+  double &costheta, double &sintheta, bool &shifted) const
+  {
+  planck_assert(scheme_==RING,"map must be in RING scheme");
+  int northring = (ring>2*nside_) ? 4*nside_-ring : ring;
+  if (northring < nside_)
+    {
+    double tmp = northring*northring*fact2_;
+    costheta = 1 - tmp;
+    sintheta = sqrt(tmp*(2-tmp));
+    ringpix = 4*northring;
+    shifted = true;
+    startpix = 2*northring*(northring-1);
+    }
+  else
+    {
+    costheta = (2*nside_-northring)*fact1_;
+    sintheta = sqrt((1+costheta)*(1-costheta));
+    ringpix = 4*nside_;
+    shifted = ((northring-nside_) & 1) == 0;
+    startpix = ncap_ + (northring-nside_)*ringpix;
+    }
+  if (northring != ring) // southern hemisphere
+    {
+    costheta = -costheta;
+    startpix = npix_ - startpix - ringpix;
+    }
+  }
+
+void Healpix_Base::neighbors (int pix, fix_arr<int,8> &result) const
+  {
+  static const int xoffset[] = { -1,-1, 0, 1, 1, 1, 0,-1 };
+  static const int yoffset[] = {  0, 1, 1, 1, 0,-1,-1,-1 };
+  static const int facearray[][12] =
+        { {  8, 9,10,11,-1,-1,-1,-1,10,11, 8, 9 },   // S
+          {  5, 6, 7, 4, 8, 9,10,11, 9,10,11, 8 },   // SE
+          { -1,-1,-1,-1, 5, 6, 7, 4,-1,-1,-1,-1 },   // E
+          {  4, 5, 6, 7,11, 8, 9,10,11, 8, 9,10 },   // SW
+          {  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11 },   // center
+          {  1, 2, 3, 0, 0, 1, 2, 3, 5, 6, 7, 4 },   // NE
+          { -1,-1,-1,-1, 7, 4, 5, 6,-1,-1,-1,-1 },   // W
+          {  3, 0, 1, 2, 3, 0, 1, 2, 4, 5, 6, 7 },   // NW
+          {  2, 3, 0, 1,-1,-1,-1,-1, 0, 1, 2, 3 } }; // N
+  static const int swaparray[][12] =
+        { {  0,0,0,0,0,0,0,0,3,3,3,3 },   // S
+          {  0,0,0,0,0,0,0,0,6,6,6,6 },   // SE
+          {  0,0,0,0,0,0,0,0,0,0,0,0 },   // E
+          {  0,0,0,0,0,0,0,0,5,5,5,5 },   // SW
+          {  0,0,0,0,0,0,0,0,0,0,0,0 },   // center
+          {  5,5,5,5,0,0,0,0,0,0,0,0 },   // NE
+          {  0,0,0,0,0,0,0,0,0,0,0,0 },   // W
+          {  6,6,6,6,0,0,0,0,0,0,0,0 },   // NW
+          {  3,3,3,3,0,0,0,0,0,0,0,0 } }; // N
+
+  int ix, iy, face_num;
+  (scheme_==RING) ?
+    ring2xyf(pix,ix,iy,face_num) : nest2xyf(pix,ix,iy,face_num);
+
+  const int nsm1 = nside_-1;
+  if ((ix>0)&&(ix<nsm1)&&(iy>0)&&(iy<nsm1))
+    {
+    if (scheme_==RING)
+      for (int m=0; m<8; ++m)
+        result[m] = xyf2ring(ix+xoffset[m],iy+yoffset[m],face_num);
+    else
+      for (int m=0; m<8; ++m)
+        result[m] = xyf2nest(ix+xoffset[m],iy+yoffset[m],face_num);
+    }
+  else
+    {
+    for (int i=0; i<8; ++i)
+      {
+      int x=ix+xoffset[i];
+      int y=iy+yoffset[i];
+      int nbnum=4;
+      if (x<0)
+        { x+=nside_; nbnum-=1; }
+      else if (x>=nside_)
+        { x-=nside_; nbnum+=1; }
+      if (y<0)
+        { y+=nside_; nbnum-=3; }
+      else if (y>=nside_)
+        { y-=nside_; nbnum+=3; }
+
+      int f = facearray[nbnum][face_num];
+      if (f>=0)
+        {
+        if (swaparray[nbnum][face_num]&1) x=nside_-x-1;
+        if (swaparray[nbnum][face_num]&2) y=nside_-y-1;
+        if (swaparray[nbnum][face_num]&4) std::swap(x,y);
+        result[i] = (scheme_==RING) ? xyf2ring(x,y,f) : xyf2nest(x,y,f);
+        }
+      else
+        result[i] = -1;
+      }
+    }
+  }
+
+void Healpix_Base::get_ring_info2 (int ring, int &startpix, int &ringpix,
+  double &theta, bool &shifted) const
+  {
+  int northring = (ring>2*nside_) ? 4*nside_-ring : ring;
+  if (northring < nside_)
+    {
+    double tmp = northring*northring*fact2_;
+    double costheta = 1 - tmp;
+    double sintheta = sqrt(tmp*(2-tmp));
+    theta = atan2(sintheta,costheta);
+    ringpix = 4*northring;
+    shifted = true;
+    startpix = 2*northring*(northring-1);
+    }
+  else
+    {
+    theta = acos((2*nside_-northring)*fact1_);
+    ringpix = 4*nside_;
+    shifted = ((northring-nside_) & 1) == 0;
+    startpix = ncap_ + (northring-nside_)*ringpix;
+    }
+  if (northring != ring) // southern hemisphere
+    {
+    theta = pi-theta;
+    startpix = npix_ - startpix - ringpix;
+    }
+  }
+
+void Healpix_Base::get_interpol (const pointing &ptg, fix_arr<int,4> &pix,
+  fix_arr<double,4> &wgt) const
+  {
+  double z = cos (ptg.theta);
+  int ir1 = ring_above(z);
+  int ir2 = ir1+1;
+  double theta1, theta2, w1, tmp, dphi;
+  int sp,nr;
+  bool shift;
+  int i1,i2;
+  if (ir1>0)
+    {
+    get_ring_info2 (ir1, sp, nr, theta1, shift);
+    dphi = twopi/nr;
+    tmp = (ptg.phi/dphi - .5*shift);
+    i1 = (tmp<0) ? int(tmp)-1 : int(tmp);
+    w1 = (ptg.phi-(i1+.5*shift)*dphi)/dphi;
+    i2 = i1+1;
+    if (i1<0) i1 +=nr;
+    if (i2>=nr) i2 -=nr;
+    pix[0] = sp+i1; pix[1] = sp+i2;
+    wgt[0] = 1-w1; wgt[1] = w1;
+    }
+  if (ir2<(4*nside_))
+    {
+    get_ring_info2 (ir2, sp, nr, theta2, shift);
+    dphi = twopi/nr;
+    tmp = (ptg.phi/dphi - .5*shift);
+    i1 = (tmp<0) ? int(tmp)-1 : int(tmp);
+    w1 = (ptg.phi-(i1+.5*shift)*dphi)/dphi;
+    i2 = i1+1;
+    if (i1<0) i1 +=nr;
+    if (i2>=nr) i2 -=nr;
+    pix[2] = sp+i1; pix[3] = sp+i2;
+    wgt[2] = 1-w1; wgt[3] = w1;
+    }
+
+  if (ir1==0)
+    {
+    double wtheta = ptg.theta/theta2;
+    wgt[2] *= wtheta; wgt[3] *= wtheta;
+    double fac = (1-wtheta)*0.25;
+    wgt[0] = fac; wgt[1] = fac; wgt[2] += fac; wgt[3] +=fac;
+    pix[0] = (pix[2]+2)%4;
+    pix[1] = (pix[3]+2)%4;
+    }
+  else if (ir2==4*nside_)
+    {
+    double wtheta = (ptg.theta-theta1)/(pi-theta1);
+    wgt[0] *= (1-wtheta); wgt[1] *= (1-wtheta);
+    double fac = wtheta*0.25;
+    wgt[0] += fac; wgt[1] += fac; wgt[2] = fac; wgt[3] =fac;
+    pix[2] = ((pix[0]+2)&3)+npix_-4;
+    pix[3] = ((pix[1]+2)&3)+npix_-4;
+    }
+  else
+    {
+    double wtheta = (ptg.theta-theta1)/(theta2-theta1);
+    wgt[0] *= (1-wtheta); wgt[1] *= (1-wtheta);
+    wgt[2] *= wtheta; wgt[3] *= wtheta;
+    }
+
+  if (scheme_==NEST)
+    for (int m=0; m<pix.size(); ++m)
+      pix[m] = ring2nest(pix[m]);
+  }
+
+double Healpix_Base::max_pixrad() const
+  {
+  vec3 va,vb;
+  va.set_z_phi (2./3., pi/(4*nside_));
+  double t1 = 1.-1./nside_;
+  t1*=t1;
+  vb.set_z_phi (1-t1/3, 0);
+  return v_angle(va,vb);
+  }
diff --git a/src/Healpix_2.15a/healpix_base.h b/src/Healpix_2.15a/healpix_base.h
new file mode 100644
index 0000000..4cd04b4
--- /dev/null
+++ b/src/Healpix_2.15a/healpix_base.h
@@ -0,0 +1,285 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*! \file src/Healpix_2.15a/Healpix_cxx/healpix_base.h
+ *  Copyright (C) 2003, 2004, 2005, 2006 Max-Planck-Society
+ *  \author Martin Reinecke
+ */
+
+#ifndef HEALPIX_BASE_H
+#define HEALPIX_BASE_H
+
+#include <vector>
+#include "src/Healpix_2.15a/cxxutils.h"
+#include "src/Healpix_2.15a/lsconstants.h"
+#include "src/Healpix_2.15a/pointing.h"
+template<typename T, unsigned int sz> class fix_arr;
+
+/*! The two possible ordering schemes of a HEALPix map. */
+typedef enum { RING, /*!< RING scheme */
+               NEST  /*!< NESTED scheme */
+             }  Healpix_Ordering_Scheme;
+
+class nside_dummy {};
+extern const nside_dummy SET_NSIDE;
+
+/*! Functionality related to the HEALPix pixelisation. */
+class Healpix_Base
+  {
+  protected:
+    enum { order_max=13 };
+
+    class Tablefiller
+      {
+      public:
+        Tablefiller();
+      };
+    static Tablefiller Filler;
+    friend class Tablefiller;
+
+    static short ctab[0x100], utab[0x100];
+
+    static const int jrll[];
+    static const int jpll[];
+
+    /*! The order of the map; -1 for nonhierarchical map. */
+    int order_;
+    /*! The N_side parameter of the map; 0 if not allocated. */
+    int nside_;
+    int npface_, ncap_, npix_;
+    double fact1_, fact2_;
+    /*! The map's ordering scheme. */
+    Healpix_Ordering_Scheme scheme_;
+
+    inline int ring_above (double z) const;
+    void in_ring (int iz, double phi0, double dphi,
+      std::vector<int> &listir) const;
+
+    typedef int (Healpix_Base::*swapfunc)(int pix) const;
+    typedef void (Healpix_Base::*pix2xyf)
+                 (int pix, int &x, int &y, int &f) const;
+    typedef int (Healpix_Base::*xyf2pix) (int x, int y, int f) const;
+
+  public:
+
+    // Sjors 18nov2010: moved these from protected to public
+    int xyf2nest(int ix, int iy, int face_num) const;
+    void nest2xyf(int pix, int &ix, int &iy, int &face_num) const;
+    int xyf2ring(int ix, int iy, int face_num) const;
+    void ring2xyf(int pix, int &ix, int &iy, int &face_num) const;
+
+    /*! Calculates the map order from its \a N_side parameter.
+        Returns -1 if \a nside is not a power of 2.
+        \param nside the \a N_side parameter */
+    static int nside2order (int nside)
+      {
+      planck_assert (nside>0, "invalid value for Nside");
+      if ((nside)&(nside-1)) return -1;
+      return ilog2(nside);
+      }
+    /*! Calculates the \a N_side parameter from the number of pixels.
+        \param npix the number of pixels */
+    static int npix2nside (int npix);
+    /*! Constructs an unallocated object. */
+    Healpix_Base ()
+      : order_(-1), nside_(0), npface_(0), ncap_(0), npix_(0),
+        fact1_(0), fact2_(0), scheme_(RING) {}
+    /*! Constructs an object with a given \a order and the ordering
+        scheme \a scheme. */
+    Healpix_Base (int order, Healpix_Ordering_Scheme scheme)
+      { Set (order, scheme); }
+    /*! Constructs an object with a given \a nside and the ordering
+        scheme \a scheme. The \a nside_dummy parameter must be set to
+        SET_NSIDE. */
+    Healpix_Base (int nside, Healpix_Ordering_Scheme scheme, const nside_dummy)
+      { SetNside (nside, scheme); }
+
+    /* Adjusts the object to \a order and \a scheme. */
+    void Set (int order, Healpix_Ordering_Scheme scheme)
+      {
+      planck_assert ((order>=0)&&(order<=order_max), "bad order");
+      order_  = order;
+      nside_  = 1<<order;
+      npface_ = nside_<<order_;
+      ncap_   = (npface_-nside_)<<1;
+      npix_   = 12*npface_;
+      fact2_  = 4./npix_;
+      fact1_  = (nside_<<1)*fact2_;
+      scheme_ = scheme;
+      }
+    /* Adjusts the object to \a nside and \a scheme. */
+    void SetNside (int nside, Healpix_Ordering_Scheme scheme)
+      {
+      order_  = nside2order(nside);
+      planck_assert ((scheme!=NEST) || (order_>=0),
+        "SetNside: nside must be power of 2 for nested maps");
+      nside_  = nside;
+      npface_ = nside_*nside_;
+      ncap_   = (npface_-nside_)<<1;
+      npix_   = 12*npface_;
+      fact2_  = 4./npix_;
+      fact1_  = (nside_<<1)*fact2_;
+      scheme_ = scheme;
+      }
+
+    /*! Returns the z-coordinate of the ring \a ring. This also works
+        for the (not really existing) rings 0 and 4*nside. */
+    double ring2z (int ring) const;
+    /*! Returns the number of the ring in which \a pix lies. */
+    int pix2ring (int pix) const;
+
+    /*! Translates a pixel number from NEST to RING. */
+    int nest2ring (int pix) const;
+    /*! Translates a pixel number from RING to NEST. */
+    int ring2nest (int pix) const;
+    /*! Translates a pixel number from NEST to its Peano index. */
+    int nest2peano (int pix) const;
+    /*! Translates a pixel number from its Peano index to NEST. */
+    int peano2nest (int pix) const;
+
+    int ang2pix_z_phi (double z, double phi) const;
+
+    /*! Returns the number of the pixel which contains the angular coordinates
+        \a ang. */
+    int ang2pix (const pointing &ang) const
+      { return ang2pix_z_phi (cos(ang.theta), ang.phi); }
+    /*! Returns the number of the pixel which contains the vector \a vec
+        (\a vec is normalized if necessary). */
+    int vec2pix (const vec3 &vec) const
+      { return ang2pix_z_phi (vec.z/vec.Length(), safe_atan2(vec.y,vec.x)); }
+
+    void pix2ang_z_phi (int pix, double &z, double &phi) const;
+
+    /*! Returns the angular coordinates of the center of the pixel with
+        number \a pix. */
+    pointing pix2ang (int pix) const
+      {
+      double z, phi;
+      pix2ang_z_phi (pix,z,phi);
+      return pointing(acos(z),phi);
+      }
+    /*! Returns the vector to the center of the pixel with number \a pix. */
+    vec3 pix2vec (int pix) const
+      {
+      double z, phi;
+      pix2ang_z_phi (pix,z,phi);
+      vec3 res;
+      res.set_z_phi (z, phi);
+      return res;
+      }
+
+    /*! Returns the numbers of all pixels whose centers lie within \a radius
+        of \a dir in \a listpix.
+        \param dir the angular coordinates of the disc center
+        \param radius the radius (in radians) of the disc
+        \param listpix a vector containing the numbers of all pixels within
+               the disc
+        \note This method is more efficient in the RING scheme. */
+    void query_disc (const pointing &dir, double radius,
+      std::vector<int> &listpix) const;
+    /*! Returns the numbers of all pixels that lie at least partially within
+        \a radius of \a dir in \a listpix. It may also return a few pixels
+        which do not lie in the disk at all.
+        \param dir the angular coordinates of the disc center
+        \param radius the radius (in radians) of the disc
+        \param listpix a vector containing the numbers of all pixels within
+               the disc
+        \note This method works in both RING and NEST schemes, but is
+          considerably faster in the RING scheme. */
+    void query_disc_inclusive (const pointing &dir, double radius,
+      std::vector<int> &listpix) const
+        { query_disc (dir,radius+1.362*pi/(4*nside_),listpix); }
+
+    /*! Returns useful information about a given ring of the map.
+        \param ring the ring number (the number of the first ring is 1)
+        \param startpix the number of the first pixel in the ring
+        \param ringpix the number of pixels in the ring
+        \param costheta the cosine of the colatitude (in radians) of the ring
+        \param sintheta the sine of the colatitude (in radians) of the ring
+        \param shifted if \a true, the center of the first pixel is not at
+               \a phi=0 */
+    void get_ring_info (int ring, int &startpix, int &ringpix,
+      double &costheta, double &sintheta, bool &shifted) const;
+    /*! Returns useful information about a given ring of the map.
+        \param ring the ring number (the number of the first ring is 1)
+        \param startpix the number of the first pixel in the ring
+        \param ringpix the number of pixels in the ring
+        \param theta the colatitude (in radians) of the ring
+        \param shifted if \a true, the center of the first pixel is not at
+               \a phi=0 */
+    void get_ring_info2 (int ring, int &startpix, int &ringpix,
+      double &theta, bool &shifted) const;
+
+    /*! Returns the neighboring pixels of \a pix in \a result.
+        On exit, \a result contains (in this order)
+        the pixel numbers of the SW, W, NW, N, NE, E, SE and S neighbor
+        of \a pix. If a neighbor does not exist (this can only be the case
+        for the W, N, E and S neighbors), its entry is set to -1.
+
+        \note This method works in both RING and NEST schemes, but is
+          considerably faster in the NEST scheme. */
+    void neighbors (int pix, fix_arr<int,8> &result) const;
+    /*! Returns interpolation information for the direction \a ptg.
+        The surrounding pixels are returned in \a pix, their corresponding
+        weights in \a wgt.
+        \note This method works in both RING and NEST schemes, but is
+          considerably faster in the RING scheme. */
+    void get_interpol (const pointing &ptg, fix_arr<int,4> &pix,
+                       fix_arr<double,4> &wgt) const;
+
+    /*! Returns the order parameter of the object. */
+    int Order() const { return order_; }
+    /*! Returns the \a N_side parameter of the object. */
+    int Nside() const { return nside_; }
+    /*! Returns the number of pixels of the object. */
+    int Npix() const { return npix_; }
+    /*! Returns the ordering scheme of the object. */
+    Healpix_Ordering_Scheme Scheme() const { return scheme_; }
+
+    /*! Returns \a true, if both objects have the same nside and scheme,
+        else  \a false. */
+    bool conformable (const Healpix_Base &other) const
+      { return ((nside_==other.nside_) && (scheme_==other.scheme_)); }
+
+    /*! Swaps the contents of two Healpix_Base objects. */
+    void swap (Healpix_Base &other)
+      {
+      std::swap(order_,other.order_);
+      std::swap(nside_,other.nside_);
+      std::swap(npface_,other.npface_);
+      std::swap(ncap_,other.ncap_);
+      std::swap(npix_,other.npix_);
+      std::swap(fact1_,other.fact1_);
+      std::swap(fact2_,other.fact2_);
+      std::swap(scheme_,other.scheme_);
+      }
+
+    /*! Returns the maximum angular distance (in radian) between any pixel
+        center and its corners. */
+    double max_pixrad() const;
+  };
+
+#endif
diff --git a/src/Healpix_2.15a/lsconstants.h b/src/Healpix_2.15a/lsconstants.h
new file mode 100644
index 0000000..b40270b
--- /dev/null
+++ b/src/Healpix_2.15a/lsconstants.h
@@ -0,0 +1,112 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*! \file src/Healpix_2.15a/cxxsupport/lsconstants.h
+ *  Mathematical, physical and technical constants for LevelS.
+ */
+
+#ifndef PLANCK_CONSTANTS_H
+#define PLANCK_CONSTANTS_H
+
+#include <cmath>
+
+/*! \defgroup mathconstgroup Mathematical constants */
+/*! \{ */
+
+const double pi=3.141592653589793238462643383279502884197;
+const double twopi=6.283185307179586476925286766559005768394;
+const double inv_twopi=1.0/twopi;
+const double fourpi=12.56637061435917295385057353311801153679;
+const double halfpi=1.570796326794896619231321691639751442099;
+const double inv_halfpi=0.6366197723675813430755350534900574;
+const double inv_sqrt4pi = 0.2820947917738781434740397257803862929220;
+
+const double ln2 = 0.6931471805599453094172321214581766;
+const double inv_ln2 = 1.4426950408889634073599246810018921;
+const double ln10 = 2.3025850929940456840179914546843642;
+
+const double onethird=1.0/3.0;
+const double twothird=2.0/3.0;
+const double fourthird=4.0/3.0;
+
+const double degr2rad=pi/180.0;
+const double rad2degr=180.0/pi;
+
+//! Ratio between FWHM and sigma of a Gauss curve (\f$\sqrt{8\ln2}\f$).
+const double sigma2fwhm=2.3548200450309493; // sqrt(8*log(2.))
+const double fwhm2sigma=1/sigma2fwhm;
+
+/*! \} */
+
+/*! \defgroup physconstgroup Physical constants */
+/*! \{ */
+
+const double Jansky2SI=1.0e-26;
+const double SI2Jansky=1.0e+26;
+
+//! Light speed in m/s.
+const double speedOfLight=2.99792458e8;
+
+//! Boltzmann's constant in J/K
+const double kBoltzmann=1.380658e-23;
+
+//! Stefan-Boltzmann constant in W/m^2/K^4
+const double sigmaStefanBoltzmann=5.67051e-8;
+
+//! Planck's constant in J s
+const double hPlanck=6.6260755e-34;
+
+//! Astronomical unit in m
+const double astronomicalUnit=1.49597893e11;
+
+//! Solar constant in W/m^2
+const double solarConstant=1368.0;
+
+//! Tropical year in s
+const double tropicalYear=3.15569259747e7;
+
+//! Average CMB temperature in K
+const double tcmb = 2.726;
+
+//! Colatitude of the solar system motion relative to CMB
+//! (ecliptical coordinates).
+const double solsysdir_ecl_theta = 1.7678013480275747;
+
+//! Longitude of the solar system motion relative to CMB
+//! (ecliptical coordinates).
+const double solsysdir_ecl_phi = 3.0039153062803194;
+
+//! Speed of the solar system motion relative to CMB in m/s.
+const double solsysspeed = 371000.0;
+
+/*! \} */
+
+// technical constants
+
+//! Healpix value representing "undefined"
+const double Healpix_undef=-1.6375e30;
+
+#endif
diff --git a/src/Healpix_2.15a/message_error.h b/src/Healpix_2.15a/message_error.h
new file mode 100644
index 0000000..39bc39b
--- /dev/null
+++ b/src/Healpix_2.15a/message_error.h
@@ -0,0 +1,96 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*
+ *  Class for error reporting
+ *
+ *  Copyright (C) 2003, 2004 Max-Planck-Society
+ *  Authors: Reinhard Hell, Martin Reinecke
+ */
+
+#ifndef PLANCK_MESSAGE_ERROR_H
+#define PLANCK_MESSAGE_ERROR_H
+
+#include <exception>
+#include <iostream>
+#include <string>
+
+#if defined (PLANCK_STACKTRACE)
+#include <execinfo.h>
+#endif
+
+inline void show_stackframe()
+  {
+#if defined (PLANCK_STACKTRACE)
+  void *trace[16];
+  int trace_size = backtrace(trace, 16);
+  char **messages = backtrace_symbols(trace, trace_size);
+  std::cerr << "[bt] Execution path:" << std::endl;
+  for (int i=0; i<trace_size; ++i)
+    std::cerr << "[bt] " << messages[i] << std::endl;
+#endif
+  }
+
+
+class Message_error
+  {
+  private:
+    std::string msg;
+
+  public:
+    Message_error()
+      : msg (std::string("Unspecified error"))
+      { std::cerr<<msg<<std::endl; show_stackframe(); }
+
+    explicit Message_error(const std::string &message)
+      : msg (message) { std::cerr<<msg<<std::endl; show_stackframe(); }
+
+    virtual const char* what() const
+      { return msg.c_str(); }
+
+    virtual ~Message_error() {}
+  };
+
+#if defined (PLANCK_CHECKS)
+
+#define PLANCK_DIAGNOSIS_BEGIN try {
+#define PLANCK_DIAGNOSIS_END \
+} \
+catch (Message_error &e) \
+  { std::cerr << "Planck exception: " << e.what() << std::endl; throw; } \
+catch (std::exception &e) \
+  { std::cerr << "std::exception: " << e.what() << std::endl; throw; } \
+catch (...) \
+  { std::cerr << "Unknown exception" << std::endl; throw; }
+
+#else
+
+#define PLANCK_DIAGNOSIS_BEGIN
+#define PLANCK_DIAGNOSIS_END
+
+#endif
+
+#endif
diff --git a/src/Healpix_2.15a/openmp_support.h b/src/Healpix_2.15a/openmp_support.h
new file mode 100644
index 0000000..7e2066e
--- /dev/null
+++ b/src/Healpix_2.15a/openmp_support.h
@@ -0,0 +1,86 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*
+ *  Copyright (C) 2005, 2006, 2007 Max-Planck-Society
+ *  \author Martin Reinecke
+ */
+
+#ifndef PLANCK_OPENMP_SUPPORT_H
+#define PLANCK_OPENMP_SUPPORT_H
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+
+inline bool openmp_enabled()
+  {
+#ifdef _OPENMP
+  return true;
+#else
+  return false;
+#endif
+  }
+
+inline int openmp_max_threads ()
+  {
+#ifdef _OPENMP
+  return omp_get_max_threads();
+#else
+  return 1;
+#endif
+  }
+
+inline int openmp_thread_num ()
+  {
+#ifdef _OPENMP
+  return omp_get_thread_num();
+#else
+  return 0;
+#endif
+  }
+
+/*! Calculates the range of indices between \a glo and \a ghi which
+    must be processed by this thread and returns it in \a lo and \a hi.
+
+    The indices \a ghi and \a hi are "one past the last real index",
+    in analogy to the STL iterators. */
+inline void openmp_calc_share (int glo, int ghi, int &lo, int &hi)
+  {
+#ifdef _OPENMP
+  int nwork = ghi-glo;
+  int nproc = omp_get_num_threads();
+  int me = omp_get_thread_num();
+  int nbase = nwork/nproc;
+  int additional = nwork%nproc;
+  lo = glo+me*nbase + ((me<additional) ? me : additional);
+  hi = lo+nbase+(me<additional);
+#else
+  lo=glo; hi=ghi;
+#endif
+  }
+
+#endif
diff --git a/src/Healpix_2.15a/pointing.h b/src/Healpix_2.15a/pointing.h
new file mode 100644
index 0000000..a10a7b3
--- /dev/null
+++ b/src/Healpix_2.15a/pointing.h
@@ -0,0 +1,115 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*! \file src/Healpix_2.15a/cxxsupport/pointing.h
+ *  Class representing a direction in 3D space
+ *
+ *  Copyright (C) 2003 Max-Planck-Society
+ *  \author Martin Reinecke
+ */
+
+#ifndef PLANCK_POINTING_H
+#define PLANCK_POINTING_H
+
+#include <cmath>
+#include "src/Healpix_2.15a/vec3.h"
+#include "src/Healpix_2.15a/cxxutils.h"
+
+/*! \defgroup pointinggroup Pointings */
+/*! \{ */
+
+/*! Class representing a direction in 3D space or a location on the
+    unit sphere. */
+class pointing
+  {
+  public:
+    /*! Colatitude of the pointing (i.e. the North pole is at \a theta=0). */
+    double theta;
+    /*! Longitude of the pointing. */
+    double phi;
+
+    /*! Default constructor. \a theta and \a phi are not initialized. */
+    pointing() {}
+    /*! Creates a pointing with \a Theta and \a Phi. */
+    pointing (double Theta, double Phi) : theta(Theta), phi(Phi) {}
+
+// FIXME: should become "explicit" some time
+    /*! Creates a pointing from the vector \a inp. \a inp need not be
+        normalized. */
+    pointing (const vec3 &inp)
+      {
+      using namespace std;
+      theta = atan2(sqrt(inp.x*inp.x+inp.y*inp.y),inp.z);
+      phi = safe_atan2 (inp.y,inp.x);
+      if (phi<0) phi += twopi;
+      }
+// FIXME: should be removed some time
+    /*! Returns a normalized vector pointing in the same direction. */
+    operator vec3() const
+      {
+      double st=sin(theta);
+      return vec3 (st*cos(phi), st*sin(phi), cos(theta));
+      }
+    /*! Returns a normalized vector pointing in the same direction. */
+    vec3 to_vec3() const
+      {
+      double st=sin(theta);
+      return vec3 (st*cos(phi), st*sin(phi), cos(theta));
+      }
+    /*! Changes the angles so that \a 0<=theta<=pi and \a 0<=phi<2*pi. */
+    void normalize()
+      {
+      theta=fmodulo(theta,twopi);
+      if (theta>pi)
+        {
+        phi+=pi;
+        theta=twopi-theta;
+        }
+      phi=fmodulo(phi,twopi);
+      }
+  };
+
+/*! Converts \a vec to \a ptg. \a vec need not be normalized.
+    \relates pointing */
+inline void vec2pnt(const vec3 &vec, pointing &ptg)
+  {
+  using namespace std;
+  ptg.theta = atan2(sqrt(vec.x*vec.x+vec.y*vec.y),vec.z);
+  ptg.phi = safe_atan2 (vec.y,vec.x);
+  if (ptg.phi<0) ptg.phi += twopi;
+  }
+
+/*! Writes \a p to \a os.
+    \relates pointing */
+inline std::ostream &operator<< (std::ostream &os, const pointing &p)
+  {
+  os << p.theta << ", " << p.phi << std::endl;
+  return os;
+  }
+
+/*! \} */
+
+#endif
diff --git a/src/Healpix_2.15a/vec3.h b/src/Healpix_2.15a/vec3.h
new file mode 100644
index 0000000..a6eed96
--- /dev/null
+++ b/src/Healpix_2.15a/vec3.h
@@ -0,0 +1,125 @@
+/*
+ *  This file is part of Healpix_cxx.
+ *
+ *  Healpix_cxx is free software; you can 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.
+ *
+ *  Healpix_cxx is distributed in the hope that 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 Healpix_cxx; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *  For more information about HEALPix, see http://healpix.jpl.nasa.gov
+ */
+
+/*
+ *  Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik
+ *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
+ *  (DLR).
+ */
+
+/*! \file src/Healpix_2.15a/cxxsupport/vec3.h
+ *  Class representing 3D cartesian vectors
+ *
+ *  Copyright (C) 2003, 2006 Max-Planck-Society
+ *  \author Martin Reinecke
+ */
+
+#ifndef PLANCK_VEC3_H
+#define PLANCK_VEC3_H
+
+#include <cmath>
+#include <iostream>
+
+/*! \defgroup vec3group 3D vectors */
+/*! \{ */
+
+/*! Class representing a 3D cartesian vector. */
+class vec3
+  {
+  public:
+    double x, /*!< x-coordinate */
+           y, /*!< y-coordinate */
+           z; /*!< z-coordinate */
+
+    /*! Default constructor. Does not initialize \a x, \a y, and \a z. */
+    vec3 () {}
+    /*! Creates a vector with the coordinates \a xc, \a yc, and \a zc. */
+    vec3 (double xc, double yc, double zc)
+      : x(xc), y(yc), z(zc) {}
+
+    /*! Creates a unit vector from a z coordinate and an azimuthal angle. */
+    void set_z_phi (double z_, double phi)
+      {
+      using namespace std;
+      double sintheta = sqrt((1.-z_)*(1.+z_));
+      x = sintheta*cos(phi);
+      y = sintheta*sin(phi);
+      z = z_;
+      }
+
+    /*! Normalizes the vector to length 1. */
+    void Normalize ()
+      {
+      using namespace std;
+      double l = 1.0/sqrt (x*x + y*y + z*z);
+      x*=l; y*=l; z*=l;
+      }
+
+    /*! Returns the length of the vector. */
+    double Length () const
+      { return sqrt (x*x + y*y + z*z); }
+
+    /*! Returns the squared length of the vector. */
+    double SquaredLength () const
+      { return (x*x + y*y + z*z); }
+    /*! Returns the vector with the signs of all coordinates flipped. */
+    const vec3 operator- () const
+      { return vec3 (-x, -y, -z); }
+    /*! Flips the signs of all coordinates. */
+    void Flip ()
+      { x=-x; y=-y; z=-z; }
+    /*! Subtracts \a vec from the vector. */
+    const vec3 operator- (const vec3 &vec) const
+      { return vec3 (x-vec.x, y-vec.y, z-vec.z); }
+    /*! Adds \a vec to the vector. */
+    const vec3 operator+ (const vec3 &vec) const
+      { return vec3 (x+vec.x, y+vec.y, z+vec.z); }
+    /*! Returns the vector scaled by \a fact. */
+    const vec3 operator* (double fact) const
+      { return vec3 (x*fact, y*fact, z*fact); }
+    /*! Returns the vector scaled by \a 1/fact. */
+    const vec3 operator/ (double fact) const
+      { double xfact = 1./fact; return vec3 (x*xfact, y*xfact, z*xfact); }
+    /*! Scales the vector by \a fact. */
+    vec3 &operator*= (double fact)
+      { x*=fact; y*=fact; z*=fact; return *this; }
+  };
+
+/*! Returns the dot product of \a v1 and \a v2.
+    \relates vec3 */
+inline double dotprod(const vec3 &v1, const vec3 &v2)
+  { return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; }
+
+/*! Returns the cross product of \a a and \a b.
+    \relates vec3 */
+inline vec3 crossprod(const vec3 &a, const vec3 &b)
+  { return vec3 (a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); }
+
+/*! Writes \a v to \a os.
+    \relates vec3 */
+inline std::ostream &operator<< (std::ostream &os, const vec3 &v)
+  {
+  os << v.x << ", " << v.y << ", " << v.z << std::endl;
+  return os;
+  }
+
+/*! \} */
+
+#endif
diff --git a/src/apps/autopick.cpp b/src/apps/autopick.cpp
new file mode 100644
index 0000000..ca93a32
--- /dev/null
+++ b/src/apps/autopick.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <src/autopicker.h>
+
+
+int main(int argc, char *argv[])
+{
+	AutoPicker prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.initialise();
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
diff --git a/src/apps/autopick_mpi.cpp b/src/apps/autopick_mpi.cpp
new file mode 100644
index 0000000..854581f
--- /dev/null
+++ b/src/apps/autopick_mpi.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <src/autopicker_mpi.h>
+
+
+int main(int argc, char *argv[])
+{
+	AutoPickerMpi prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.initialise();
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
diff --git a/src/apps/display.cpp b/src/apps/display.cpp
new file mode 100644
index 0000000..937b828
--- /dev/null
+++ b/src/apps/display.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include <unistd.h>
+#include <string.h>
+
+#include <src/args.h>
+#include <src/image.h>
+#include <src/strings.h>
+#include <src/funcs.h>
+#include <src/memory.h>
+#include <src/euler.h>
+#include <src/time.h>
+#include <src/displayer.h>
+
+int main(int argc, char *argv[])
+{
+    Displayer prm;
+
+    try
+    {
+        prm.read(argc, argv);
+
+
+        if (prm.do_gui)
+        {
+        	prm.runGui();
+        }
+        else
+        {
+        	prm.initialise();
+        	prm.run();
+        }
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+        return 0;
+}
diff --git a/src/apps/find_tiltpairs.cpp b/src/apps/find_tiltpairs.cpp
new file mode 100644
index 0000000..18744e6
--- /dev/null
+++ b/src/apps/find_tiltpairs.cpp
@@ -0,0 +1,503 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <src/args.h>
+#include <src/strings.h>
+#include <src/funcs.h>
+#include <src/memory.h>
+#include <src/euler.h>
+#include <src/time.h>
+#include <src/metadata_table.h>
+
+class angular_error_parameters
+{
+public:
+
+	FileName fn_unt, fn_til, fn_out;
+	MetaDataTable MDunt, MDtil;
+	double tilt, tilt0, tiltF, tiltStep;
+	double rot, rot0, rotF, rotStep;
+        int size, dim;
+	int x0, xF, xStep;
+	int y0, yF, yStep;
+	double acc;
+	int mind2;
+	bool do_opt;
+	double best_rot, best_tilt;
+	int best_x, best_y;
+	Matrix2D<double> Pass;
+	std::vector<int> p_unt, p_til, p_map, pairs_t2u;
+	// I/O Parser
+	IOParser parser;
+
+	void usage()
+	{
+		parser.writeUsage(std::cerr);
+	}
+
+	void read(int argc, char **argv)
+	{
+
+		parser.setCommandLine(argc, argv);
+
+		int general_section = parser.addSection("General Options");
+		fn_unt = parser.getOption("--u", "STAR file with the untilted xy-coordinates");
+		fn_til = parser.getOption("--t", "STAR file with the untilted xy-coordinates");
+		size = textToInteger(parser.getOption("--size", "Largest dimension of the micrograph (in pixels), e.g. 4096"));
+		dim = textToInteger(parser.getOption("--dim", "Dimension of boxed particles (for EMAN .box files in pixels)", "200"));
+		acc = textToFloat(parser.getOption("--acc", "Allowed accuracy (in pixels), e.g. half the particle diameter"));
+		tilt = textToFloat(parser.getOption("--tilt", "Fix tilt angle (in degrees)", "99999."));
+		rot = textToFloat(parser.getOption("--rot", "Fix direction of the tilt axis (in degrees), 0 = along y, 90 = along x", "99999."));
+		do_opt = !parser.checkOption("--dont_opt", "Skip optimization of the transformation matrix");
+		mind2 = ROUND(acc * acc);
+
+		int angle_section = parser.addSection("Specified tilt axis and translational search ranges");
+		tilt0 = textToFloat(parser.getOption("--tilt0", "Minimum tilt angle (in degrees)","0."));
+		tiltF = textToFloat(parser.getOption("--tiltF", "Maximum tilt angle (in degrees)","99999."));
+		if (tiltF == 99999.) tiltF = tilt0;
+		tiltStep = textToFloat(parser.getOption("--tiltStep", "Tilt angle step size (in degrees)","1."));
+
+		rot0 = textToFloat(parser.getOption("--rot0", "Minimum rot angle (in degrees)","0."));
+		rotF = textToFloat(parser.getOption("--rotF", "Maximum rot angle (in degrees)","99999."));
+		if (rotF == 99999.) rotF = rot0;
+		rotStep = textToFloat(parser.getOption("--rotStep", "Rot angle step size (in degrees)","1."));
+
+		x0 = textToInteger(parser.getOption("--x0", "Minimum X offset (pixels)","-99999"));
+		xF = textToInteger(parser.getOption("--xF", "Maximum X offset (pixels)","99999"));
+		xStep = textToInteger(parser.getOption("--xStep", "X offset step size (pixels)","-1"));
+		y0 = textToInteger(parser.getOption("--y0", "Minimum Y offset (pixels)","-99999"));
+		yF = textToInteger(parser.getOption("--yF", "Maximum Y offset (pixels)","99999"));
+		yStep = textToInteger(parser.getOption("--yStep", "Y offset step size (pixels)","-1"));
+
+       	// Check for errors in the command-line option
+    	if (parser.checkForErrors())
+    		REPORT_ERROR("Errors encountered on the command line, exiting...");
+
+		// If tilt and rot were given: do not search those
+		if (tilt != 99999.)
+		{
+			tilt0 = tiltF = tilt;
+			tiltStep = 1.;
+		}
+		if (rot != 99999.)
+		{
+			rot0 = rotF = rot;
+			rotStep = 1.;
+		}
+
+		// By default search the entire micrograph
+		x0 = XMIPP_MAX(x0, -size);
+		xF = XMIPP_MIN(xF, size);
+		// By default use a xStep of one third the accuracy
+		if (xStep < 0)
+			xStep = acc / 3;
+
+		// By default treat y search in the same way as the x-search
+		if (y0 == -99999)
+			y0 = x0;
+		if (yF == 99999)
+			yF = xF;
+		if (yStep < 0)
+			yStep = xStep;
+
+		// Done reading, now fill p_unt and p_til
+		MDunt.read(fn_unt);
+		MDtil.read(fn_til);
+
+		// Check for the correct labels
+		if (!MDunt.containsLabel(EMDL_IMAGE_COORD_X) || !MDunt.containsLabel(EMDL_IMAGE_COORD_Y))
+			REPORT_ERROR("ERROR: Untilted STAR file does not contain the rlnCoordinateX or Y labels");
+		if (!MDtil.containsLabel(EMDL_IMAGE_COORD_X) || !MDtil.containsLabel(EMDL_IMAGE_COORD_Y))
+			REPORT_ERROR("ERROR: Tilted STAR file does not contain the rlnCoordinateX or Y labels");
+
+		double x, y;
+
+		p_unt.clear();
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDunt)
+		{
+			MDunt.getValue(EMDL_IMAGE_COORD_X, x);
+			MDunt.getValue(EMDL_IMAGE_COORD_Y, y);
+			p_unt.push_back((int)x);
+			p_unt.push_back((int)y);
+		}
+		p_til.clear();
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDtil)
+		{
+			MDtil.getValue(EMDL_IMAGE_COORD_X, x);
+			MDtil.getValue(EMDL_IMAGE_COORD_Y, y);
+			p_til.push_back((int)x);
+			p_til.push_back((int)y);
+		}
+
+		// Initialize best transformation params
+		best_x = best_y = 9999;
+		best_rot = best_tilt = 9999.;
+
+	}
+
+	int getNumberOfPairs(int dx=0, int dy=0)
+	{
+
+		pairs_t2u.clear();
+		pairs_t2u.resize(p_til.size()/2, -1);
+		int result = 0;
+		for (int u = 0; u < p_map.size()/2; u++)
+		{
+			for (int t = 0; t < p_til.size()/2; t++)
+			{
+				// only search over particles that do not have a pair yet
+				if (pairs_t2u[t] < 0)
+				{
+					int XX = p_map[2*u]-p_til[2*t]+dx;
+					XX*= XX;
+					int YY = p_map[2*u+1]-p_til[2*t+1]+dy;
+					XX += YY*YY;
+					if (XX < mind2)
+					{
+						result++;
+						pairs_t2u[t] = u;
+						//No longer have to search for all the others in q
+						break;
+					}
+				}
+			}
+		}
+		return result;
+
+	}
+
+	double getAverageDistance(int dx=0, int dy=0)
+	{
+
+
+		std::ofstream  fh;
+		FileName fn_map;
+		fn_map = "dist.txt";
+		fh.open(fn_map.c_str(), std::ios::out);
+
+		double result = 0.;
+		int count = 0;
+		for (int t = 0; t < pairs_t2u.size(); t++)
+		{
+			int u = pairs_t2u[t];
+			if (u >= 0)
+			{
+				int XX = p_map[2*u]-p_til[2*t]+dx;
+				XX*= XX;
+				int YY = p_map[2*u+1]-p_til[2*t+1]+dy;
+				XX += YY*YY;
+				//std::cerr << " sqrt(XX)= " << sqrt(XX) << " t= " << t << " u= " << u << std::endl;
+				result += sqrt(XX);
+				fh << sqrt(XX) << std::endl;
+				count ++;
+			}
+		}
+		result /= (double)count;
+		fh.close();
+		return result;
+
+	}
+
+	int prunePairs(int dx=0, int dy=0)
+	{
+
+		int nprune = 0;
+		// Prune for double pairs
+		for (int t = 0; t < pairs_t2u.size(); t++)
+		{
+			int u = pairs_t2u[t];
+			if (u >= 0)
+			{
+				for (int tp = t+1; tp < pairs_t2u.size(); tp++)
+				{
+					int up = pairs_t2u[tp];
+					// Find pairs to the same tilted position
+					if (up == u)
+					{
+						nprune++;
+
+						// Only keep the nearest neighbours as a pair
+						int XX = p_map[2*u]-p_til[2*t]+dx;
+						XX*= XX;
+						int YY = p_map[2*u+1]-p_til[2*t+1]+dy;
+						XX += YY*YY;
+
+						//up==p
+						int XXp = p_map[2*u]-p_til[2*tp]+dx;
+						XXp*= XXp;
+						int YYp = p_map[2*u+1]-p_til[2*tp+1]+dy;
+						XXp += YYp*YYp;
+
+						if (XX < XXp)
+							pairs_t2u[tp] = -1;
+						else
+							pairs_t2u[t] = -1;
+					}
+				}
+			}
+		}
+		return nprune;
+	}
+
+	void mapOntoTilt()
+	{
+		p_map.resize(p_unt.size());
+		for (int u = 0; u < p_map.size()/2; u++)
+		{
+			double xu = (double)p_unt[2*u];
+			double yu = (double)p_unt[2*u+1];
+
+			p_map[2*u] = ROUND(MAT_ELEM(Pass, 0, 0) * xu + MAT_ELEM(Pass, 0, 1) * yu + MAT_ELEM(Pass, 0, 2));
+			p_map[2*u+1] = ROUND(MAT_ELEM(Pass, 1, 0) * xu + MAT_ELEM(Pass, 1, 1) * yu + MAT_ELEM(Pass, 1, 2));
+
+		}
+	}
+
+
+	double optimiseTransformationMatrix(bool do_optimise_nr_pairs)
+	{
+		std::vector<int> best_pairs_t2u, best_map;
+		double score, best_score, best_dist=9999.;
+		if (do_optimise_nr_pairs)
+			best_score = 0.;
+		else
+			best_score = -999999.;
+
+		int nn = XMIPP_MAX(1., (rotF-rot0)/rotStep);
+		nn *= XMIPP_MAX(1., (tiltF-tilt0)/tiltStep);
+		nn *= XMIPP_MAX(1., (xF-x0)/xStep);
+		nn *= XMIPP_MAX(1., (yF-y0)/yStep);
+		int n = 0;
+		init_progress_bar(nn);
+		for (double rot = rot0; rot <= rotF; rot+= rotStep)
+		{
+			for (double tilt = tilt0; tilt <= tiltF; tilt+= tiltStep)
+			{
+				// Assume tilt-axis lies in-plane...
+				double psi = -rot;
+				// Rotate all points correspondingly
+				Euler_angles2matrix(rot, tilt, psi, Pass);
+				//std::cerr << " Pass= " << Pass << std::endl;
+				// Zero-translations for now (these are added in the x-y loops below)
+				MAT_ELEM(Pass, 0, 2) = MAT_ELEM(Pass, 1, 2) = 0.;
+				mapOntoTilt();
+				for (int x = x0; x <= xF; x += xStep)
+				{
+					for (int y = y0; y <= yF; y += yStep, n++)
+					{
+						if (do_optimise_nr_pairs)
+							score = getNumberOfPairs(x, y);
+						else
+							score = -getAverageDistance(x, y); // negative because smaller distance is better!
+
+                                                bool is_best = false;
+                                                if (do_optimise_nr_pairs && score==best_score)
+                                                {
+                                                    double dist = getAverageDistance(x, y);
+                                                    if (dist < best_dist)
+                                                    {
+                                                        best_dist = dist;
+                                                        is_best = true;
+                                                    }
+                                                }
+						if (score > best_score || is_best)
+						{
+							best_score = score;
+							best_pairs_t2u = pairs_t2u;
+							best_rot = rot;
+							best_tilt = tilt;
+							best_x = x;
+							best_y = y;
+						}
+						if (n%1000==0) progress_bar(n);
+					}
+				}
+			}
+		}
+		progress_bar(nn);
+		// Update pairs with the best_pairs
+		if (do_optimise_nr_pairs)
+			pairs_t2u = best_pairs_t2u;
+
+		// Update the Passing matrix and the mapping
+		Euler_angles2matrix(best_rot, best_tilt, -best_rot, Pass);
+		// Zero-translations for now (these are added in the x-y loops below)
+		MAT_ELEM(Pass, 0, 2) = MAT_ELEM(Pass, 1, 2) = 0.;
+		mapOntoTilt();
+		return best_score;
+
+	}
+
+	void optimiseTransformationMatrixContinuous()
+	{
+		// Get coordinates of all pairs:
+		Matrix2D<double> Au, Bt;
+	    Au.initZeros(3, 3);
+	    Bt.initZeros(3, 3);
+	    Pass.initZeros(4,4);
+
+	    // Add all pairs to dependent matrices (adapted from add_point in Xmipps micrograph_mark main_widget_mark.cpp)
+		for (int t = 0; t < pairs_t2u.size(); t++)
+		{
+			int u = pairs_t2u[t];
+			if (u >= 0)
+	        {
+				Au(0, 0) += (double)(p_unt[2*u] * p_unt[2*u]);
+				Au(0, 1) += (double)(p_unt[2*u] * p_unt[2*u+1]);
+				Au(0, 2) += (double)(p_unt[2*u]);
+				Au(1, 0) = Au(0, 1);
+				Au(1, 1) += (double)(p_unt[2*u+1] * p_unt[2*u+1]);
+				Au(1, 2) += (double)(p_unt[2*u+1]);
+				Au(2, 0) = Au(0, 2);
+				Au(2, 1) = Au(1, 2);
+				Au(2, 2) += 1.;
+
+				Bt(0, 0) += (double)(p_til[2*t] * p_unt[2*u]);
+				Bt(0, 1) += (double)(p_til[2*t+1] * p_unt[2*u]);
+				Bt(0, 2) = Au(0, 2);
+				Bt(1, 0) += (double)(p_til[2*t] * p_unt[2*u+1]);
+				Bt(1, 1) += (double)(p_til[2*t+1] * p_unt[2*u+1]);
+				Bt(1, 2) = Au(1, 2);
+				Bt(2, 0) += (double)(p_til[2*t]);
+				Bt(2, 1) += (double)(p_til[2*t+1]);
+				Bt(2,2) += 1.;
+	        }
+	    }
+
+	    // Solve equations
+	    solve(Au, Bt, Pass);
+	    Pass = Pass.transpose();
+	    std::cout << " Optimised passing matrix= " << Pass << std::endl;
+	    //These values can be complete CRAP. Better not show them at all....
+	    //double rotp, tiltp, psip;
+	    //tiltp = acos(Pass(1,1));
+	    //rotp = acos(Pass(1,0)/sin(tiltp));
+	    //psip = acos(Pass(0,1)/-sin(tiltp));
+	    //std::cout << " Optimised tilt angle= " << RAD2DEG(tiltp) << std::endl;
+	    //std::cout << " Optimised in-plane rot angles= " << RAD2DEG(rotp) <<" and "<< RAD2DEG(psip) << std::endl;
+	    // Map using the new matrix
+	    mapOntoTilt();
+
+	}
+
+	void run()
+	{
+
+		// First do a crude search over the given parameter optimization space
+		// Optimize the number of pairs here...
+		int npart = optimiseTransformationMatrix(true);
+		// Get rid of double pairs (two different untilted coordinates are close to a tilted coordinate)
+		int nprune = 0;
+		nprune = prunePairs(best_x, best_y);
+		// Calculate average distance between the pairs
+		double avgdist = getAverageDistance(best_x, best_y);
+		std::cout << " Before optimization of the passing matrix: "<<std::endl;
+		std::cout << "  - Number of pruned pairs= "<<nprune<<std::endl;
+		std::cout << "  - best_rot= " << best_rot << " best_tilt= " << best_tilt << " best_x= " << best_x << " best_y= " << best_y << std::endl;
+		std::cout << "  - Number of particle pairs= " << npart << " average distance= " <<avgdist<<std::endl;
+
+#define WRITE_MAPPED
+#ifdef WRITE_MAPPED
+		std::ofstream  fh;
+		FileName fn_map;
+		fn_map = "mapped.box";
+		fh.open(fn_map.c_str(), std::ios::out);
+		for (int i = 0; i < p_map.size()/2; i++)
+		{
+                    fh << p_map[2*i] + best_x -dim/2<< " " << p_map[2*i+1] + best_y -dim/2<< " "<<dim<<" "<<dim<<" -3"<<std::endl;
+			//if (pairs[i]>=0)
+			//	std::cerr << " i= " << i << " pairs[i]= " << pairs[i] << std::endl;
+		}
+		fh.close();
+#endif
+
+		if (do_opt)
+		{
+			optimiseTransformationMatrixContinuous();
+			npart = getNumberOfPairs();
+			nprune = prunePairs();
+			avgdist = getAverageDistance();
+			std::cout << " After optimization of the passing matrix: "<<std::endl;
+			std::cout << "  - Number of pruned pairs= "<<nprune<<std::endl;
+			std::cout << "  - Final number of particle pairs= " << npart << " average distance= " <<avgdist<<std::endl;
+
+		}
+
+#ifdef WRITE_MAPPED
+		fn_map = "mapped_opt.box";
+		fh.open(fn_map.c_str(), std::ios::out);
+		for (int i = 0; i < p_map.size()/2; i++)
+		{
+                    fh << p_map[2*i] -dim/2<< " " << p_map[2*i+1] -dim/2<<" "<<dim<<" "<<dim<<" -3"<< std::endl;
+		}
+		fh.close();
+#endif
+
+		// Write out STAR files with the coordinates
+		MetaDataTable MDu, MDt;
+		for (int t = 0; t < p_til.size()/2; t++)
+		{
+			int u = pairs_t2u[t];
+			if (u >= 0)
+			{
+				MDu.addObject();
+				MDu.setValue(EMDL_IMAGE_COORD_X, ((double)(p_unt[2*u])));
+				MDu.setValue(EMDL_IMAGE_COORD_Y, ((double)(p_unt[2*u+1])));
+
+				MDt.addObject();
+				MDt.setValue(EMDL_IMAGE_COORD_X, ((double)(p_til[2*t])));
+				MDt.setValue(EMDL_IMAGE_COORD_Y, ((double)(p_til[2*t+1])));
+			}
+		}
+		fn_unt = fn_unt.withoutExtension() + "_pairs.star";
+		fn_til = fn_til.withoutExtension() + "_pairs.star";
+		MDu.write(fn_unt);
+		MDt.write(fn_til);
+
+		std::cout << " Written out coordinate STAR files: " << fn_unt << " and " << fn_til <<std::endl;
+		std::cout << " Done!" << std::endl;
+
+	}
+
+};
+
+int main(int argc, char *argv[])
+{
+	angular_error_parameters prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.run();
+
+    }
+
+    catch (RelionError XE)
+    {
+        std::cout << XE;
+        prm.usage();
+        exit(1);
+    }
+
+    return 0;
+
+}
+
+
diff --git a/src/apps/image_handler.cpp b/src/apps/image_handler.cpp
new file mode 100644
index 0000000..72d41e7
--- /dev/null
+++ b/src/apps/image_handler.cpp
@@ -0,0 +1,465 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include <src/image.h>
+#include <src/funcs.h>
+#include <src/args.h>
+#include <src/fftw.h>
+#include <src/time.h>
+#include <src/symmetries.h>
+
+class image_handler_parameters
+{
+	public:
+   	FileName fn_in, fn_out, fn_sel, fn_img, fn_sym, fn_sub, fn_mult, fn_div, fn_add, fn_subtract, fn_mtf;
+	int bin_avg, avg_first, avg_last, edge_x0, edge_xF, edge_y0, edge_yF, filter_edge_width, new_box;
+	bool do_add_edge, do_flipXY, do_flipmXY, do_shiftCOM;
+	double multiply_constant, divide_constant, add_constant, subtract_constant, threshold_above, threshold_below, angpix, new_angpix, lowpass, highpass, bfactor, shift_x, shift_y, shift_z;
+   	// I/O Parser
+	IOParser parser;
+
+	Image<double> Iout;
+
+	void usage()
+	{
+		parser.writeUsage(std::cerr);
+	}
+
+	void read(int argc, char **argv)
+	{
+
+		parser.setCommandLine(argc, argv);
+
+		int general_section = parser.addSection("General options");
+	    fn_in = parser.getOption("--i", "Input image (.mrc) or movie/stack (.mrcs)");
+	    fn_out = parser.getOption("--o", "Output file");
+
+	    int cst_section = parser.addSection("image-by-constant operations");
+	    multiply_constant = textToFloat(parser.getOption("--multiply_constant", "Multiply the image(s) pixel values by this constant", "1"));
+	    divide_constant = textToFloat(parser.getOption("--divide_constant", "Divide the image(s) pixel values by this constant", "1"));
+	    add_constant = textToFloat(parser.getOption("--add_constant", "Add this constant to the image(s) pixel values", "0."));
+	    subtract_constant = textToFloat(parser.getOption("--subtract_constant", "Subtract this constant from the image(s) pixel values", "0."));
+	    threshold_above = textToFloat(parser.getOption("--threshold_above", "Set all values higher than this value to this value", "999."));
+	    threshold_below = textToFloat(parser.getOption("--threshold_below", "Set all values lower than this value to this value", "-999."));
+
+	    int img_section = parser.addSection("image-by-image operations");
+	    fn_mult = parser.getOption("--multiply", "Multiply input image(s) by the pixel values in this image", "");
+	    fn_div = parser.getOption("--divide", "Divide input image(s) by the pixel values in this image", "");
+	    fn_add = parser.getOption("--add", "Add the pixel values in this image to the input image(s) ", "");
+	    fn_subtract = parser.getOption("--subtract", "Subtract the pixel values in this image to the input image(s) ", "");
+
+	    int four_section = parser.addSection("per-image operations");
+	    fn_mtf = parser.getOption("--correct_mtf", "STAR-file with MTF values to correct for (rlnResolutionInversePixel and rlnMtfValue)", "");
+	    bfactor = textToFloat(parser.getOption("--bfactor", "Apply a B-factor (in A^2)", "0."));
+	    lowpass = textToFloat(parser.getOption("--lowpass", "Low-pass filter frequency (in A)", "-1."));
+	    highpass = textToFloat(parser.getOption("--highpass", "High-pass filter frequency (in A)", "-1."));
+	    angpix = textToFloat(parser.getOption("--angpix", "Pixel size (in A)", "1."));
+	    new_angpix = textToFloat(parser.getOption("--rescale_angpix", "Scale input image(s) to this new pixel size (in A)", "-1."));
+	    new_box = textToInteger(parser.getOption("--new_box", "Resize the image(s) to this new box size (in pixel) ", "-1"));
+	    filter_edge_width = textToInteger(parser.getOption("--filter_edge_width", "Width of the raised cosine on the low/high-pass filter edge (in resolution shells)", "2"));
+	    do_shiftCOM = parser.checkOption("--shift_com", "Shift image(s) to their center-of-mass (only on positive pixel values)");
+	    shift_x = textToFloat(parser.getOption("--shift_x", "Shift images this many pixels in the X-direction", "0."));
+	    shift_y = textToFloat(parser.getOption("--shift_y", "Shift images this many pixels in the Y-direction", "0."));
+	    shift_z = textToFloat(parser.getOption("--shift_z", "Shift images this many pixels in the Z-direction", "0."));
+
+	    int three_d_section = parser.addSection("3D operations");
+	    fn_sym = parser.getOption("--sym", "Symmetrise 3D map with this point group (e.g. D6)", "");
+
+	    int preprocess_section = parser.addSection("2D-micrograph (or movie) operations");
+	    do_flipXY = parser.checkOption("--flipXY", "Flip the image(s) in the XY direction?");
+	    do_flipmXY = parser.checkOption("--flipmXY", "Flip the image(s) image(s)in the -XY direction?");
+	    do_add_edge = parser.checkOption("--add_edge", "Add a barcode-like edge to the micrograph/movie frames?");
+	    edge_x0 = textToInteger(parser.getOption("--edge_x0", "Pixel column to be used for the left edge", "0"));
+	    edge_y0 = textToInteger(parser.getOption("--edge_y0", "Pixel row to be used for the top edge", "0"));
+	    edge_xF = textToInteger(parser.getOption("--edge_xF", "Pixel column to be used for the right edge", "4095"));
+	    edge_yF = textToInteger(parser.getOption("--edge_yF", "Pixel row to be used for the bottom edge", "4095"));
+
+	    int avg_section = parser.addSection("Movie-frame averaging options");
+       	bin_avg = textToInteger(parser.getOption("--avg_bin", "Width (in frames) for binning average, i.e. of every so-many frames", "-1"));
+    	avg_first = textToInteger(parser.getOption("--avg_first", "First frame to include in averaging", "-1"));
+    	avg_last = textToInteger(parser.getOption("--avg_last", "Last frame to include in averaging", "-1"));
+
+    	// Check for errors in the command-line option
+    	if (parser.checkForErrors())
+    		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+	}
+
+	void run()
+	{
+
+		Image<double> Ihead, Iin;
+		MultidimArray<double> Mtmp;
+
+		Ihead.read(fn_in, false);
+		int xdim, ydim, zdim;
+		long int ndim;
+		Ihead.getDimensions(xdim, ydim, zdim, ndim);
+
+		if (zdim > 1 && (do_add_edge || do_flipXY || do_flipmXY))
+			REPORT_ERROR("ERROR: you cannot perform 2D operations like --add_edge, --flipXY or --flipmXY on 3D maps. If you intended to operate on a movie, use .mrcs extensions for stacks!");
+
+		if (zdim > 1 && (bin_avg > 0 || (avg_first >= 0 && avg_last >= 0)))
+			REPORT_ERROR("ERROR: you cannot perform movie-averaging operations on 3D maps. If you intended to operate on a movie, use .mrcs extensions for stacks!");
+
+		int avgndim = 1;
+		if (bin_avg > 0)
+		{
+			avgndim = ndim / bin_avg;
+		}
+		Image<double> Iavg(xdim, ydim, zdim, avgndim);
+		Image<double> Iout(xdim, ydim, zdim);
+		Image<double> Iop;
+		if (fn_mult != "")
+			Iop.read(fn_mult);
+		else if (fn_div != "")
+			Iop.read(fn_div);
+		else if (fn_add != "")
+			Iop.read(fn_add);
+		else if (fn_subtract != "")
+			Iop.read(fn_subtract);
+
+		if (fn_mult != "" || fn_div != "" || fn_add != "" || fn_subtract != "")
+			if (XSIZE(Iop()) != xdim || YSIZE(Iop()) != ydim || ZSIZE(Iop()) != zdim)
+				REPORT_ERROR("Error: operate-image is not of the correct size");
+
+		// Read each frame and do whatever is asked
+		time_config();
+   		init_progress_bar(ndim);
+		bool do_rewrite;
+		for (long int nn = 0; nn < ndim; nn++)
+		{
+			if (ndim > 1)
+				Iin.read(fn_in, true, nn);
+			else
+				Iin.read(fn_in);
+
+			do_rewrite = false;
+
+			// 2D options
+			if (do_add_edge)
+			{
+				do_rewrite = true;
+				// Treat X-boundaries
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(Iin())
+				{
+					if (j < edge_x0)
+						DIRECT_A2D_ELEM(Iin(), i, j) = DIRECT_A2D_ELEM(Iin(), i, edge_x0);
+					else if (j > edge_xF)
+						DIRECT_A2D_ELEM(Iin(), i, j) = DIRECT_A2D_ELEM(Iin(), i, edge_xF);
+				}
+				// Treat Y-boundaries
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(Iin())
+				{
+					if (i < edge_y0)
+						DIRECT_A2D_ELEM(Iin(), i, j) = DIRECT_A2D_ELEM(Iin(), edge_y0, j);
+					else if (i > edge_yF)
+						DIRECT_A2D_ELEM(Iin(), i, j) = DIRECT_A2D_ELEM(Iin(), edge_yF, j);
+				}
+			}
+			// Flipping: this needs to be done from Iin to Iout (i.e. can't be done on-line on Iout only!)
+			if (do_flipXY)
+			{
+				do_rewrite = true;
+				// Flip X/Y
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(Iin())
+				{
+					DIRECT_A2D_ELEM(Iout(), i, j) = DIRECT_A2D_ELEM(Iin(), j, i);
+
+				}
+			}
+			else if (do_flipmXY)
+			{
+				do_rewrite = true;
+				// Flip mX/Y
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(Iin())
+				{
+					DIRECT_A2D_ELEM(Iout(), i, j) = DIRECT_A2D_ELEM(Iin(), XSIZE(Iin()) - 1 - j, YSIZE(Iin()) - 1 - i);
+				}
+			}
+			else
+			{
+				Iout = Iin;
+			}
+
+
+			// From here on also 3D options
+			if (fabs(multiply_constant - 1.) > 0.)
+			{
+				do_rewrite = true;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Iin())
+				{
+					DIRECT_A3D_ELEM(Iout(), k, i, j) *= multiply_constant;
+				}
+			}
+			else if (fabs(divide_constant - 1.) > 0.)
+			{
+				do_rewrite = true;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Iin())
+				{
+					DIRECT_A3D_ELEM(Iout(), k, i, j) /= divide_constant;
+				}
+			}
+			else if (fabs(add_constant) > 0.)
+			{
+				do_rewrite = true;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Iin())
+				{
+					DIRECT_A3D_ELEM(Iout(), k, i, j) += add_constant;
+				}
+			}
+			else if (fabs(subtract_constant) > 0.)
+			{
+				do_rewrite = true;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Iin())
+				{
+					DIRECT_A3D_ELEM(Iout(), k, i, j) -= subtract_constant;
+				}
+			}
+			else if (fn_mult != "")
+			{
+				do_rewrite = true;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Iin())
+				{
+					DIRECT_A3D_ELEM(Iout(), k, i, j) *= DIRECT_A3D_ELEM(Iop(), k, i, j);
+				}
+			}
+			else if (fn_div != "")
+			{
+				do_rewrite = true;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Iin())
+				{
+					if (DIRECT_A3D_ELEM(Iop(), k, i, j) < 1e-10)
+						std::cout << "Warning: very small pixel values in divide image..." << std::endl;
+					DIRECT_A3D_ELEM(Iout(), k, i, j) /= DIRECT_A3D_ELEM(Iop(), k, i, j);
+				}
+			}
+			else if (fn_add != "")
+			{
+				do_rewrite = true;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Iin())
+				{
+					DIRECT_A3D_ELEM(Iout(), k, i, j) += DIRECT_A3D_ELEM(Iop(), k, i, j);
+				}
+			}
+			else if (fn_subtract != "")
+			{
+				do_rewrite = true;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Iin())
+				{
+					DIRECT_A3D_ELEM(Iout(), k, i, j) -= DIRECT_A3D_ELEM(Iop(), k, i, j);
+				}
+			}
+
+			// More 2D/3D stuff
+			if (fn_mtf != "")
+			{
+				do_rewrite = true;
+				correctMapForMTF(Iout(), fn_mtf);
+			}
+			if (fabs(bfactor) > 0.)
+			{
+				do_rewrite = true;
+				applyBFactorToMap(Iout(), bfactor, angpix);
+			}
+			if (lowpass > 0.)
+			{
+				do_rewrite = true;
+				lowPassFilterMap(Iout(), lowpass, angpix, filter_edge_width);
+			}
+			if (highpass > 0.)
+			{
+				do_rewrite = true;
+				highPassFilterMap(Iout(), lowpass, angpix, filter_edge_width);
+			}
+
+			// Shifting
+			if (do_shiftCOM)
+			{
+				do_rewrite = true;
+				selfTranslateCenterOfMassToCenter(Iout(), DONT_WRAP);
+			}
+			else if (fabs(shift_x) > 0. || fabs(shift_y) > 0. || fabs(shift_z) > 0.)
+			{
+				do_rewrite = true;
+				Matrix1D<double> shift(2);
+				XX(shift) = shift_x;
+				YY(shift) = shift_y;
+				if (zdim > 1)
+				{
+					shift.resize(3);
+					ZZ(shift) = shift_z;
+				}
+				selfTranslate(Iout(), shift, DONT_WRAP);
+			}
+
+			// Re-scale
+			if (new_angpix > 0.)
+			{
+				do_rewrite = true;
+
+				int oldsize = XSIZE(Iout());
+				int newsize = ROUND(oldsize * (angpix / new_angpix));
+				resizeMap(Iout(), newsize);
+
+				// Also reset the sampling rate in the header
+				Iout.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_X, new_angpix);
+				Iout.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Y, new_angpix);
+				if (Iout().getDim() == 3)
+					Iout.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Z, new_angpix);
+
+			}
+
+			// Re-window
+			if (new_box > 0)
+			{
+				do_rewrite = true;
+				Iout().setXmippOrigin();
+				if (Iout().getDim() == 2)
+				{
+					Iout().window(FIRST_XMIPP_INDEX(new_box), FIRST_XMIPP_INDEX(new_box),
+							   LAST_XMIPP_INDEX(new_box),  LAST_XMIPP_INDEX(new_box));
+				}
+				else if (Iout().getDim() == 3)
+				{
+					Iout().window(FIRST_XMIPP_INDEX(new_box), FIRST_XMIPP_INDEX(new_box), FIRST_XMIPP_INDEX(new_box),
+							   LAST_XMIPP_INDEX(new_box),  LAST_XMIPP_INDEX(new_box),  LAST_XMIPP_INDEX(new_box));
+				}
+			}
+
+			// 3D-only stuff
+			if (fn_sym != "")
+			{
+				do_rewrite = true;
+				symmetriseMap(Iout(), fn_sym);
+			}
+
+			// Thresholding (can be done after any other operation)
+			if (fabs(threshold_above - 999.) > 0.)
+			{
+				do_rewrite = true;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Iin())
+				{
+					if (DIRECT_A3D_ELEM(Iout(), k, i, j) > threshold_above)
+						DIRECT_A3D_ELEM(Iout(), k, i, j) = threshold_above;
+				}
+			}
+			if (fabs(threshold_below + 999.) > 0.)
+			{
+				do_rewrite = true;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Iin())
+				{
+					if (DIRECT_A3D_ELEM(Iout(), k, i, j) < threshold_below)
+						DIRECT_A3D_ELEM(Iout(), k, i, j) = threshold_below;
+				}
+			}
+
+			if (do_rewrite)
+			{
+				if (ndim > 1)
+				{
+					// Movies: first frame overwrite, then append
+					if (nn == 0)
+						Iout.write(fn_out, -1, (ndim > 1), WRITE_OVERWRITE);
+					else
+						Iout.write(fn_out, -1, false, WRITE_APPEND);
+				}
+				else
+				{
+					// Check whether fn_out has an "@": if so REPLACE the corresponding frame in the output stack!
+					long int n;
+					FileName fn_tmp;
+					fn_out.decompose(n,fn_tmp);
+					n--;
+					if (n >= 0)
+						Iout.write(fn_tmp, n, true, WRITE_REPLACE);
+					else
+						Iout.write(fn_out);
+				}
+			}
+
+			// Take care of averaging (this again is done in 2D!)
+			if (bin_avg > 0)
+			{
+				int myframe = nn / bin_avg;
+				if (myframe < avgndim)
+				{
+					FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(Iout())
+					{
+						DIRECT_NZYX_ELEM(Iavg(),myframe,0,i,j) += DIRECT_A2D_ELEM(Iout(), i, j); // just store sum
+					}
+				}
+			}
+			else if (avg_first >= 0 && avg_last >= 0 && nn+1 >= avg_first && nn+1 <= avg_last) // add one to start counting at 1
+			{
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Iout())
+				{
+					DIRECT_MULTIDIM_ELEM(Iavg(), n) += DIRECT_MULTIDIM_ELEM(Iout(), n); // just store sum
+				}
+			}
+
+			progress_bar(nn);
+		}
+   		progress_bar(ndim);
+
+   		if (bin_avg > 0 || (avg_first >= 0 && avg_last >= 0))
+   		{
+   			Iavg.write(fn_out);
+   			std::cout << " Done! Written output as: " << fn_out << std::endl;
+   		}
+   		else if (do_rewrite)
+   		{
+   			std::cout << " Done! Written output as: " << fn_out << std::endl;
+   		}
+   		else
+   		{
+   			std::cout << " Done nothing, please provide an operation to perform ... " << std::endl;
+   		}
+
+
+	}
+
+
+};
+
+
+int main(int argc, char *argv[])
+{
+	image_handler_parameters prm;
+
+	try
+    {
+
+		prm.read(argc, argv);
+
+		prm.run();
+
+    }
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+    return 0;
+}
+
+
+
diff --git a/src/apps/maingui.cpp b/src/apps/maingui.cpp
new file mode 100644
index 0000000..fcda86a
--- /dev/null
+++ b/src/apps/maingui.cpp
@@ -0,0 +1,66 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include "src/gui_mainwindow.h"
+#include <unistd.h>
+#include <string.h>
+
+
+int main(int argc, char *argv[])
+{
+	Fl::scheme("gtk+");
+
+#define _MAX_PATH 200
+
+	char my_dir[_MAX_PATH];
+	char short_dir[49];
+	getcwd(my_dir, _MAX_PATH);
+
+	// Get last 45 characters of my_dir to fit in titlebar of window
+	if (strlen(my_dir) > 45)
+	{
+		short_dir[0]=short_dir[1]=short_dir[2]='.';
+		int j = 3;
+		for (int i = strlen(my_dir)-45; i < strlen(my_dir); i++, j++)
+		{
+			short_dir[j] = my_dir[i];
+		}
+		short_dir[j] = '\0';
+	}
+	else
+	{
+		int i;
+		for (i = 0; i < strlen(my_dir); i++)
+			short_dir[i] = my_dir[i];
+		short_dir[i] = '\0';
+	}
+
+	char titletext[57];
+	strcpy (titletext,"RELION: ");
+	strcat (titletext, short_dir);
+	RelionMainWindow window(GUIWIDTH, GUIHEIGHT, titletext);
+
+    window.show(argc, argv);
+
+    return Fl::run();
+
+}
diff --git a/src/apps/manualpick.cpp b/src/apps/manualpick.cpp
new file mode 100644
index 0000000..d8fbd89
--- /dev/null
+++ b/src/apps/manualpick.cpp
@@ -0,0 +1,54 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include <unistd.h>
+#include <string.h>
+
+#include <src/args.h>
+#include <src/image.h>
+#include <src/strings.h>
+#include <src/funcs.h>
+#include <src/memory.h>
+#include <src/euler.h>
+#include <src/time.h>
+#include <src/manualpicker.h>
+
+int main(int argc, char *argv[])
+{
+    ManualPicker prm;
+
+    try
+    {
+        prm.read(argc, argv);
+
+       	prm.initialise();
+       	prm.run();
+
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+        return 0;
+}
diff --git a/src/apps/mask_create.cpp b/src/apps/mask_create.cpp
new file mode 100644
index 0000000..e8ce4c6
--- /dev/null
+++ b/src/apps/mask_create.cpp
@@ -0,0 +1,170 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include <src/image.h>
+#include <src/funcs.h>
+#include <src/ctf.h>
+#include <src/args.h>
+#include <src/error.h>
+#include <src/mask.h>
+#include <src/time.h>
+
+class mask_create_parameters
+{
+	public:
+   	FileName fn_apply_in, fn_mask, fn_apply_out, fn_thr, fn_omask, fn_and, fn_or, fn_andnot, fn_ornot;
+   	double ini_threshold, extend_ini_mask, width_soft_edge;
+	bool do_invert;
+   	IOParser parser;
+
+	void usage()
+	{
+		parser.writeUsage(std::cerr);
+	}
+
+	void read(int argc, char **argv)
+	{
+
+		parser.setCommandLine(argc, argv);
+
+	    int create_section = parser.addSection("Mask creation options");
+	    fn_thr = parser.getOption("--i", "Input map to use for thresholding to generate initial binary mask","");
+	    fn_omask = parser.getOption("--o", "Output mask","mask.mrc");
+	    fn_and = parser.getOption("--and", "Pixels in the initial mask will be one if the input AND this map are above the --ini_threshold value","");
+	    fn_or = parser.getOption("--or", "Pixels in the initial mask will be one if the input OR this map are above the --ini_threshold value","");
+	    fn_andnot = parser.getOption("--and_not", "Pixels in the initial mask will be one if the input is above the --ini_threshold AND this map is below it","");
+	    fn_ornot = parser.getOption("--or_not", "Pixels in the initial mask will be one if the input is above the --ini_threshold OR this map is below it","");
+	    ini_threshold  = textToFloat(parser.getOption("--ini_threshold", "Initial threshold for binarization","0.01"));
+	    extend_ini_mask = textToFloat(parser.getOption("--extend_inimask", "Extend initial binary mask this number of pixels","0"));
+	    width_soft_edge  = textToFloat(parser.getOption("--width_soft_edge", "Width (in pixels) of the additional soft edge on the binary mask", "0"));
+	    do_invert = parser.checkOption("--invert", "Invert the final mask");
+
+	    if (fn_thr=="" && fn_apply_in == "")
+	    	REPORT_ERROR("Either provide --i to apply a mask, OR --create_from to create a new mask");
+
+	    // Check for errors in the command-line option
+    	if (parser.checkForErrors())
+    		REPORT_ERROR("Errors encountered on the command line, exiting...");
+	}
+
+
+	void run()
+	{
+
+		Image<double> Iin, Iout, Ip;
+		std:: cout << " Creating a mask ..." << std::endl;
+		Iin.read(fn_thr);
+
+		if (fn_and != "")
+		{
+			Ip.read(fn_and);
+			if (!Ip().sameShape(Iin()))
+				REPORT_ERROR("ERROR: --i and --and maps are different shapes!");
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Ip())
+			{
+				if (DIRECT_MULTIDIM_ELEM(Ip(), n) > ini_threshold && DIRECT_MULTIDIM_ELEM(Iin(), n) > ini_threshold)
+					DIRECT_MULTIDIM_ELEM(Iin(), n) = ini_threshold + 1.;
+				else
+					DIRECT_MULTIDIM_ELEM(Iin(), n) = ini_threshold - 1.;
+			}
+		}
+		else if  (fn_or != "")
+		{
+			Ip.read(fn_or);
+			if (!Ip().sameShape(Iin()))
+				REPORT_ERROR("ERROR: --i and --or maps are different shapes!");
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Ip())
+			{
+				if (DIRECT_MULTIDIM_ELEM(Ip(), n) > ini_threshold || DIRECT_MULTIDIM_ELEM(Iin(), n) > ini_threshold)
+					DIRECT_MULTIDIM_ELEM(Iin(), n) = ini_threshold + 1.;
+				else
+					DIRECT_MULTIDIM_ELEM(Iin(), n) = ini_threshold - 1.;
+			}
+		}
+		else if  (fn_andnot != "")
+		{
+			Ip.read(fn_andnot);
+			if (!Ip().sameShape(Iin()))
+				REPORT_ERROR("ERROR: --i and --not maps are different shapes!");
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Ip())
+			{
+				if (DIRECT_MULTIDIM_ELEM(Iin(), n) > ini_threshold && DIRECT_MULTIDIM_ELEM(Ip(), n) < ini_threshold)
+					DIRECT_MULTIDIM_ELEM(Iin(), n) = ini_threshold + 1.;
+				else
+					DIRECT_MULTIDIM_ELEM(Iin(), n) = ini_threshold - 1.;
+			}
+		}
+		else if  (fn_ornot != "")
+		{
+			Ip.read(fn_ornot);
+			if (!Ip().sameShape(Iin()))
+				REPORT_ERROR("ERROR: --i and --not maps are different shapes!");
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Ip())
+			{
+				if (DIRECT_MULTIDIM_ELEM(Iin(), n) > ini_threshold || DIRECT_MULTIDIM_ELEM(Ip(), n) < ini_threshold)
+					DIRECT_MULTIDIM_ELEM(Iin(), n) = ini_threshold + 1.;
+				else
+					DIRECT_MULTIDIM_ELEM(Iin(), n) = ini_threshold - 1.;
+			}
+		}
+
+		autoMask(Iin(), Iout(), ini_threshold, extend_ini_mask, width_soft_edge, true); // true sets verbosity
+
+		if (do_invert)
+		{
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Iout())
+			{
+				DIRECT_MULTIDIM_ELEM(Iout(), n) = 1. - DIRECT_MULTIDIM_ELEM(Iout(), n);
+			}
+		}
+
+		// Set header and write outmap map
+		Iout.setStatisticsInHeader();
+		Iout.setSamplingRateInHeader(Iin.samplingRateX(), Iin.samplingRateY());
+		Iout.write(fn_omask);
+		std::cout << " Done creating mask! Written out: " << fn_omask << std::endl;
+	}
+
+
+};
+
+
+int main(int argc, char *argv[])
+{
+	mask_create_parameters prm;
+
+	try
+    {
+
+		prm.read(argc, argv);
+
+		prm.run();
+
+    }
+    catch (RelionError XE)
+    {
+        std::cout << XE;
+        prm.usage();
+        exit(1);
+    }
+    return 0;
+}
+
+
diff --git a/src/apps/particle_polish.cpp b/src/apps/particle_polish.cpp
new file mode 100644
index 0000000..b04a629
--- /dev/null
+++ b/src/apps/particle_polish.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <src/particle_polisher.h>
+
+
+int main(int argc, char *argv[])
+{
+	ParticlePolisher prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.initialise();
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
diff --git a/src/apps/particle_polish_mpi.cpp b/src/apps/particle_polish_mpi.cpp
new file mode 100644
index 0000000..16e32bc
--- /dev/null
+++ b/src/apps/particle_polish_mpi.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/particle_polisher_mpi.h"
+
+
+int main(int argc, char *argv[])
+{
+	ParticlePolisherMpi prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.initialise();
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
diff --git a/src/apps/particle_sort.cpp b/src/apps/particle_sort.cpp
new file mode 100644
index 0000000..8b17e77
--- /dev/null
+++ b/src/apps/particle_sort.cpp
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <src/particle_sorter.h>
+
+
+int main(int argc, char *argv[])
+{
+	ParticleSorter prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.initialise();
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
+
+
+
diff --git a/src/apps/particle_sort_mpi.cpp b/src/apps/particle_sort_mpi.cpp
new file mode 100644
index 0000000..3eed873
--- /dev/null
+++ b/src/apps/particle_sort_mpi.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/particle_sorter_mpi.h"
+
+
+int main(int argc, char *argv[])
+{
+	ParticleSorterMpi prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.initialise();
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
diff --git a/src/apps/postprocess.cpp b/src/apps/postprocess.cpp
new file mode 100644
index 0000000..0136445
--- /dev/null
+++ b/src/apps/postprocess.cpp
@@ -0,0 +1,46 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <src/postprocessing.h>
+
+
+int main(int argc, char *argv[])
+{
+	Postprocessing prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
+
+
diff --git a/src/apps/preprocess.cpp b/src/apps/preprocess.cpp
new file mode 100644
index 0000000..45ec1ee
--- /dev/null
+++ b/src/apps/preprocess.cpp
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <src/preprocessing.h>
+
+
+int main(int argc, char *argv[])
+{
+	Preprocessing prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.initialise();
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
+
+
diff --git a/src/apps/preprocess_mpi.cpp b/src/apps/preprocess_mpi.cpp
new file mode 100644
index 0000000..c393392
--- /dev/null
+++ b/src/apps/preprocess_mpi.cpp
@@ -0,0 +1,48 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <src/preprocessing_mpi.h>
+
+
+int main(int argc, char *argv[])
+{
+	PreprocessingMpi prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.initialise();
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
+
+
diff --git a/src/apps/project.cpp b/src/apps/project.cpp
new file mode 100644
index 0000000..2dee6a9
--- /dev/null
+++ b/src/apps/project.cpp
@@ -0,0 +1,329 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include <src/projector.h>
+#include <src/backprojector.h>
+#include <src/fftw.h>
+#include <src/args.h>
+#include <src/ctf.h>
+#include <src/strings.h>
+#include <src/funcs.h>
+#include <src/memory.h>
+#include <src/euler.h>
+#include <src/time.h>
+#include <src/metadata_table.h>
+#include <src/ml_model.h>
+#include <src/exp_model.h>
+#include <src/healpix_sampling.h>
+class project_parameters
+{
+public:
+
+	FileName fn_map, fn_ang, fn_out, fn_img, fn_model, fn_sym;
+	double rot, tilt, psi, xoff, yoff, zoff, angpix, maxres, stddev_white_noise, particle_diameter, ana_prob_range, ana_prob_step;
+	int padding_factor;
+	int r_max, r_min_nn, interpolator;
+    bool do_only_one, do_ctf, ctf_phase_flipped, do_timing, do_add_noise, do_subtract_exp, do_ignore_particle_name;
+	// I/O Parser
+	IOParser parser;
+	MlModel model;
+
+
+	void usage()
+	{
+		parser.writeUsage(std::cerr);
+	}
+
+	void read(int argc, char **argv)
+	{
+		parser.setCommandLine(argc, argv);
+
+		int general_section = parser.addSection("Options");
+		fn_map = parser.getOption("--i", "Input map to be projected");
+		fn_out = parser.getOption("--o", "Rootname for output projections", "proj");
+       	do_ctf = parser.checkOption("--ctf", "Apply CTF to reference projections");
+       	ctf_phase_flipped = parser.checkOption("--ctf_phase_flip", "Flip phases of the CTF in the output projections");
+       	angpix = textToFloat(parser.getOption("--angpix", "Pixel size (in Angstroms)", "1"));
+       	fn_ang = parser.getOption("--ang", "STAR file with orientations for multiple projections (if None, assume single projection)","None");
+       	rot = textToFloat(parser.getOption("--rot", "First Euler angle (for a single projection)", "0"));
+       	tilt = textToFloat(parser.getOption("--tilt", "Second Euler angle (for a single projection)", "0"));
+       	psi = textToFloat(parser.getOption("--psi", "Third Euler angle (for a single projection)", "0"));
+       	xoff = textToFloat(parser.getOption("--xoff", "Origin X-offsets (in pixels) (for a single projection)", "0"));
+       	yoff = textToFloat(parser.getOption("--yoff", "Origin Y-offsets (in pixels) (for a single projection)", "0"));
+       	zoff = textToFloat(parser.getOption("--zoff", "Origin Z-offsets (in pixels) (for a single 3D rotation)", "0"));
+       	do_add_noise = parser.checkOption("--add_noise", "Add noise to the output projections (only with --ang)");
+       	stddev_white_noise = textToFloat(parser.getOption("--white_noise", "Standard deviation of added white Gaussian noise", "0"));
+       	fn_model = parser.getOption("--model_noise", "Model STAR file with power spectra for coloured Gaussian noise", "");
+       	do_subtract_exp = parser.checkOption("--subtract_exp", "Subtract projections from experimental images (in --ang)");
+       	do_ignore_particle_name = parser.checkOption("--ignore_particle_name", "Ignore the rlnParticleName column (in --ang)");
+       	do_only_one = (fn_ang == "None");
+
+       	maxres = textToFloat(parser.getOption("--maxres", "Maximum resolution (in Angstrom) to consider in Fourier space (default Nyquist)", "-1"));
+       	padding_factor = textToInteger(parser.getOption("--pad", "Padding factor", "2"));
+
+       	if (parser.checkOption("--NN", "Use nearest-neighbour instead of linear interpolation"))
+       		interpolator = NEAREST_NEIGHBOUR;
+       	else
+       		interpolator = TRILINEAR;
+
+       	// Hidden
+       	r_min_nn = textToInteger(getParameter(argc, argv, "--r_min_nn", "10"));
+
+       	// Check for errors in the command-line option
+    	if (parser.checkForErrors())
+    		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+	}
+
+	void project()
+	{
+
+    	MetaDataTable DFo, MDang;
+    	Matrix2D<double> A3D;
+    	FileName fn_expimg;
+
+    	MultidimArray<Complex > F2D, Fexpimg;
+    	MultidimArray<double> Fctf, dummy;
+    	Image<double> vol, img, expimg;
+    	FourierTransformer transformer, transformer_expimg;
+
+		std::cerr << " Reading map: " << fn_map << std::endl;
+    	vol.read(fn_map);
+    	std::cerr << " Done reading map!" << std::endl;
+
+    	if (!do_only_one)
+    	{
+    		std::cerr << " Reading STAR file with all angles " << fn_ang << std::endl;
+    		MDang.read(fn_ang);
+    		std::cerr << " Done reading STAR file!" << std::endl;
+    	}
+
+    	// Now that we have the size of the volume, check r_max
+   		if (maxres < 0.)
+   			r_max = XSIZE(vol());
+   		else
+   			r_max = CEIL(XSIZE(vol()) * angpix / maxres);
+
+    	// Set right size of F2D and initialize to zero
+   		img().resize(YSIZE(vol()), XSIZE(vol()));
+    	transformer.setReal(img());
+    	transformer.getFourierAlias(F2D);
+
+    	// Set up the projector
+    	Projector projector((int)XSIZE(vol()), interpolator, padding_factor, r_min_nn);
+    	projector.computeFourierTransformMap(vol(), dummy, 2* r_max);
+
+    	if (do_only_one)
+    	{
+            Euler_rotation3DMatrix(rot, tilt, psi, A3D);
+            F2D.initZeros();
+            projector.get2DFourierTransform(F2D, A3D, IS_NOT_INV);
+
+            if (ABS(xoff) > 0.001 || ABS(yoff) > 0.001)
+            {
+            	Matrix1D<double> shift(2);
+            	XX(shift) = -xoff;
+            	YY(shift) = -yoff;
+            	shiftImageInFourierTransform(F2D, F2D, XSIZE(vol()), shift);
+            }
+        	transformer.inverseFourierTransform();
+        	// Shift the image back to the center...
+        	CenterFFT(img(), false);
+        	img.write(fn_out);
+        	std::cerr<<" Done writing "<<fn_out<<std::endl;
+    	}
+    	else
+    	{
+            init_progress_bar(MDang.numberOfObjects());
+            DFo.clear();
+            rot = tilt = psi = xoff = yoff = zoff = 0.;
+
+            // Can only add noise to multiple images
+            if (do_add_noise)
+            {
+            	if (fn_model != "")
+            		model.read(fn_model);
+            	else if (stddev_white_noise > 0.)
+            		stddev_white_noise /= XSIZE(vol()) * sqrt(2); // fftw normalization and factor sqrt(2) for two-dimensionality of complex plane
+            	else
+            		REPORT_ERROR("ERROR: When adding noise provide either --model_noise or --white_noise");
+            }
+
+
+            long int imgno = 0;
+            FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDang)
+            {
+            	MDang.getValue(EMDL_ORIENT_ROT, rot);
+            	MDang.getValue(EMDL_ORIENT_TILT, tilt);
+            	MDang.getValue(EMDL_ORIENT_PSI, psi);
+            	MDang.getValue(EMDL_ORIENT_ORIGIN_X, xoff);
+            	MDang.getValue(EMDL_ORIENT_ORIGIN_Y, yoff);
+
+            	Euler_rotation3DMatrix(rot, tilt, psi, A3D);
+            	F2D.initZeros();
+            	projector.get2DFourierTransform(F2D, A3D, IS_NOT_INV);
+
+            	if (ABS(xoff) > 0.001 || ABS(yoff) > 0.001)
+            	{
+            		Matrix1D<double> shift(2);
+            		XX(shift) = -xoff;
+            		YY(shift) = -yoff;
+            		shiftImageInFourierTransform(F2D, F2D, XSIZE(vol()), shift );
+				}
+
+            	// Apply CTF if necessary
+            	CTF ctf;
+            	if (do_ctf)
+            	{
+                    ctf.read(MDang, MDang);
+                    Fctf.resize(F2D);
+                    ctf.getFftwImage(Fctf, XSIZE(vol()), XSIZE(vol()), angpix, ctf_phase_flipped, false, false, true);
+                    FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(F2D)
+                    {
+                        DIRECT_MULTIDIM_ELEM(F2D, n) *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+                    }
+                }
+
+                // Apply Gaussian noise
+                if (do_add_noise)
+                {
+                    if (fn_model !="")
+                    {
+                        //// 23MAY2014: for preparation of 1.3 release: removed reading a exp_model, replaced by just reading MDang
+                        // This does however mean that I no longer know mic_id of this image: replace by 0....
+                        FileName fn_group;
+                        if (MDang.containsLabel(EMDL_MLMODEL_GROUP_NAME))
+                        {
+                            MDang.getValue(EMDL_MLMODEL_GROUP_NAME, fn_group);
+                        }
+                        else
+                        {
+                            if (MDang.containsLabel(EMDL_MICROGRAPH_NAME))
+                            {
+                                MDang.getValue(EMDL_MICROGRAPH_NAME, fn_group);
+                            }
+                            else
+                            {
+                                REPORT_ERROR("ERROR: cannot find rlnGroupName or rlnMicrographName in the input --ang file...");
+                            }
+                        }
+                        int my_mic_id = -1;
+                        for (int mic_id = 0; mic_id < model.group_names.size(); mic_id++)
+                        {
+                            if (fn_group == model.group_names[mic_id])
+                            {
+                                my_mic_id = mic_id;
+                                break;
+                            }
+                        }
+                        if (my_mic_id < 0)
+                            REPORT_ERROR("ERROR: cannot find " + fn_group + " in the input model file...");
+
+                        double normcorr = 1.;
+                        if (MDang.containsLabel(EMDL_IMAGE_NORM_CORRECTION))
+                        {
+                            MDang.getValue(EMDL_IMAGE_NORM_CORRECTION, normcorr);
+                        }
+
+                        // Add coloured noise
+                        FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(F2D)
+                        {
+                            int ires = ROUND( sqrt( (double)(kp*kp + ip*ip + jp*jp) ) );
+                            ires = XMIPP_MIN(ires, model.ori_size/2); // at freqs higher than Nyquist: use last sigma2 value
+
+                            double sigma = sqrt(DIRECT_A1D_ELEM(model.sigma2_noise[my_mic_id], ires));
+                            DIRECT_A3D_ELEM(F2D, k, i, j).real += rnd_gaus(0., sigma);
+                            DIRECT_A3D_ELEM(F2D, k, i, j).imag += rnd_gaus(0., sigma);
+                        }
+                    }
+                    else
+                    {
+                        // Add white noise
+                        FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(F2D)
+                        {
+                            DIRECT_A3D_ELEM(F2D, k, i, j).real += rnd_gaus(0., stddev_white_noise);
+                            DIRECT_A3D_ELEM(F2D, k, i, j).imag += rnd_gaus(0., stddev_white_noise);
+                        }
+                    }
+                }
+
+                transformer.inverseFourierTransform();
+                // Shift the image back to the center...
+                CenterFFT(img(), false);
+
+                // Subtract the projection from the corresponding experimental image
+                if (do_subtract_exp)
+                {
+                    MDang.getValue(EMDL_IMAGE_NAME, fn_expimg);
+                    expimg.read(fn_expimg);
+                    img() = expimg() - img();
+                }
+
+                // Write this particle to the stack on disc
+                // First particle: write stack in overwrite mode, from then on just append to it
+                fn_img.compose(imgno+1,fn_out+".mrcs");
+                if (imgno == 0)
+                    img.write(fn_img, -1, false, WRITE_OVERWRITE);
+                else
+                    img.write(fn_img, -1, false, WRITE_APPEND);
+
+                // Set the image name to the output STAR file
+                DFo.addObject();
+                DFo.setObject(MDang.getObject());
+                DFo.setValue(EMDL_IMAGE_NAME,fn_img);
+
+                if (imgno%60==0) progress_bar(imgno);
+                imgno++;
+            }
+            progress_bar(MDang.numberOfObjects());
+
+            // Write out STAR file with all information
+            fn_img = fn_out + ".star";
+            DFo.write(fn_img);
+            std::cout<<" Done writing "<<imgno<<" images in "<<fn_img<<std::endl;
+
+    	} // end else do_only_one
+
+	}// end project function
+
+};
+
+int main(int argc, char *argv[])
+{
+	time_config();
+	project_parameters prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.project();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
diff --git a/src/apps/reconstruct.cpp b/src/apps/reconstruct.cpp
new file mode 100644
index 0000000..9d6c79b
--- /dev/null
+++ b/src/apps/reconstruct.cpp
@@ -0,0 +1,449 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include <src/backprojector.h>
+#include <src/funcs.h>
+#include <src/ctf.h>
+#include <src/args.h>
+#include <src/error.h>
+#include <src/euler.h>
+#include <src/time.h>
+
+class reconstruct_parameters
+{
+	public:
+   	FileName fn_out, fn_sel, fn_img, fn_sym, fn_sub, fn_fsc, fn_debug;
+	MetaDataTable DF;
+	int r_max, r_min_nn, blob_order, padding_factor, ref_dim, interpolator, iter, nr_threads, debug_ori_size, debug_size, ctf_dim;
+	double blob_radius, blob_alpha, angular_error, shift_error, angpix, maxres, beamtilt_x, beamtilt_y;
+	bool do_ctf, ctf_phase_flipped, only_flip_phases, intact_ctf_first_peak, do_fom_weighting, do_beamtilt;
+	// I/O Parser
+	IOParser parser;
+
+	void usage()
+	{
+		parser.writeUsage(std::cerr);
+	}
+
+	void read(int argc, char **argv)
+	{
+
+		parser.setCommandLine(argc, argv);
+
+		int general_section = parser.addSection("General options");
+
+		fn_debug = parser.getOption("--debug", "Rootname for debug reconstruction files", "");
+		debug_ori_size =  textToInteger(parser.getOption("--debug_ori_size", "Rootname for debug reconstruction files", "1"));
+		debug_size =  textToInteger(parser.getOption("--debug_size", "Rootname for debug reconstruction files", "1"));
+
+		fn_sel = parser.getOption("--i", "Input STAR file with the projection images and their orientations", "");
+	    fn_out = parser.getOption("--o", "Name for output reconstruction","relion.mrc");
+	    fn_sym = parser.getOption("--sym", "Symmetry group", "c1");
+       	angpix = textToFloat(parser.getOption("--angpix", "Pixel size (in Angstroms)", "1"));
+       	maxres = textToFloat(parser.getOption("--maxres", "Maximum resolution (in Angstrom) to consider in Fourier space (default Nyquist)", "-1"));
+       	padding_factor = textToInteger(parser.getOption("--pad", "Padding factor", "2"));
+    	nr_threads = textToInteger(parser.getOption("--j", "Number of threads to use for FFTs", "1"));
+
+	    int ctf_section = parser.addSection("CTF options");
+       	do_ctf = parser.checkOption("--ctf", "Apply CTF correction");
+    	intact_ctf_first_peak = parser.checkOption("--ctf_intact_first_peak", "Leave CTFs intact until first peak");
+    	ctf_phase_flipped = parser.checkOption("--ctf_phase_flipped", "Images have been phase flipped");
+    	only_flip_phases = parser.checkOption("--only_flip_phases", "Do not correct CTF-amplitudes, only flip phases");
+    	beamtilt_x = textToFloat(parser.getOption("--beamtilt_x", "Beamtilt in the X-direction (in mrad)", "0."));
+    	beamtilt_y = textToFloat(parser.getOption("--beamtilt_y", "Beamtilt in the Y-direction (in mrad)", "0."));
+    	do_beamtilt = (ABS(beamtilt_x) > 0. || ABS(beamtilt_y) > 0.);
+
+       	int expert_section = parser.addSection("Expert options");
+       	fn_sub = parser.getOption("--subtract","Subtract projections of this map from the images used for reconstruction", "");
+        if (parser.checkOption("--NN", "Use nearest-neighbour instead of linear interpolation before gridding correction"))
+       		interpolator = NEAREST_NEIGHBOUR;
+       	else
+       		interpolator = TRILINEAR;
+        blob_radius   = textToFloat(parser.getOption("--blob_r", "Radius of blob for gridding interpolation", "1.9"));
+        blob_order    = textToInteger(parser.getOption("--blob_m", "Order of blob for gridding interpolation", "0"));
+        blob_alpha    = textToFloat(parser.getOption("--blob_a", "Alpha-value of blob for gridding interpolation", "15"));
+       	iter = textToInteger(parser.getOption("--iter", "Number of gridding-correction iterations", "10"));
+       	ref_dim = textToInteger(parser.getOption("--refdim", "Dimension of the reconstruction (2D or 3D)", "3"));
+    	angular_error = textToFloat(parser.getOption("--angular_error", "Apply random deviations with this standard deviation (in degrees) to each of the 3 Euler angles", "0."));
+    	shift_error = textToFloat(parser.getOption("--shift_error", "Apply random deviations with this standard deviation (in pixels) to each of the 2 translations", "0."));
+    	do_fom_weighting = parser.checkOption("--fom_weighting", "Weight particles according to their figure-of-merit (_rlnParticleFigureOfMerit)");
+    	fn_fsc = parser.getOption("--fsc", "FSC-curve for regularized reconstruction", "");
+
+    	// Hidden
+       	r_min_nn = textToInteger(getParameter(argc, argv, "--r_min_nn", "10"));
+
+    	// Check for errors in the command-line option
+    	if (parser.checkForErrors())
+    		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+    	// Read MetaData file, which should have the image names and their angles!
+    	if (fn_debug == "")
+    		DF.read(fn_sel);
+
+     	randomize_random_generator();
+
+     	if (do_beamtilt && ! do_ctf)
+     		REPORT_ERROR("ERROR: one can only correct for beamtilt in combination with CTF correction!");
+
+	}
+
+	void reconstruct()
+	{
+
+		if (fn_debug != "")
+		{
+			BackProjector backprojector(debug_ori_size, 3, fn_sym, interpolator, padding_factor, r_min_nn, blob_order, blob_radius, blob_alpha);
+			backprojector.initialiseDataAndWeight(debug_size);
+			backprojector.data.printShape();
+			backprojector.weight.printShape();
+			Image<double> It;
+			It.read(fn_debug+"_data_real.mrc");
+			It().setXmippOrigin();
+			It().xinit=0;
+
+			It().printShape();
+			FOR_ALL_ELEMENTS_IN_ARRAY3D(It())
+			{
+				A3D_ELEM(backprojector.data, k, i, j).real = A3D_ELEM(It(), k, i, j);
+			}
+			It.read(fn_debug+"_data_imag.mrc");
+			It().setXmippOrigin();
+			It().xinit=0;
+			FOR_ALL_ELEMENTS_IN_ARRAY3D(It())
+			{
+				A3D_ELEM(backprojector.data, k, i, j).imag = A3D_ELEM(It(), k, i, j);
+			}
+			It.read(fn_debug+"_weight.mrc");
+			It().setXmippOrigin();
+			It().xinit=0;
+			FOR_ALL_ELEMENTS_IN_ARRAY3D(It())
+			{
+				A3D_ELEM(backprojector.weight, k, i, j) = A3D_ELEM(It(), k, i, j);
+			}
+
+			MultidimArray<double> dummy;
+			backprojector.reconstruct(It(), iter, false, 1., dummy, dummy, dummy, dummy, 1., false, true, nr_threads, -1);
+	    	It.write(fn_out);
+	    	std::cerr<<" Done writing map in "<<fn_out<<std::endl;
+                exit(1);
+
+		}
+		else
+		{
+
+		double rot, tilt, psi, fom;
+		Matrix2D<double> A3D;
+		MultidimArray<Complex > Faux, F2D, Fsub;
+		MultidimArray<double> Fweight, Fctf, dummy;
+		Image<double> vol, img, sub;
+		FourierTransformer transformer;
+		Matrix1D< double > trans(2);
+		Projector proj;
+		int mysize;
+//#define DEBUG_WW
+#ifdef DEBUG_WW
+
+   		// Get dimension of the images
+   		(DF).firstObject();
+   		DF.getValue(EMDL_IMAGE_NAME, fn_img);
+   		img.read(fn_img);
+   		mysize=(int)XSIZE(img());
+		BackProjector backprojectort(mysize, ref_dim, fn_sym, interpolator, padding_factor, r_min_nn, blob_order, blob_radius, blob_alpha);
+		backprojectort.initZeros(2 * r_max);
+
+		Image<double> Imagn, Iphas, Iw, tvol;
+		Imagn.read("FEW_it24_rank2_data_magn.spi");
+		Iphas.read("FEW_it24_rank2_data_phas.spi");
+		Iw.read("FEW_it24_rank2_weight.spi");
+        Iw().setXmippOrigin();
+        Iw().xinit=0;
+
+		// Write out invw
+		Image<double> oo;
+		oo=Iw;
+		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Iw())
+		{
+			if (DIRECT_MULTIDIM_ELEM(Iw(), n) > 1e-2)
+				DIRECT_MULTIDIM_ELEM(oo(), n) = 1./ DIRECT_MULTIDIM_ELEM(Iw(), n);
+		}
+		oo.write("invw.spi");
+
+		Imagn().printShape();
+		backprojectort.data.printShape();
+		backprojectort.weight.printShape();
+		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Imagn())
+		{
+			double realval = sin(DIRECT_MULTIDIM_ELEM(Iphas(), n)) * DIRECT_MULTIDIM_ELEM(Imagn(), n);
+			double imagval = cos(DIRECT_MULTIDIM_ELEM(Iphas(), n)) * DIRECT_MULTIDIM_ELEM(Imagn(), n);
+			DIRECT_MULTIDIM_ELEM(backprojectort.data, n) = (Complex)(realval, imagval);
+		}
+		backprojectort.weight = Iw();
+  		std::cerr << "Starting the reconstruction ..." << std::endl;
+   		backprojectort.reconstruct(tvol(), iter, false, 1., dummy, dummy, dummy, dummy, 1., false, false, nr_threads, -1);
+    	tvol.write(fn_out);
+    	std::cerr<<" Done writing TMPPPPPPPPPPPPPPPPP debugging!!!c map in "<<fn_out<<std::endl;
+		exit(0);
+#endif
+
+
+   		// Get dimension of the images
+		(DF).firstObject();
+		DF.getValue(EMDL_IMAGE_NAME, fn_img);
+		img.read(fn_img);
+		mysize=(int)XSIZE(img());
+
+   		if (DF.containsLabel(EMDL_CTF_MAGNIFICATION) && DF.containsLabel(EMDL_CTF_DETECTOR_PIXEL_SIZE))
+    	{
+    		double mag, dstep;
+   			DF.getValue(EMDL_CTF_MAGNIFICATION, mag);
+   			DF.getValue(EMDL_CTF_DETECTOR_PIXEL_SIZE, dstep);
+   			angpix = 10000. * dstep / mag;
+   			std::cout << " + Using pixel size calculated from magnification and detector pixel size in the input STAR file: " << angpix << std::endl;
+    	}
+
+   		BackProjector backprojector(mysize, ref_dim, fn_sym, interpolator, padding_factor, r_min_nn, blob_order, blob_radius, blob_alpha);
+
+   		if (maxres < 0.)
+   			r_max = -1;
+   		else
+   			r_max = CEIL(mysize * angpix / maxres);
+
+   		backprojector.initZeros(2 * r_max);
+   		Projector projector(mysize, interpolator, padding_factor, r_min_nn);
+
+   		if (fn_sub != "")
+   		{
+   			sub.read(fn_sub);
+   			projector.computeFourierTransformMap(sub(), dummy, 2 * r_max);
+   		}
+
+		// Check for beam-tilt parameters in the input star file
+   		if (do_beamtilt && ( DF.containsLabel(EMDL_IMAGE_BEAMTILT_X) || DF.containsLabel(EMDL_IMAGE_BEAMTILT_Y) ) )
+   				std::cout << " + Using the beamtilt parameters in the input STAR file" << std::endl;
+
+		std::cerr << "Back-projecting all images ..." << std::endl;
+   		int imgno = 0;
+		time_config();
+   		init_progress_bar(DF.size());
+   		FOR_ALL_OBJECTS_IN_METADATA_TABLE(DF)
+   		{
+
+   			DF.getValue(EMDL_IMAGE_NAME, fn_img);
+   			img.read(fn_img);
+   			img().setXmippOrigin();
+
+			// Rotations
+			if (ref_dim==2)
+   			{
+   				rot = tilt = 0.;
+   			}
+   			else
+   			{
+   				DF.getValue( EMDL_ORIENT_ROT, rot);
+   				DF.getValue( EMDL_ORIENT_TILT, tilt);
+   			}
+  			psi = 0.;
+  			DF.getValue( EMDL_ORIENT_PSI, psi);
+  			if (angular_error > 0.)
+  			{
+  				rot += rnd_gaus(0., angular_error);
+  				tilt += rnd_gaus(0., angular_error);
+  				psi += rnd_gaus(0., angular_error);
+  				//std::cout << rnd_gaus(0., angular_error) << std::endl;
+  			}
+
+   			Euler_angles2matrix(rot, tilt, psi, A3D);
+
+   			// Translations (either through phase-shifts or in real space
+   			trans.initZeros();
+   			DF.getValue( EMDL_ORIENT_ORIGIN_X, XX(trans));
+   			DF.getValue( EMDL_ORIENT_ORIGIN_Y, YY(trans));
+  			if (shift_error > 0.)
+   			{
+   				XX(trans) += rnd_gaus(0., shift_error);
+   				YY(trans) += rnd_gaus(0., shift_error);
+   			}
+
+   			if (do_fom_weighting)
+   				DF.getValue( EMDL_PARTICLE_FOM, fom);
+
+
+   			// Use either selfTranslate OR shiftImageInFourierTransform!!
+   			//selfTranslate(img(), trans, WRAP);
+   			CenterFFT(img(), true);
+   			transformer.FourierTransform(img(), F2D);
+   			if (ABS(XX(trans)) > 0. || ABS(YY(trans)) > 0.)
+   				shiftImageInFourierTransform(F2D, F2D, XSIZE(img()), trans );
+
+			Fctf.resize(F2D);
+			Fctf.initConstant(1.);
+			// Apply CTF if necessary
+			if (do_ctf)
+			{
+				CTF ctf;
+				ctf.read(DF, DF);
+				ctf.getFftwImage(Fctf, mysize, mysize, angpix, ctf_phase_flipped, only_flip_phases, intact_ctf_first_peak, true);
+
+				if (do_beamtilt || (DF.containsLabel(EMDL_IMAGE_BEAMTILT_X) && DF.containsLabel(EMDL_IMAGE_BEAMTILT_Y) ))
+				{
+					if (DF.containsLabel(EMDL_IMAGE_BEAMTILT_X))
+						DF.getValue(EMDL_IMAGE_BEAMTILT_X, beamtilt_x);
+					if (DF.containsLabel(EMDL_IMAGE_BEAMTILT_Y))
+						DF.getValue(EMDL_IMAGE_BEAMTILT_Y, beamtilt_y);
+					selfApplyBeamTilt(F2D, beamtilt_x, beamtilt_y, ctf.lambda, ctf.Cs, angpix, mysize);
+				}
+			}
+
+			// Subtract reference projection
+			if (fn_sub != "")
+			{
+				Fsub.resize(F2D);
+				projector.get2DFourierTransform(Fsub, A3D, IS_NOT_INV);
+
+				// Apply CTF if necessary
+				if (do_ctf)
+				{
+					FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fsub)
+					{
+						DIRECT_MULTIDIM_ELEM(Fsub, n) *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+					}
+				}
+
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fsub)
+				{
+					DIRECT_MULTIDIM_ELEM(F2D, n) -= DIRECT_MULTIDIM_ELEM(Fsub, n);
+				}
+				// Back-project difference image
+				backprojector.set2DFourierTransform(F2D, A3D, IS_NOT_INV);
+			}
+			else
+			{
+				// "Normal" reconstruction, multiply X by CTF, and W by CTF^2
+				if (do_ctf)
+				{
+					FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(F2D)
+					{
+						DIRECT_MULTIDIM_ELEM(F2D, n)  *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+						DIRECT_MULTIDIM_ELEM(Fctf, n) *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+					}
+				}
+
+				// Do the following after squaring the CTFs!
+				if (do_fom_weighting)
+				{
+					FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(F2D)
+					{
+						DIRECT_MULTIDIM_ELEM(F2D, n)  *= fom;
+						DIRECT_MULTIDIM_ELEM(Fctf, n)  *= fom;
+					}
+				}
+
+//#define DEBUG_RECONSTRUCT_ONLY
+#ifdef DEBUG_RECONSTRUCT_ONLY
+					if (fn_img == "/lmb/home/scheres/data/betaGal_rh_withnoise/betaGal_2010_all_p_2x2_unflipped/img00001.win100")
+					//if (part_id == my_first_particle_id)
+					{
+						std::cerr << " fn_img= " << fn_img << std::endl;
+						//std::cerr << " myscale= " << myscale << std::endl;
+						//std::cerr << " mymodel.avg_norm_correction= " << mymodel.avg_norm_correction << " normcorr= " << normcorr << std::endl;
+						//std::cerr << " sigma2_fudge= " << sigma2_fudge << " mymodel.tau2_fudge_factor= " << mymodel.tau2_fudge_factor<< std::endl;
+						//std::cerr << " A3D= " << A3D << std::endl;
+						std::cerr << " A3D= " << A3D << std::endl;
+						//std::cerr << " exp_R_mic= " << exp_R_mic << std::endl;
+						std::cerr << " rot= " << rot << " tilt= " << tilt << " psi= " << psi << " xoff= "<< XX(trans)<< " yoff= "<<YY(trans)<<std::endl;
+						//std::cerr << "mic_id= "<<mic_id<<" mymodel.sigma2_noise[mic_id]= " << mymodel.sigma2_noise[mic_id] << std::endl;
+						Image<double> It;
+						It()=Fctf;
+						It.write("reconstruct_Fctf.spi");
+						It().resize(mysize, mysize);
+						MultidimArray<Complex > Faux = F2D;
+						FourierTransformer transformer;
+						transformer.inverseFourierTransform(Faux, It());
+						CenterFFT(It(), false);
+						It.write("reconstruct_Mimg.spi");
+					}
+#endif
+
+
+				backprojector.set2DFourierTransform(F2D, A3D, IS_NOT_INV, &Fctf);
+			}
+
+
+
+   			if (imgno++%60==0)
+   				progress_bar(imgno);
+		}
+   		progress_bar(DF.size());
+
+
+   		bool do_map = false;
+   		bool do_use_fsc = false;
+   		MultidimArray<double> fsc;
+   		fsc.resize(mysize/2+1);
+   		if (fn_fsc != "")
+   		{
+   			do_map = true;
+   			do_use_fsc =true;
+   			MetaDataTable MDfsc;
+   			MDfsc.read(fn_fsc);
+   			FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDfsc)
+   			{
+   				int idx;
+   				double val;
+   				MDfsc.getValue(EMDL_SPECTRAL_IDX, idx);
+   				MDfsc.getValue(EMDL_MLMODEL_FSC_HALVES_REF, val);
+   				fsc(idx) =  val;
+   			}
+   		}
+   		std::cerr << "Starting the reconstruction ..." << std::endl;
+   		backprojector.reconstruct(vol(), iter, do_map, 1., dummy, dummy, dummy, fsc, 1., do_use_fsc, true, nr_threads, -1);
+
+   		vol.write(fn_out);
+    	std::cerr<<" Done writing map in "<<fn_out<<std::endl;
+
+	}
+	}
+
+
+};
+
+
+int main(int argc, char *argv[])
+{
+	reconstruct_parameters prm;
+
+	try
+    {
+
+		prm.read(argc, argv);
+
+		prm.reconstruct();
+
+    }
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+    return 0;
+}
+
+
diff --git a/src/apps/refine.cpp b/src/apps/refine.cpp
new file mode 100644
index 0000000..5d268c5
--- /dev/null
+++ b/src/apps/refine.cpp
@@ -0,0 +1,51 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include <src/ml_optimiser.h>
+
+/**************************************************************************
+        Main
+ **************************************************************************/
+int main(int argc, char **argv)
+{
+	MlOptimiser optimiser;
+
+    try
+    {
+    	// Read in parameters from the command line
+    	optimiser.read(argc, argv);
+
+    	// Set up things
+    	optimiser.initialise();
+
+    	// Do the real work
+    	optimiser.iterate();
+
+    }
+
+    catch (RelionError XE)
+    {
+        optimiser.usage();
+        std::cerr << XE;
+        exit(1);
+    }
+
+    exit(0);
+}
diff --git a/src/apps/refine_mpi.cpp b/src/apps/refine_mpi.cpp
new file mode 100644
index 0000000..bcd1ce8
--- /dev/null
+++ b/src/apps/refine_mpi.cpp
@@ -0,0 +1,57 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include <src/ml_optimiser_mpi.h>
+
+
+int main(int argc, char **argv)
+{
+
+	MlOptimiserMpi optimiser;
+    try
+    {
+    	// Read in parameters from the command line
+    	optimiser.read(argc, argv);
+
+    	// Set things up
+    	optimiser.initialise();
+
+    	// Iterate
+    	optimiser.iterate();
+
+    }
+    catch (RelionError XE)
+    {
+        if (optimiser.verb > 0)
+        {
+        	optimiser.usage();
+        }
+    	std::cerr << XE;
+
+        MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
+
+    }
+
+    MPI_Finalize();
+
+    exit(0);
+
+}
+
diff --git a/src/apps/run_ctffind.cpp b/src/apps/run_ctffind.cpp
new file mode 100644
index 0000000..343860d
--- /dev/null
+++ b/src/apps/run_ctffind.cpp
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <src/ctffind_runner.h>
+
+
+int main(int argc, char *argv[])
+{
+	CtffindRunner prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.initialise();
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
+
diff --git a/src/apps/run_ctffind_mpi.cpp b/src/apps/run_ctffind_mpi.cpp
new file mode 100644
index 0000000..54327d0
--- /dev/null
+++ b/src/apps/run_ctffind_mpi.cpp
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <src/ctffind_runner_mpi.h>
+
+
+int main(int argc, char *argv[])
+{
+	CtffindRunnerMpi prm;
+
+	try
+    {
+		prm.read(argc, argv);
+
+		prm.initialise();
+
+		prm.run();
+    }
+
+    catch (RelionError XE)
+    {
+        prm.usage();
+        std::cout << XE;
+        exit(1);
+    }
+
+    return 0;
+
+}
+
+
diff --git a/src/apps/stack_create.cpp b/src/apps/stack_create.cpp
new file mode 100644
index 0000000..7c1f226
--- /dev/null
+++ b/src/apps/stack_create.cpp
@@ -0,0 +1,216 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include <src/image.h>
+#include <src/funcs.h>
+#include <src/ctf.h>
+#include <src/args.h>
+#include <src/error.h>
+#include <src/euler.h>
+#include <src/time.h>
+
+class stack_create_parameters
+{
+	public:
+   	FileName fn_star, fn_root, fn_ext;
+	MetaDataTable MD;
+	// I/O Parser
+	IOParser parser;
+	bool do_spider, do_split_per_micrograph, do_apply_trans;
+
+	void usage()
+	{
+		parser.writeUsage(std::cerr);
+	}
+
+	void read(int argc, char **argv)
+	{
+
+		parser.setCommandLine(argc, argv);
+
+		int general_section = parser.addSection("General options");
+	    fn_star = parser.getOption("--i", "Input STAR file with the images (as rlnImageName) to be saved in a stack");
+	    fn_root = parser.getOption("--o", "Output rootname","output");
+	    do_spider  = parser.checkOption("--spider_format", "Write out in SPIDER stack format (by default MRC stack format)");
+	    do_split_per_micrograph = parser.checkOption("--split_per_micrograph", "Write out separate stacks for each micrograph (needs rlnMicrographName in STAR file)");
+	    do_apply_trans = parser.checkOption("--apply_transformation", "Apply the inplane-transformations (needs _rlnOriginX/Y and _rlnAnglePsi in STAR file)");
+
+	    fn_ext = (do_spider) ? ".spi" : ".mrcs";
+
+      	// Check for errors in the command-line option
+    	if (parser.checkForErrors())
+    		REPORT_ERROR("Errors encountered on the command line, exiting...");
+	}
+
+
+	void run()
+	{
+		MD.read(fn_star);
+
+		// Check for rlnImageName label
+		if (!MD.containsLabel(EMDL_IMAGE_NAME))
+			REPORT_ERROR("ERROR: Input STAR file does not contain the rlnImageName label");
+
+		if (do_split_per_micrograph && !MD.containsLabel(EMDL_MICROGRAPH_NAME))
+			REPORT_ERROR("ERROR: Input STAR file does not contain the rlnMicrographName label");
+
+		Image<double> in;
+		FileName fn_img, fn_mic;
+		std::vector<FileName> fn_mics;
+		std::vector<int> mics_ndims;
+
+		// First get number of images and their size
+		int ndim=0;
+		bool is_first=true;
+		int xdim, ydim, zdim;
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MD)
+		{
+			if (is_first)
+			{
+				MD.getValue(EMDL_IMAGE_NAME, fn_img);
+				in.read(fn_img);
+				xdim=XSIZE(in());
+				ydim=YSIZE(in());
+				zdim=ZSIZE(in());
+				is_first=false;
+			}
+
+			if (do_split_per_micrograph)
+			{
+				MD.getValue(EMDL_MICROGRAPH_NAME, fn_mic);
+				bool have_found = false;
+				for (int m = 0; m < fn_mics.size(); m++)
+				{
+					if (fn_mic == fn_mics[m])
+					{
+						have_found = true;
+						mics_ndims[m]++;
+						break;
+					}
+				}
+				if (!have_found)
+				{
+					fn_mics.push_back(fn_mic);
+					mics_ndims.push_back(1);
+				}
+			}
+			ndim++;
+		}
+
+
+		// If not splitting, just fill fn_mics and mics_ndim with one entry (to re-use loop below)
+		if (!do_split_per_micrograph)
+		{
+			fn_mics.push_back("");
+			mics_ndims.push_back(ndim);
+		}
+
+
+		// Loop over all micrographs
+		for (int m = 0; m < fn_mics.size(); m++)
+		{
+			ndim = mics_ndims[m];
+			fn_mic = fn_mics[m];
+
+			// Resize the output image
+			std::cout << "Resizing the output stack to "<< ndim<<" images of size: "<<xdim<<"x"<<ydim<<"x"<<zdim << std::endl;
+			double Gb = ndim*zdim*ydim*xdim*8./1024./1024./1024.;
+			std::cout << "This will require " << Gb << "Gb of memory...."<< std::endl;
+			Image<double> out(xdim, ydim, zdim, ndim);
+
+			int n = 0;
+			init_progress_bar(ndim);
+			FOR_ALL_OBJECTS_IN_METADATA_TABLE(MD)
+			{
+				FileName fn_mymic;
+				if (do_split_per_micrograph)
+					MD.getValue(EMDL_MICROGRAPH_NAME, fn_mymic);
+				else
+					fn_mymic="";
+
+				if (fn_mymic == fn_mic)
+				{
+
+					MD.getValue(EMDL_IMAGE_NAME, fn_img);
+					in.read(fn_img);
+
+					if (do_apply_trans)
+					{
+						double xoff = 0.;
+						double yoff = 0.;
+						double psi = 0.;
+						MD.getValue(EMDL_ORIENT_ORIGIN_X, xoff);
+						MD.getValue(EMDL_ORIENT_ORIGIN_Y, yoff);
+						MD.getValue(EMDL_ORIENT_PSI, psi);
+						// Apply the actual transformation
+						Matrix2D<double> A;
+						rotation2DMatrix(psi, A);
+					    MAT_ELEM(A,0, 2) = xoff;
+					    MAT_ELEM(A,1, 2) = yoff;
+					    selfApplyGeometry(in(), A, IS_NOT_INV, DONT_WRAP);
+					}
+
+					out().setImage(n, in());
+					n++;
+					if (n%100==0) progress_bar(n);
+
+				}
+			}
+			progress_bar(ndim);
+
+
+			FileName fn_out;
+			if (do_split_per_micrograph)
+			{
+				// Remove any extensions from micrograph names....
+				fn_out = fn_root + "_" + fn_mic.withoutExtension() + fn_ext;
+			}
+			else
+				fn_out = fn_root + fn_ext;
+			out.write(fn_out);
+			std::cout << "Written out: " << fn_out << std::endl;
+		}
+		std::cout << "Done!" <<std::endl;
+	}
+
+};
+
+
+int main(int argc, char *argv[])
+{
+	stack_create_parameters prm;
+
+	try
+    {
+
+		prm.read(argc, argv);
+
+		prm.run();
+
+    }
+    catch (RelionError XE)
+    {
+        std::cout << XE;
+        prm.usage();
+        exit(1);
+    }
+    return 0;
+}
+
diff --git a/src/args.cpp b/src/args.cpp
new file mode 100644
index 0000000..e4d9d23
--- /dev/null
+++ b/src/args.cpp
@@ -0,0 +1,364 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include "src/args.h"
+#include "src/gcc_version.h"
+#include "src/matrix1d.h"
+
+// Get parameters from the command line ====================================
+std::string getParameter(int argc, char **argv, const std::string param, const std::string option)
+{
+    int i = 0;
+
+    while ((i < argc) && (strcmp(param.c_str(), argv[i])))
+        i++;
+    if (i < argc - 1)
+    {
+        return(argv[i+1]);
+    }
+    else
+    {
+    	if (option != "NULL")
+    	{
+    		return (std::string)option;
+    	}
+    	else
+        {
+            std::string auxstr;
+            auxstr = (std::string)"Argument " + param + " not found or invalid argument";
+            REPORT_ERROR(auxstr);
+        }
+    }
+}
+
+// Checks if a boolean parameter was included the command line =============
+bool checkParameter(int argc, char **argv, std::string param)
+{
+    int i = 0;
+
+    while ((i < argc) && (strcmp(param.c_str(), argv[i]) != 0))
+        i++;
+
+    if (i < argc)
+        return(true);
+    else
+        return(false);
+}
+
+
+IOParser::IOParser()
+{
+	clear();
+
+}
+
+IOParser::IOParser(const IOParser &in)
+{
+	copy(in);
+}
+
+IOParser& IOParser::operator= (const IOParser &in)
+{
+	copy(in);
+}
+
+IOParser::~IOParser()
+{
+	clear();
+}
+
+
+void IOParser::copy(const IOParser &in)
+{
+	options = in.options;
+	usages = in.usages;
+	optionals = in.optionals;
+	defaultvalues = in.defaultvalues;
+	argc = in.argc;
+	argv = in.argv;
+	error_messages = in.error_messages;
+	warning_messages = in.warning_messages;
+	current_section = in.current_section;
+	section_names = in.section_names;
+	section_numbers = in.section_numbers;
+}
+
+void IOParser::clear()
+{
+	argc = 0;
+	argv = NULL;
+	options.clear();
+	usages.clear();
+	optionals.clear();
+	defaultvalues.clear();
+	error_messages.clear();
+	warning_messages.clear();
+	section_names.clear();
+	section_numbers.clear();
+	current_section = 0;
+}
+
+void IOParser::setCommandLine(int _argc, char** _argv)
+{
+	argc = _argc;
+	argv = _argv;
+}
+
+void IOParser::addOption(std::string option, std::string usage, std::string defaultvalue)
+{
+	if (section_names.size() == 0)
+		REPORT_ERROR("IOParser::addOption: ERROR First add a section to the parser, then the options!");
+	options.push_back(option);
+	usages.push_back(usage);
+	section_numbers.push_back(current_section);
+	if (defaultvalue == "NULL")
+	{
+		optionals.push_back(false);
+		defaultvalues.push_back(" ");
+	}
+	else
+	{
+		optionals.push_back(true);
+		defaultvalues.push_back((std::string)defaultvalue);
+	}
+}
+
+int IOParser::addSection(std::string name)
+{
+	current_section = section_names.size();
+	section_names.push_back(name);
+	return current_section;
+}
+
+/** Set the current section to this number */
+void IOParser::setSection(int number)
+{
+	current_section = number;
+}
+
+bool IOParser::optionExists(std::string option)
+{
+	int ii;
+	for (ii = 0; ii < options.size(); ii++)
+		if (strcmp((options[ii]).c_str(), option.c_str()) == 0)
+			return true;
+
+	return false;
+
+}
+
+std::string IOParser::getOption(std::string option, std::string usage, std::string defaultvalue)
+{
+
+	// If this option did not exist yet, add it to the list
+	if (!optionExists(option))
+		addOption(option, usage, defaultvalue);
+
+    int i = 0;
+
+    while ((i < argc) && (strcmp(option.c_str(), argv[i])))
+        i++;
+    if (i < argc - 1)
+    {
+        return(argv[i+1]);
+    }
+    else
+    {
+    	if (defaultvalue != "NULL")
+    	{
+    		return (std::string)defaultvalue;
+    	}
+    	else
+        {
+            std::string auxstr;
+            auxstr = (std::string)"ERROR: Argument " + option + " not found or invalid argument";
+            error_messages.push_back(auxstr);
+            return "";
+        }
+    }
+
+}
+// Checks if a boolean parameter was included the command line =============
+bool IOParser::checkOption(std::string option, std::string usage, std::string defaultvalue)
+{
+	// If this option did not exist yet, add it to the list
+	if (!optionExists(option))
+		addOption(option, usage, defaultvalue);
+
+	return checkParameter(argc, argv, option);
+}
+
+void IOParser::writeCommandLine(std::ostream &out)
+{
+	for (int i = 1; i < argc; i++)
+		out << argv[i] << " ";
+	out << std::endl;
+
+}
+
+bool IOParser::checkForErrors(int verb)
+{
+
+	// First check the command line for unknown arguments
+	checkForUnknownArguments();
+
+	// First print warning messages
+	if (warning_messages.size() > 0)
+	{
+		if (verb > 0)
+		{
+			std::cerr << "The following warnings were encountered upon command-line parsing: " << std::endl;
+			for (unsigned int i = 0; i < warning_messages.size(); ++i)
+				std::cerr << warning_messages[i] << std::endl;
+		}
+	}
+
+	// Then check for error messages
+	if (error_messages.size() > 0)
+	{
+		if (verb > 0)
+		{
+			std::cerr << "The following errors were encountered upon command-line parsing: " << std::endl;
+			for (unsigned int i = 0; i < error_messages.size(); ++i)
+				std::cerr << error_messages[i] << std::endl;
+		}
+		return true;
+	}
+	else
+		return false;
+
+}
+
+void IOParser::checkForUnknownArguments()
+{
+	for (int i = 1; i < argc; i++)
+	{
+		// Valid options should start with "--"
+		bool is_ok = true;
+		if (strncmp("--", argv[i], 2) == 0)
+		{
+			if (!optionExists((std::string)argv[i]))
+			{
+				is_ok = false;
+			}
+		}
+		// If argv[i] starts with one "-": check it is a number and argv[i-1] is a valid option
+		else if (strncmp("--", argv[i], 1) == 0)
+		{
+			float testval;
+			// test whether this is a number
+			int is_a_number = sscanf(argv[i], "%f", &testval);
+		    if (is_a_number)
+		    {
+		    	// check whether  argv[i-1] is a valid option
+		    	if (!optionExists(argv[i-1]))
+		    		is_ok = false;
+		    }
+		    else
+		    	is_ok = false;
+		}
+
+		if (!is_ok)
+		{
+			std::string auxstr;
+			auxstr = (std::string)"WARNING: Option " + argv[i] + " is not a valid argument";
+			warning_messages.push_back(auxstr);
+		}
+
+
+	}
+}
+
+void IOParser::writeUsageOneLine(int i, std::ostream &out)
+{
+	std::string aux = "  ";
+	aux += options[i];
+
+	if (optionals[i])
+	{
+		aux += " (";
+		aux += defaultvalues[i];
+		aux += ")";
+	}
+
+	out << std::setw(35) << aux;
+	out << " : ";
+	out << usages[i];
+	out << std::endl;
+
+}
+
+void IOParser::writeUsageOneSection(int section, std::ostream &out)
+{
+	// First write all compulsory options
+	//out << "+++ Compulsory:" << std::endl;
+	for (int i = 0; i < options.size(); i++)
+	{
+		if (!optionals[i] && section_numbers[i] == section)
+			writeUsageOneLine(i, out);
+	}
+
+	// Then write optional ones
+	//out << "+++ Optional (defaults between parentheses):" << std::endl;
+	for (int i = 0; i < options.size(); i++)
+	{
+		if (optionals[i] && section_numbers[i] == section)
+			writeUsageOneLine(i, out);
+	}
+
+}
+
+void IOParser::writeUsage(std::ostream &out)
+{
+
+	out << "+++ RELION: command line arguments (with defaults for optional ones between parantheses) +++"<<std::endl;
+
+	for (int section = 0; section < section_names.size(); section++)
+	{
+		out << "====== " << section_names[section] << " ===== " << std::endl;
+		writeUsageOneSection(section, out);
+	}
+
+}
+
diff --git a/src/args.h b/src/args.h
new file mode 100644
index 0000000..9315736
--- /dev/null
+++ b/src/args.h
@@ -0,0 +1,208 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+*
+* Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+*
+* Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+*
+* 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
+*
+*  All comments concerning this program package may be sent to the
+*  e-mail address 'xmipp at cnb.csic.es'
+***************************************************************************/
+
+#ifndef ARGS_H
+#define ARGS_H
+
+#include <cstdio>
+#include <iostream>
+#include <iomanip>
+#include <string>
+#include <vector>
+//ROB
+#include <string.h>
+
+#include "src/funcs.h"
+#include "src/matrix1d.h"
+template <typename T> class Matrix1D;
+
+
+/** @defgroup Arguments Functions for parsing the command line
+ *
+ * These functions help you to manage the command line parameters
+ */
+
+/** Get parameters from the command line.
+ * @ingroup CommandLineFunctions
+ *
+ * This function assumes that the command line is structured in such a way that
+ * for each parameter a block like "-param <param_value>" is defined. The label
+ * "param" can be substituted by any other one you like. If the parameter is
+ * optional then this function allows you to define a default value. If no
+ * default value is supplied and the parameter is not specified in the command
+ * line, then an exception is thrown. You may change the default exception.
+ *
+ * You may also indicate that in case of error no exception is raised and force
+ * the program to abort (use the exit variable).
+ *
+ * @code
+ * m_param = textToFloat(getParameter(argc, argv, "-m"));
+ *
+ * // Get compulsory parameter "-m"
+ * m_param = textToFloat(getParameter(argc, argv, "-m","2.65"));
+ *
+ * // Optional parameter, if no parameter is given it takes 2.65 by default
+ * m_param = textToFloat(getParameter(argc, argv, "-m", NULL, 6001, "-m parameter not \
+ *     found. I'm going out", TRUE);
+ *
+ * // Compulsory parameter, if not found give an special error message and exit
+ * // the program
+ *
+ * @endcode
+ */
+std::string getParameter(int argc,
+                char** argv,
+                std::string param,
+                std::string option = "NULL");
+
+/** Get boolean parameters from the command line.
+ * @ingroup CommandLineFunctions
+ *
+ * This function assumes that the command line is structured in such a way that
+ * for each parameter a block like "-param" is defined. The label "param" can be
+ * substituted by any other one you like. It might be used to look for a boolean
+ * parameter, for instance:
+ *
+ *     -verbose means that verbose functionality is set (TRUE)
+ *
+ * @code
+ * verbose = checkParameter(argc, argv, "-verbose"));
+ *
+ * // checks if "-verbose" was supplied in the command line. If -verbose was
+ * // supplied the function returns TRUE (1), otherwise returns FALSE (0)
+ * @endcode
+ */
+bool checkParameter(int argc, char** argv, std::string param);
+
+
+class IOParser
+{
+private:
+
+	std::vector<std::string> options;
+	std::vector<std::string> usages;
+	std::vector<bool>        optionals;
+	std::vector<std::string> defaultvalues;
+	std::vector<int>         section_numbers;
+	std::vector<std::string> section_names;
+	std::vector<std::string> error_messages;
+	std::vector<std::string> warning_messages;
+
+	int current_section;
+
+	// The original command line
+	int argc;
+	char** argv;
+
+public:
+
+    /** Constructor */
+    IOParser();
+
+    /** Copy constructor */
+    IOParser(const IOParser &in);
+
+    /**Assignment operator */
+    IOParser& operator= (const IOParser &in);
+
+    /** Destructor */
+    ~IOParser();
+
+    /** Copy everything from input to this */
+    void copy(const IOParser &in);
+
+    /** Clear object */
+    void clear();
+
+    /** Store pointer to command line */
+    void setCommandLine(int _argc, char** _argv);
+
+    /** Check whether option exists in the stored options */
+    bool optionExists(std::string option);
+
+    /** Add a section to the parser, and set the current section to the newly created one, returns number of current section */
+    int addSection(std::string name);
+
+    /** Set the current section to this number */
+    void setSection(int number);
+
+    /** Get the current section to this number */
+    int getSection()
+    {
+    	return current_section;
+    }
+
+    /** Add an option to the object list */
+    void addOption(std::string option, std::string usage, std::string defaultvalue = "NULL");
+
+    /** Get the value from the command line, and adds option to the list if it did not yet exist */
+    std::string getOption(std::string option, std::string usage, std::string defaultvalue = "NULL");
+
+    /** Returns true if option was given and false if not, and adds option to the list if it did not yet exist */
+	bool checkOption(std::string option, std::string usage, std::string defaultvalue = "false");
+
+    /** Checks the whole command line and reports an error if it contains an undefined option */
+    bool commandLineContainsUndefinedOption();
+
+    /** Write the stored command line to outstream */
+    void writeCommandLine(std::ostream &outstream);
+
+    /** Returns true is there were any error messages (and prints them if verb>0 */
+    bool checkForErrors(int verb = 1);
+
+    /** Check the whole command line for invalid arguments, if found add to the error messages */
+    void checkForUnknownArguments();
+
+    /** Write one line of the usage to outstream */
+    void writeUsageOneLine(int i, std::ostream &out);
+
+    /** Write one section of the usage to outstream */
+   void writeUsageOneSection(int section, std::ostream &out);
+
+    /** Write the usage for all options to outstream */
+    void writeUsage(std::ostream &outstream);
+};
+
+
+#endif
diff --git a/src/assembly.cpp b/src/assembly.cpp
new file mode 100644
index 0000000..44c7471
--- /dev/null
+++ b/src/assembly.cpp
@@ -0,0 +1,420 @@
+/*
+ * assembly.cpp
+ *
+ *  Created on: Apr 16, 2013
+ *      Author: "Sjors H.W. Scheres"
+ */
+
+#include "src/assembly.h"
+
+void Atom::clear()
+{
+    name = "";
+    occupancy = bfactor = 0.;
+    coords.clear();
+}
+
+Matrix1D<double> Atom::getCoordinates()
+{
+	return coords;
+}
+
+void Residue::clear()
+{
+	number = -1;
+	name = "";
+	atoms.clear();
+}
+
+long int Residue::addAtom(std::string atomname, double x, double y, double z, double occ, double bfac)
+{
+	Atom atom(atomname);
+	atom.coords = vectorR3(x,y,z);
+	atom.occupancy = occ;
+	atom.bfactor = bfac;
+	long int result = atoms.size();
+	atoms.push_back(atom);
+	return result;
+}
+
+void Molecule::clear()
+{
+	name = "";
+	alt_name = "";
+	residues.clear();
+}
+
+long int Molecule::insertResidue(Residue &res, int pos)
+{
+	long int result = residues.size();
+	residues.insert(residues.begin() + pos, res);
+	return result;
+}
+
+long int Molecule::addResidue(Residue &res)
+{
+	long int result = residues.size();
+	residues.push_back(res);
+	return result;
+}
+
+long int Molecule::addResidue(std::string name, int resnum)
+{
+	Residue residue(name, resnum);
+	long int result = residues.size();
+	residues.push_back(residue);
+	return result;
+}
+
+void Molecule::insertResidues(Molecule add, int residue_start, int residue_end)
+{
+
+	int add_nResidues, this_nResidues;
+	int ires_start = -1, ires_end = -1;
+
+	add_nResidues = add.numberOfResidues();
+
+	if (residue_start < 0 && residue_end < 0)
+	{
+		// Add whole chain
+		ires_start = 0;
+		ires_end = add_nResidues-1;
+	}
+	else
+	{
+		// Find beginning and ending ires
+		for (int ires = 0; ires < add_nResidues; ires++)
+		{
+			if (residue_start == add.residues[ires].number)
+				ires_start = ires;
+			if (residue_end == add.residues[ires].number)
+				ires_end = ires;
+		}
+	}
+
+	if (ires_start < 0 || ires_end < 0)
+	{
+		std::cerr << " ires_start= " << ires_start << " ires_end= " << ires_end << std::endl;
+		std::cerr << " residue_start= " << residue_start << " residue_end= " << residue_end << std::endl;
+		REPORT_ERROR("OrigamiBuilder::insertBases ERROR: negative ires_start or ires_end");
+	}
+
+	for (int ires = ires_start; ires <= ires_end; ires++)
+	{
+		int my_res = add.residues[ires].number;
+		bool have_inserted=false;
+		for (int ii = 0; ii < numberOfResidues(); ii++)
+		{
+			if (residues[ii].number > my_res)
+			{
+				insertResidue(add.residues[ires], ii);
+				have_inserted = true;
+				break;
+			}
+		}
+		if (!have_inserted)
+			addResidue(add.residues[ires]);
+	}
+
+}
+
+void Assembly::clear()
+{
+     name = "";
+     molecules.clear();
+}
+
+long int Assembly::addMolecule(std::string _name, std::string alt_name)
+{
+	Molecule molecule(_name, alt_name);
+	long int result = molecules.size();
+	molecules.push_back(molecule);
+	return result;
+}
+
+long int Assembly::addMolecule(Molecule &toadd)
+{
+
+	std::string ori_toadd_name = simplify(toadd.name);
+	// Check whether the name of this molecule is unique
+	// If not add a suffix to it
+	bool is_uniq = false;
+	int suffix = 0;
+	while (!is_uniq)
+	{
+		suffix++;
+		is_uniq = true;
+		for (int imol = 0; imol < molecules.size(); imol++)
+		{
+			if (molecules[imol].name == toadd.name)
+			{
+				is_uniq = false;
+				break;
+			}
+		}
+		if (!is_uniq)
+		{
+			toadd.name = ori_toadd_name + integerToString(suffix);
+		}
+
+	}
+	long int result = molecules.size();
+	molecules.push_back(toadd);
+	return result;
+
+}
+
+long int Assembly::numberOfMolecules() const
+{
+	return molecules.size();
+}
+
+long int Assembly::numberOfResidues() const
+{
+	long int sum = 0;
+	for (int imol = 0; imol < molecules.size(); imol++)
+		sum += molecules[imol].residues.size();
+	return sum;
+}
+
+long int Assembly::numberOfAtoms() const
+{
+	long int sum = 0;
+	for (int imol = 0; imol < molecules.size(); imol++)
+		for (int ires = 0; ires < molecules[imol].residues.size(); ires++)
+			sum += molecules[imol].residues[ires].atoms.size();
+	return sum;
+}
+
+void Assembly::printInformation(std::ostream& out) const
+{
+	out << " Assembly: " << name << std::endl;
+	out << " - Number of molecules : " << numberOfMolecules() << std::endl;
+	out << " - Number of residues  : " << numberOfResidues() << std::endl;
+	out << " - Number of atoms     : " << numberOfAtoms() << std::endl;
+
+}
+
+
+void Assembly::readPDB(std::string filename, bool use_segid_instead_of_chainid, bool do_sort)
+{
+
+	// Clear existing object
+	clear();
+
+	std::ifstream fh(filename.c_str(), std::ios_base::in);
+
+	if (fh.fail())
+		REPORT_ERROR( (std::string) "Assembly::read: File " + filename + " does not exists" );
+
+	char line[100];
+	bool is_sorted = true;
+	int old_resnum = -1;
+	long int mol_id = -1;
+	long int res_id = -1;
+	std::string molname, alt_molname, old_molname="";
+
+	fh.seekg(0);
+
+	// Loop over all lines
+	while (fh.getline (line, 600))
+	{
+		// Only look at lines with an ATOM label
+		std::string record(line,0,6);
+		if (record == "ATOM  ")
+		{
+			  char snum[5]={'\0'};
+		      char atomname[5]={'\0'};
+		      char resname[4]={'\0'};
+		      char chainID[1]={'\0'};
+		      int resnum=-1;
+		      char insertion_residue_code;
+		      float x,y,z;
+		      float occupancy, bfactor;
+		      char segID[5]={'\0'}, element[3]={'\0'}, charge[3]={'\0'};
+
+		      int nr= sscanf(line, "ATOM  %5s %4s %3s %1s%4d%1c   %8f%8f%8f%6f%6f      %4s%2s%2s",
+		                          snum, atomname, resname, chainID, &resnum, &insertion_residue_code,
+		                          &x, &y, &z, &occupancy, &bfactor, segID, element, charge);
+
+//#define DEBUG
+		      if (nr < 5)
+		      {
+		    	  std::string str(line);
+		    	  REPORT_ERROR("Assembly::readPDB ERROR: too few entries on ATOM line:" + str);
+		      }
+
+		      if (resnum < 0)
+		      {
+		    	  REPORT_ERROR("Assembly::readPDB ERROR: negative residue number encountered");
+		      }
+
+		      std::string str_chainID(chainID);
+		      std::string str_segID(segID);
+		      std::string str_atomname(atomname);
+		      std::string str_resname(resname);
+
+		      // 1. Get mol_id: to which molecule does this atom belong?
+		      // Allow for non-ordered atoms belonging to the same molecule...
+		      // To speed up things: first check whether the chainID/segID is the same as the previous line
+		      molname = (use_segid_instead_of_chainid) ? str_segID : str_chainID;
+		      alt_molname = (use_segid_instead_of_chainid) ? str_chainID : str_segID;
+#ifdef DEBUG
+		      std::cerr << " molname= " << molname << " alt_molname= " << alt_molname << " str_chainID= " << str_chainID << " chainID= "<< chainID<<std::endl;
+#endif
+		      if (molname != old_molname)
+		      {
+		    	  // Check whether a molecule with the same name already exists
+		    	  mol_id = -1;
+		    	  for (long int imol = 0; imol < molecules.size(); imol++)
+		    	  {
+		    		  if (molname == molecules[imol].name)
+		    		  {
+		    			  mol_id = imol;
+		    			  break;
+		    		  }
+		    	  }
+
+		    	  // If not found, add a new molecule
+		    	  if (mol_id < 0)
+		    	  {
+#ifdef DEBUG
+		    		  std::cerr << " snum= " << snum << " atomname= " << atomname << " resname= " << resname ;
+		    		  std::cerr << " chainID= " << chainID << " resnum= " << resnum << " x= " << x ;
+		    		  std::cerr << " y= " << y << " z= " << z << " bfactor= " << bfactor << std::endl;
+#endif
+		    		  mol_id = addMolecule(molname, alt_molname);
+		    		  old_resnum = -1;
+		    	  }
+		    	  else
+		    	  {
+		    		  int lastres = molecules[mol_id].residues.size()-1;
+		    		  old_resnum = (molecules[mol_id]).residues[lastres].number;
+		    	  }
+		      }
+
+		      // 2. Check whether this is a new residue
+		      // All Atoms inside one Residue are assumed to be together!
+		      if (resnum != old_resnum)
+		      {
+		    	  res_id = molecules[mol_id].addResidue(str_resname, resnum);
+		    	  if (resnum < old_resnum && molname == old_molname && do_sort)
+		    	  {
+		    		  std::cout <<" Warning unsorted residues: " << resnum << " molname= " << molname << " old_resnum= " << old_resnum << " old_molname= " <<old_molname << ""<<std::endl;
+		    		  is_sorted = false;
+		    	  }
+		      }
+
+		      // 3. Add the actual atom
+		      molecules[mol_id].residues[res_id].addAtom(atomname, x, y, z, occupancy, bfactor);
+
+		      // For use in next line
+		      old_molname = molname;
+		      old_resnum = resnum;
+		}
+		else
+		{
+			// At TER statements: reset old_molname to prevent sorting
+			old_molname = "";
+			old_resnum = 0;
+		}
+
+	}
+
+	fh.close();
+
+	// If the Residues were not sorted, do this now:
+	if (!is_sorted && do_sort)
+	{
+		std::cout << " Resorting residues in input PDB file " << filename << " ... " << std::endl;
+		sortResidues();
+	}
+
+}
+
+// Write PDB format
+void Assembly::writePDB(std::string filename)
+{
+	FILE *file;
+	file = fopen(filename.c_str(), "w");
+	if (file==NULL)
+		REPORT_ERROR("Error writing file: " + filename);
+
+	fprintf(file, "%s\n", "REMARK Created by DsigNA");
+	long int atomnum = 0;
+	for (int imol = 0; imol < molecules.size(); imol++)
+	{
+		for (int ires = 0; ires < molecules[imol].residues.size(); ires++)
+		{
+			for (int iatom = 0; iatom < molecules[imol].residues[ires].atoms.size(); iatom++, atomnum++)
+			{
+				// If more than 100,000 atoms: just start counting at one again.
+				if (atomnum > 99999)
+					atomnum -= 99999;
+				char chainID = molecules[imol].name[0];
+				fprintf(file, "ATOM  %5d %-4s %3s %1c%4d    %8.3f%8.3f%8.3f%6.2f%6.2f      %4s\n",
+						                          atomnum, molecules[imol].residues[ires].atoms[iatom].name.c_str(), molecules[imol].residues[ires].name.c_str(),
+						                          chainID, molecules[imol].residues[ires].number,
+						                          XX(molecules[imol].residues[ires].atoms[iatom].coords),
+						                          YY(molecules[imol].residues[ires].atoms[iatom].coords),
+						                          ZZ(molecules[imol].residues[ires].atoms[iatom].coords),
+						                          molecules[imol].residues[ires].atoms[iatom].occupancy,
+						                          molecules[imol].residues[ires].atoms[iatom].bfactor,
+						                          molecules[imol].name.c_str());
+			}
+		}
+		if (imol + 1 < molecules.size())
+			fprintf(file, "%s\n", "TER");
+	}
+
+	fprintf(file, "%s\n", "END");
+	fclose(file);
+}
+
+void Assembly::join(Assembly &tojoin)
+{
+
+	for (int imol = 0; imol < tojoin.molecules.size(); imol++)
+		addMolecule(tojoin.molecules[imol]);
+
+}
+
+void Assembly::sortResidues()
+{
+
+	// Loop over all molecules
+	for (int imol = 0; imol < molecules.size(); imol++)
+	{
+
+		// A. Sort all Residues
+		std::vector<std::pair<int, int> > vp;
+		for (int ires = 0; ires < molecules[imol].residues.size(); ires++)
+		{
+			vp.push_back(std::make_pair(molecules[imol].residues[ires].number, ires));
+		}
+		std::sort(vp.begin(), vp.end());
+		std::vector<Residue> new_residues;
+		for (int ires = 0; ires < molecules[imol].residues.size(); ires++)
+		{
+			new_residues.push_back(molecules[imol].residues[vp[ires].second]);
+		}
+		molecules[imol].residues = new_residues;
+	}
+
+}
+
+void Assembly::applyTransformation(Matrix2D<double> &mat, Matrix1D<double> &shift)
+{
+	for (int imol = 0; imol < molecules.size(); imol++)
+	{
+		for (int ires = 0; ires < molecules[imol].residues.size(); ires++)
+		{
+			for (int iatom = 0; iatom < molecules[imol].residues[ires].atoms.size(); iatom++)
+			{
+				(molecules[imol].residues[ires].atoms[iatom]).coords = mat * (molecules[imol].residues[ires].atoms[iatom]).coords;
+				(molecules[imol].residues[ires].atoms[iatom]).coords += shift;
+			}
+		}
+	}
+
+}
diff --git a/src/assembly.h b/src/assembly.h
new file mode 100644
index 0000000..7d5b090
--- /dev/null
+++ b/src/assembly.h
@@ -0,0 +1,253 @@
+/*
+ * assembly.h
+ *
+ *  Created on: Apr 16, 2013
+ *      Author: "Sjors H.W. Scheres"
+ */
+
+#ifndef ASSEMBLY_H_
+#define ASSEMBLY_H_
+#include <cstdlib>
+#include <cstdio>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <algorithm>
+#include "src/args.h"
+#include "src/matrix2d.h"
+
+/*
+ * Hierarchical model for a macromolecular assembly, e.g. a DNA origami object
+ *
+ *  Assembly
+ *   ->	Molecule
+ *   	->	Residue
+ *   		->	Atom  (either a true one or a coarse-grain pseudo-atom)
+ *
+ *
+ */
+
+class Atom
+{
+public:
+        // Name of this Atom
+        std::string name;
+
+        // Coordinates
+        Matrix1D<double> coords;
+
+        // Occupancy
+        double occupancy;
+
+        // B-factor
+        double bfactor;
+
+        // Empty constructor
+        Atom()
+        {
+        	clear();
+        }
+
+        // Named constructor
+        Atom(std::string in_name)
+        {
+        	clear();
+        	name = in_name;
+        }
+
+        // Destructor needed for work with vectors
+        ~Atom()
+        {
+        	clear();
+        }
+
+        // Initialize
+        void clear();
+
+        // Get the 3D corrdinates as a POint3D
+        Matrix1D<double> getCoordinates();
+};
+
+
+class Residue
+{
+public:
+        // Name of this Residue
+        std::string name;
+
+        // Number of this Residue
+        int number;
+
+        // All the Atoms in this Residue
+        std::vector<Atom> atoms;
+
+        // Empty Constructor
+        Residue()
+        {
+        	clear();
+        }
+
+        // Constructor
+        Residue(std::string in_name, int in_number)
+        {
+        	clear();
+        	name = in_name;
+        	number = in_number;
+        }
+
+        // Destructor needed for work with vectors
+        ~Residue()
+        {
+        	clear();
+        }
+
+        // Initialize
+        void clear();
+
+        // Add an Atom to this Residue;
+        long int addAtom(std::string atomname, double x, double y, double z, double occ = 1.0, double bfac = 0.0);
+
+        int numberOfAtoms()
+        {
+        	return atoms.size();
+        }
+
+};
+
+class Molecule
+{
+public:
+        // Name of this Molecule
+        std::string name;
+
+        // Alternative name of this Molecule (either chainID or segID)
+        std::string alt_name;
+
+        // All the Residues in this Molecule
+        std::vector<Residue> residues;
+
+        // Empty Constructor
+        Molecule()
+        {
+        	clear();
+        }
+
+        // Constructor
+        Molecule(std::string in_name, std::string in_alt_name="")
+        {
+        	clear();
+        	name = in_name;
+        	alt_name = in_alt_name;
+        }
+
+        // Destructor needed for work with vectors
+        ~Molecule()
+        {
+        	clear();
+        }
+
+        // Initialize
+        void clear();
+
+        // Number of residues in the molecule
+        long int numberOfResidues()
+        {
+        	return residues.size();
+        }
+
+        // Insert a Residue at the specified position in this Molecule
+        long int insertResidue(Residue &res, int pos);
+
+        // Add a Residue to this Molecule
+        long int addResidue(Residue &res);
+
+        // Add a Residue to this Molecule
+        long int addResidue(std::string name, int resnum);
+
+        // Insert a stretch of residues from another Molecule based on consecutive residue numbering
+        // If start and end residues are negative: just add the entire molecule
+        void insertResidues(Molecule add, int residue_start = -1, int residue_end = -1);
+
+};
+
+class Assembly
+{
+public:
+        // Name of this Assembly
+        std::string name;
+
+        // All the Molecules in this Assembly
+        std::vector<Molecule> molecules;
+
+        // Empty Constructor
+        Assembly()
+        {
+        	clear();
+        }
+
+        // Named Constructor
+        Assembly(std::string in_name)
+        {
+        	clear();
+        	name = in_name;
+        }
+
+    	// Copy constructor
+        Assembly(const Assembly& op)
+    	{
+    		clear();
+    		*this = op;
+    	}
+
+    	// Destructor needed for work with vectors
+        ~Assembly()
+        {
+        	clear();
+        }
+
+        // Initialize
+        void clear();
+
+        // Add a Molecule to this Assembly
+        long int addMolecule(std::string name, std::string alt_name);
+
+        // Add a Molecule to this Assembly
+        long int addMolecule(Molecule &toadd);
+
+        // return number of Molecules in the Assembly
+        long int numberOfMolecules() const;
+
+        // Total number of Atoms
+        long int numberOfAtoms() const;
+
+        // Total number of Residues
+        long int numberOfResidues() const;
+
+        // Print some information about the assembly
+        void printInformation(std::ostream& out = std::cout) const;
+
+        // Read PDB format
+        void readPDB(std::string filename, bool use_segid_instead_of_chainid = false, bool do_sort = true);
+
+        // Write the Assembly to a PDB file
+        void writePDB(std::string filename);
+
+        // Combine this Assembly with another one
+        // If there are identical Molecule.name instances, add a number-suffix to the new Assembly's Molecule.name (in the segID)
+        void join(Assembly &tojoin);
+
+        // Make sure that all Residues within each Molecule are in order w.r.t. their residue number
+        void sortResidues();
+
+        // Break Molecules into separate ones if a break larger than maximum_residue_break occurs in the residue numbering
+        // TODO
+        void checkBreaksInResidueNumbering(int maximum_residue_break = 500);
+
+        // Apply a transformation (first rotation, then shift)
+        void applyTransformation(Matrix2D<double> &mat, Matrix1D<double> &shift);
+
+};
+
+
+#endif /* ASSEMBLY_H_ */
diff --git a/src/autopicker.cpp b/src/autopicker.cpp
new file mode 100644
index 0000000..814d7d2
--- /dev/null
+++ b/src/autopicker.cpp
@@ -0,0 +1,870 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/autopicker.h"
+//#define DEBUG
+
+void AutoPicker::read(int argc, char **argv)
+{
+
+	parser.setCommandLine(argc, argv);
+
+	int gen_section = parser.addSection("General options");
+	fn_in = parser.getOption("--i", "Micrograph STAR file OR filenames from which to autopick particles, e.g. \"Micrographs/*.mrc\"");
+	fn_out = parser.getOption("--o", "Output rootname", "autopick");
+	angpix = textToFloat(parser.getOption("--angpix", "Pixel size in Angstroms"));
+	particle_diameter = textToFloat(parser.getOption("--particle_diameter", "Diameter of the circular mask that will be applied to the experimental images (in Angstroms)"));
+	do_write_fom_maps = parser.checkOption("--write_fom_maps", "Write calculated probability-ratio maps to disc (for re-reading in subsequent runs)");
+	do_read_fom_maps = parser.checkOption("--read_fom_maps", "Skip probability calculations, re-read precalculated maps from disc");
+
+	int ref_section = parser.addSection("References options");
+	fn_ref = parser.getOption("--ref", "STAR file with the reference names, or an MRC stack with all references");
+	do_invert = parser.checkOption("--invert", "Density in micrograph is inverted w.r.t. density in template");
+	psi_sampling = textToFloat(parser.getOption("--ang", "Angular sampling (in degrees); use 360 for no rotations", "10"));
+	lowpass = textToFloat(parser.getOption("--lowpass", "Lowpass filter in Angstroms for the references (prevent Einstein-from-noise!)","-1"));
+	do_ctf = parser.checkOption("--ctf", "Perform CTF correction on the references?");
+	intact_ctf_first_peak = parser.checkOption("--ctf_intact_first_peak", "Ignore CTFs until their first peak?");
+
+	int peak_section = parser.addSection("Peak-search options");
+	min_fraction_expected_Pratio = textToFloat(parser.getOption("--threshold", "Fraction of expected probability ratio in order to consider peaks?", "0.25"));
+	min_particle_distance = textToFloat(parser.getOption("--min_distance", "Minimum distance (in A) between any two particles (default is half the box size)","-1"));
+	autopick_skip_side = textToInteger(parser.getOption("--skip_side", "Keep this many extra pixels (apart from particle_size/2) away from the edge of the micrograph ","0"));
+
+	int expert_section = parser.addSection("Expert options");
+	verb = textToInteger(parser.getOption("--verb", "Verbosity", "1"));
+
+	// Check for errors in the command-line option
+	if (parser.checkForErrors())
+		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+}
+
+void AutoPicker::usage()
+{
+	parser.writeUsage(std::cerr);
+}
+
+
+void AutoPicker::initialise()
+{
+
+	if (fn_in.isStarFile())
+	{
+		MDmic.read(fn_in);
+		fn_micrographs.clear();
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDmic)
+		{
+			FileName fn_mic;
+			MDmic.getValue(EMDL_MICROGRAPH_NAME, fn_mic);
+			fn_micrographs.push_back(fn_mic);
+		}
+	}
+	else
+	{
+
+		if (do_ctf)
+			REPORT_ERROR("AutoPicker::initialise ERROR: use an input STAR file with the CTF information when using --ctf");
+
+		fn_in.globFiles(fn_micrographs);
+		if (fn_micrographs.size() == 0)
+			REPORT_ERROR("Cannot find any micrograph called: "+fns_autopick);
+	}
+
+
+	if (verb > 0)
+	{
+		std::cout << " Run autopicking on the following micrographs: " << std::endl;
+		for(unsigned  int  i = 0; i < fn_micrographs.size(); ++i)
+			std::cout << "  * " << fn_micrographs[i] << std::endl;
+	}
+
+	// Read in the references
+	Mrefs.clear();
+	if (fn_ref.isStarFile())
+	{
+		MetaDataTable MDref;
+		MDref.read(fn_ref);
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDref)
+		{
+			// Get all reference images and their names
+			Image<double> Iref;
+
+			FileName fn_img;
+			if (!MDref.getValue(EMDL_MLMODEL_REF_IMAGE, fn_img))
+			{
+				if (!MDref.getValue(EMDL_IMAGE_NAME, fn_img))
+					REPORT_ERROR("AutoPicker::initialise ERROR: either provide rlnReferenceImage or rlnImageName in the reference STAR file!");
+			}
+#ifdef DEBUG
+			std::cerr << " Reference fn= " << fn_img << std::endl;
+#endif
+			Iref.read(fn_img);
+			Iref().setXmippOrigin();
+			Mrefs.push_back(Iref());
+		}
+	}
+	else
+	{
+		Image<double> Istk, Iref;
+		Istk.read(fn_ref);
+		for (int n = 0; n < NSIZE(Istk()); n++)
+		{
+			Istk().getImage(n, Iref());
+			Iref().setXmippOrigin();
+			Iref().printShape();
+			Mrefs.push_back(Iref());
+		}
+	}
+
+	particle_size = XSIZE(Mrefs[0]);
+
+	// Get the squared particle radius (in integer pixels)
+	particle_radius2 = ROUND(particle_diameter/(2. * angpix));
+	particle_radius2*= particle_radius2;
+#ifdef DEBUG
+	std::cerr << " particle_size= " << particle_size << " sqrt(particle_radius2)= " << sqrt(particle_radius2) << std::endl;
+#endif
+	// Invert references if necessary (do this AFTER automasking them!)
+	if (do_invert)
+	{
+		for (int iref = 0; iref < Mrefs.size(); iref++)
+		{
+			Mrefs[iref] *= -1.;
+		}
+	}
+
+	// Get micrograph_size
+	Image<double> Imic;
+	Imic.read(fn_micrographs[0], false);
+	micrograph_xsize = XSIZE(Imic());
+	micrograph_ysize = YSIZE(Imic());
+	micrograph_size = (micrograph_xsize != micrograph_ysize) ? XMIPP_MAX(micrograph_xsize, micrograph_ysize) : micrograph_xsize;
+
+	if (lowpass < 0.)
+	{
+		downsize_mic = micrograph_size;
+	}
+	else
+	{
+		downsize_mic = 2 * ROUND(micrograph_size * angpix / lowpass);
+	}
+
+	if (min_particle_distance < 0)
+	{
+		min_particle_distance = particle_size * angpix / 2.;
+	}
+
+	// Pre-calculate and store Projectors for all references at the right size
+	if (!do_read_fom_maps)
+	{
+		// Calculate a circular mask based on the particle_diameter and then store its FT
+		FourierTransformer transformer;
+		MultidimArray<double> Mcirc_mask(particle_size, particle_size);
+		MultidimArray<double> Maux(micrograph_size, micrograph_size);
+		Mcirc_mask.setXmippOrigin();
+		Maux.setXmippOrigin();
+
+		// For squared difference, need the mask of the background to locally normalise the micrograph
+		nr_pixels_circular_invmask = 0;
+		Mcirc_mask.initZeros();
+		FOR_ALL_ELEMENTS_IN_ARRAY2D(Mcirc_mask)
+		{
+			if (i*i + j*j >= particle_radius2)
+			{
+				A2D_ELEM(Mcirc_mask, i, j) = 1.;
+				nr_pixels_circular_invmask++;
+			}
+		}
+		// Now set the mask in the large square and store its FFT
+		Maux.initZeros();
+		FOR_ALL_ELEMENTS_IN_ARRAY2D(Mcirc_mask)
+		{
+			A2D_ELEM(Maux, i, j ) = A2D_ELEM(Mcirc_mask, i, j);
+		}
+		CenterFFT(Maux, true);
+		transformer.FourierTransform(Maux, Finvmsk);
+
+		// Also get the particle-area mask
+		nr_pixels_circular_mask = 0;
+		Mcirc_mask.initZeros();
+		FOR_ALL_ELEMENTS_IN_ARRAY2D(Mcirc_mask)
+		{
+			if (i*i + j*j < particle_radius2)
+			{
+				A2D_ELEM(Mcirc_mask, i, j) = 1.;
+				nr_pixels_circular_mask++;
+			}
+		}
+#ifdef DEBUG
+		std::cerr << " min_particle_distance= " << min_particle_distance << " micrograph_size= " << micrograph_size << " downsize_mic= " << downsize_mic << std::endl;
+		std::cerr << " nr_pixels_circular_mask= " << nr_pixels_circular_mask << " nr_pixels_circular_invmask= " << nr_pixels_circular_invmask << std::endl;
+#endif
+
+		// Now set the mask in the large square and store its FFT
+		Maux.initZeros();
+		FOR_ALL_ELEMENTS_IN_ARRAY2D(Mcirc_mask)
+		{
+			A2D_ELEM(Maux, i, j ) = A2D_ELEM(Mcirc_mask, i, j);
+		}
+		CenterFFT(Maux, true);
+		transformer.FourierTransform(Maux, Fmsk);
+		transformer.cleanup(); // somehow I get segfaults without this cleanup....
+
+		PPref.clear();
+		Projector PP(micrograph_size);
+		MultidimArray<double> dummy;
+
+		// TODO!!! sum_ref etc should be CTF-dependent!!!
+		//sum_ref_under_circ_mask.clear();
+		//sum_ref2_under_circ_mask.clear();
+		for (int iref = 0; iref < Mrefs.size(); iref++)
+		{
+
+			// (Re-)apply the mask to the references
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Mrefs[iref])
+			{
+				DIRECT_MULTIDIM_ELEM(Mrefs[iref], n) *= DIRECT_MULTIDIM_ELEM(Mcirc_mask, n);
+			}
+
+			// Set reference in the large box of the micrograph
+			Maux.initZeros();
+			FOR_ALL_ELEMENTS_IN_ARRAY2D(Mrefs[iref])
+			{
+				A2D_ELEM(Maux, i, j) = A2D_ELEM(Mrefs[iref], i, j);
+			}
+
+			// And compute its Fourier Transform inside the Projector
+			PP.computeFourierTransformMap(Maux, dummy, downsize_mic, 1, false);
+			PPref.push_back(PP);
+
+		}
+	}
+
+#ifdef DEBUG
+	std::cerr << "Finishing initialise" << std::endl;
+#endif
+
+}
+
+void AutoPicker::run()
+{
+
+	int barstep;
+	if (verb > 0)
+	{
+		std::cout << " Autopicking ..." << std::endl;
+		init_progress_bar(fn_micrographs.size());
+		barstep = XMIPP_MAX(1, fn_micrographs.size() / 60);
+	}
+
+
+	for (long int imic = 0; imic < fn_micrographs.size(); imic++)
+	{
+
+		if (verb > 0 && imic % barstep == 0)
+			progress_bar(imic);
+
+		autoPickOneMicrograph(fn_micrographs[imic]);
+
+	}
+
+	if (verb > 0)
+		progress_bar(fn_micrographs.size());
+
+}
+
+void AutoPicker::autoPickOneMicrograph(FileName &fn_mic)
+{
+	Image<double> Imic;
+	MultidimArray<Complex > Faux, Faux2, Fmic;
+	MultidimArray<double> Maux, Mstddev, Mmean, Mdiff2, MsumX2, Mccf_best, Mpsi_best, Fctf;
+	FourierTransformer transformer;
+	double sum_ref_under_circ_mask, sum_ref2_under_circ_mask;
+	int my_skip_side = autopick_skip_side + particle_size/2;
+	CTF ctf;
+
+	int min_distance_pix = ROUND(min_particle_distance / angpix);
+
+#ifdef DEBUG
+	Image<double> tt;
+	tt().resize(micrograph_size, micrograph_size);
+	std::cerr << " fn_mic= " << fn_mic << std::endl;
+#endif
+	// Read in the micrograph
+	Imic.read(fn_mic);
+	Imic().setXmippOrigin();
+
+	// Let's just check the square size again....
+	double my_size, my_xsize, my_ysize;
+	my_xsize = XSIZE(Imic());
+	my_ysize = YSIZE(Imic());
+	my_size = (my_xsize != my_ysize) ? XMIPP_MAX(my_xsize, my_ysize) : my_xsize;
+
+	if (my_size != micrograph_size || my_xsize != micrograph_xsize || my_ysize != micrograph_ysize)
+	{
+		Imic().printShape();
+		std::cerr << " micrograph_size= " << micrograph_size << " micrograph_xsize= " << micrograph_xsize << " micrograph_ysize= " << micrograph_ysize << std::endl;
+		REPORT_ERROR("AutoPicker::autoPickOneMicrograph ERROR: No differently sized micrographs are allowed in one run, sorry you will have to run separately for each size...");
+	}
+
+	// Set mean to zero and stddev to 1 to prevent numerical problems with one-sweep stddev calculations....
+	Imic().statisticsAdjust(0., 1.);
+
+	if (micrograph_xsize != micrograph_ysize)
+	{
+		// Window non-square micrographs to be a square with the largest side
+		rewindow(Imic, micrograph_size);
+
+		// Fill region outside the original window with white Gaussian noise to prevent all-zeros in Mstddev
+		FOR_ALL_ELEMENTS_IN_ARRAY2D(Imic())
+		{
+			if (i < FIRST_XMIPP_INDEX(micrograph_ysize)
+					|| i > LAST_XMIPP_INDEX(micrograph_ysize)
+					|| j < FIRST_XMIPP_INDEX(micrograph_xsize)
+					|| j > LAST_XMIPP_INDEX(micrograph_xsize) )
+				A2D_ELEM(Imic(), i, j) = rnd_gaus(0.,1.);
+		}
+	}
+
+	// Read in the CTF information if needed
+	if (do_ctf)
+	{
+		// Search for this micrograph in the metadata table
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDmic)
+		{
+			FileName fn_tmp;
+			MDmic.getValue(EMDL_MICROGRAPH_NAME, fn_tmp);
+			if (fn_tmp==fn_mic)
+			{
+				ctf.read(MDmic, MDmic);
+				Fctf.resize(downsize_mic, downsize_mic/2 + 1);
+				ctf.getFftwImage(Fctf, micrograph_size, micrograph_size, angpix, false, false, intact_ctf_first_peak, true);
+				break;
+			}
+		}
+#ifdef DEBUG
+		std::cerr << " Read CTF info from" << fn_mic.withoutExtension()<<"_ctf.star" << std::endl;
+		Image<double> Ictf;
+		Ictf()=Fctf;
+		Ictf.write("Mmic_ctf.spi");
+#endif
+	}
+
+	Mccf_best.resize(micrograph_size, micrograph_size);
+	Mpsi_best.resize(micrograph_size, micrograph_size);
+
+	double normfft = (double)(micrograph_size * micrograph_size) / (double)nr_pixels_circular_mask;;
+	if (!do_read_fom_maps)
+	{
+		/*
+		 * Squared difference FOM:
+		 * Sum ( (X-mu)/sig  - A )^2 =
+		 *  = Sum((X-mu)/sig)^2 - 2 Sum (A*(X-mu)/sig) + Sum(A)^2
+		 *  = (1/sig^2)*Sum(X^2) - (2*mu/sig^2)*Sum(X) + (mu^2/sig^2)*Sum(1) - (2/sig)*Sum(AX) + (2*mu/sig)*Sum(A) + Sum(A^2)
+		 *
+		 * However, the squared difference with an "empty" ie all-zero reference is:
+		 * Sum ( (X-mu)/sig)^2
+		 *
+		 * The ratio of the probabilities thereby becomes:
+		 * P(ref) = 1/sqrt(2pi) * exp (( (X-mu)/sig  - A )^2 / -2 )   // assuming sigma = 1!
+		 * P(zero) = 1/sqrt(2pi) * exp (( (X-mu)/sig )^2 / -2 )
+		 *
+		 * P(ref)/P(zero) = exp(( (X-mu)/sig  - A )^2 / -2) / exp ( ( (X-mu)/sig )^2 / -2)
+		 *                = exp( (- (2/sig)*Sum(AX) + (2*mu/sig)*Sum(A) + Sum(A^2)) / - 2 )
+		 *
+		 *                Therefore, I do not need to calculate (X-mu)/sig beforehand!!!
+		 *
+		 */
+
+		// Fourier Transform (and downscale) Imic()
+		CenterFFT(Imic(), true);
+		transformer.FourierTransform(Imic(), Fmic);
+
+		// Also calculate the FFT of the squared micrograph
+		Maux.resize(Imic());
+		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Maux)
+		{
+			DIRECT_MULTIDIM_ELEM(Maux, n) = DIRECT_MULTIDIM_ELEM(Imic(), n) * DIRECT_MULTIDIM_ELEM(Imic(), n);
+		}
+		MultidimArray<Complex > Fmic2;
+		transformer.FourierTransform(Maux, Fmic2);
+
+#ifdef DEBUG
+		std::cerr << " nr_pixels_circular_invmask= " << nr_pixels_circular_invmask << std::endl;
+		std::cerr << " nr_pixels_circular_mask= " << nr_pixels_circular_mask << std::endl;
+		windowFourierTransform(Finvmsk, Faux2, micrograph_size);
+		transformer.inverseFourierTransform(Faux2, tt());
+		CenterFFT(tt(), false);
+		tt.write("Minvmask.spi");
+		windowFourierTransform(Fmsk, Faux2, micrograph_size);
+		transformer.inverseFourierTransform(Faux2, tt());
+		CenterFFT(tt(), false);
+		tt.write("Mmask.spi");
+#endif
+
+		// The following calculate mu and sig under the solvent area at every position in the micrograph
+		calculateStddevAndMeanUnderMask(Fmic, Fmic2, Finvmsk, nr_pixels_circular_invmask, Mstddev, Mmean);
+
+		// From now on use downsized Fmic, as the cross-correlation with the references can be done at lower resolution
+		windowFourierTransform(Fmic, Faux, downsize_mic);
+		Fmic = Faux;
+
+	}// end if do_read_fom_maps
+
+	// Now start looking for the peaks of all references
+	// Clear the output vector with all peaks
+	std::vector<Peak> peaks;
+	peaks.clear();
+	for (int iref = 0; iref < Mrefs.size(); iref++)
+	{
+		double expected_Pratio; // the expectedFOM for this (ctf-corrected) reference
+		if (do_read_fom_maps)
+		{
+			FileName fn_tmp;
+			Image<double> It;
+			fn_tmp.compose(fn_mic.withoutExtension()+"_"+fn_out+"_ref", iref,"_bestCCF.spi");
+			It.read(fn_tmp);
+			Mccf_best = It();
+			// Retrieve expected_Pratio from the header of the image..
+			It.MDMainHeader.getValue(EMDL_IMAGE_STATS_MAX, expected_Pratio);
+			fn_tmp.compose(fn_mic.withoutExtension()+"_"+fn_out+"_ref", iref,"_bestPSI.spi");
+			It.read(fn_tmp);
+			Mpsi_best = It();
+
+		} //end else if do_read_fom_maps
+		else
+		{
+			Mccf_best.initConstant(-99.e99);
+			bool is_first_psi = true;
+			for (double psi = 0. ; psi < 360.; psi+=psi_sampling)
+			{
+
+				// Get the Euler matrix
+				Matrix2D<double> A(3,3);
+				Euler_angles2matrix(0., 0., psi, A);
+
+				// Now get the FT of the rotated (non-ctf-corrected) template
+				Faux.initZeros(downsize_mic, downsize_mic/2 + 1);
+				PPref[iref].get2DFourierTransform(Faux, A, IS_NOT_INV);
+
+#ifdef DEBUG
+				std::cerr << " psi= " << psi << std::endl;
+				windowFourierTransform(Faux, Faux2, micrograph_size);
+				transformer.inverseFourierTransform(Faux2, tt());
+				CenterFFT(tt(), false);
+				tt.write("Mref_rot.spi");
+
+				windowFourierTransform(Fmic, Faux2, micrograph_size);
+				transformer.inverseFourierTransform(Faux2, tt());
+				CenterFFT(tt(), false);
+				tt.write("Mmic.spi");
+
+#endif
+
+				// Apply the CTF on-the-fly (so same PPref can be used for many different micrographs)
+				if (do_ctf)
+				{
+					FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Faux)
+					{
+						DIRECT_MULTIDIM_ELEM(Faux, n) *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+					}
+#ifdef DEBUG
+				windowFourierTransform(Faux, Faux2, micrograph_size);
+				transformer.inverseFourierTransform(Faux2, Maux);
+				CenterFFT(Maux, false);
+				Maux.setXmippOrigin();
+				tt().resize(particle_size, particle_size);
+				tt().setXmippOrigin();
+				FOR_ALL_ELEMENTS_IN_ARRAY2D(tt())
+				{
+					A2D_ELEM(tt(), i, j) = A2D_ELEM(Maux, i, j);
+				}
+				tt.write("Mref_rot_ctf.spi");
+#endif
+				}
+
+				if (is_first_psi)
+				{
+					// Calculate the expected ratio of probabilities for this CTF-corrected reference
+					// and the sum_ref_under_circ_mask and sum_ref_under_circ_mask2
+					// Do this also if we're not recalculating the fom maps...
+
+					windowFourierTransform(Faux, Faux2, micrograph_size);
+					transformer.inverseFourierTransform(Faux2, Maux);
+					CenterFFT(Maux, false);
+					Maux.setXmippOrigin();
+					// TODO: check whether I need CenterFFT(Maux, false)
+
+					sum_ref_under_circ_mask = 0.;
+					sum_ref2_under_circ_mask = 0.;
+					double suma2 = 0.;
+					double sumn = 1.;
+					MultidimArray<double> Mctfref(particle_size, particle_size);
+					Mctfref.setXmippOrigin();
+					FOR_ALL_ELEMENTS_IN_ARRAY2D(Mctfref) // only loop over smaller Mctfref, but take values from large Maux!
+					{
+						if (i*i + j*j < particle_radius2)
+						{
+							suma2 += A2D_ELEM(Maux, i, j) * A2D_ELEM(Maux, i, j);
+							suma2 += 2. * A2D_ELEM(Maux, i, j) * rnd_gaus(0., 1.);
+							sum_ref_under_circ_mask += A2D_ELEM(Maux, i, j);
+							sum_ref2_under_circ_mask += A2D_ELEM(Maux, i, j) * A2D_ELEM(Maux, i, j);
+							sumn += 1.;
+						}
+#ifdef DEBUG
+						A2D_ELEM(Mctfref, i, j) = A2D_ELEM(Maux, i, j);
+#endif
+					}
+					sum_ref_under_circ_mask /= sumn;
+					sum_ref2_under_circ_mask /= sumn;
+					expected_Pratio = exp(suma2 / (2. * sumn));
+#ifdef DEBUG
+					std::cerr << " expected_Pratio["<<iref<<"]= " << expected_Pratio << std::endl;
+					tt()=Mctfref;
+					tt.write("Mctfref.spi");
+#endif
+				}
+
+				// Now multiply template and micrograph to calculate the cross-correlation
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Faux)
+				{
+					DIRECT_MULTIDIM_ELEM(Faux, n) = conj(DIRECT_MULTIDIM_ELEM(Faux, n)) * DIRECT_MULTIDIM_ELEM(Fmic, n);
+				}
+				windowFourierTransform(Faux, Faux2, micrograph_size);
+				transformer.inverseFourierTransform(Faux2, Maux);
+				CenterFFT(Maux, false);
+#ifdef DEBUG
+				tt()=Maux*normfft;
+				tt.write("Mcc.spi");
+#endif
+
+				// Calculate ratio of prabilities P(ref)/P(zero)
+				// Keep track of the best values and their corresponding iref and psi
+
+				// So now we already had precalculated: Mdiff2 = 1/sig*Sum(X^2) - 2/sig*Sum(X) + mu^2/sig*Sum(1)
+				// Still to do (per reference): - 2/sig*Sum(AX) + 2*mu/sig*Sum(A) + Sum(A^2)
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Maux)
+				{
+					double diff2 = - 2. * normfft * DIRECT_MULTIDIM_ELEM(Maux, n);
+					diff2 += 2. * DIRECT_MULTIDIM_ELEM(Mmean, n) * sum_ref_under_circ_mask;
+					if (DIRECT_MULTIDIM_ELEM(Mstddev, n) > 1E-10)
+						diff2 /= DIRECT_MULTIDIM_ELEM(Mstddev, n);
+					diff2 += sum_ref2_under_circ_mask;
+#ifdef DEBUG
+						/*
+						if (diff2 < 0. || n==28800 || n==0)
+						{
+							std::cerr << " n= "<<n<< "diff2= " << diff2 << " old Mdiff2=" <<DIRECT_MULTIDIM_ELEM(Mdiff2, n)
+									<< " -2AX/sig " << - 2. * normfft * DIRECT_MULTIDIM_ELEM(Maux, n) / DIRECT_MULTIDIM_ELEM(Mstddev, n)
+									<< " 2Amu/sig= " << 2. * DIRECT_MULTIDIM_ELEM(Mmean, n) * sum_ref_under_circ_mask[iref] / DIRECT_MULTIDIM_ELEM(Mstddev, n)
+									<< " A2=" <<  sum_ref2_under_circ_mask[iref]
+									<< " stddev= " <<  DIRECT_MULTIDIM_ELEM(Mstddev, n) << " avg= "<< DIRECT_MULTIDIM_ELEM(Mmean, n)
+									<< std::endl;
+						}
+						*/
+#endif
+					diff2 = exp(- diff2 / 2.); // exponentiate to reflect the Gaussian error model. sigma=1 after normalization, 0.4=1/sqrt(2pi)
+
+					// Store fraction of (1 - probability-ratio) wrt  (1 - expected Pratio)
+					diff2 = (diff2 - 1.) / (expected_Pratio - 1.);
+#ifdef DEBUG
+					DIRECT_MULTIDIM_ELEM(Maux, n) = diff2;
+#endif
+					if (diff2 > DIRECT_MULTIDIM_ELEM(Mccf_best, n))
+					{
+						DIRECT_MULTIDIM_ELEM(Mccf_best, n) = diff2;
+						DIRECT_MULTIDIM_ELEM(Mpsi_best, n) = psi;
+					}
+				}
+#ifdef DEBUG
+				std::cerr << " Maux.computeMax()= " << Maux.computeMax() << std::endl;
+				tt()=Maux;
+				tt.write("Mccf.spi");
+			    std::cerr << " Press any key to continue... "  << std::endl;
+			    char c;
+			    std::cin >> c;
+
+#endif
+			    is_first_psi = false;
+			} // end for psi
+
+
+			if (do_write_fom_maps)
+			{
+				// TMP output
+				FileName fn_tmp;
+				Image<double> It;
+				It() = Mccf_best;
+				// Store expected_Pratio in the header of the image..
+				It.MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX, expected_Pratio);;
+				fn_tmp.compose(fn_mic.withoutExtension()+"_"+fn_out+"_ref", iref,"_bestCCF.spi");
+				It.write(fn_tmp);
+
+				It() = Mpsi_best;
+				fn_tmp.compose(fn_mic.withoutExtension()+"_"+fn_out+"_ref", iref,"_bestPSI.spi");
+				It.write(fn_tmp);
+			} // end if do_write_fom_maps
+
+		} // end if do_read_fom_maps
+
+		// Now that we have Mccf_best and Mpsi_best, get the peaks
+		std::vector<Peak> my_ref_peaks;
+		Mccf_best.setXmippOrigin();
+		Mpsi_best.setXmippOrigin();
+		peakSearch(Mccf_best, Mpsi_best, iref, my_skip_side, my_ref_peaks);
+
+		prunePeakClusters(my_ref_peaks, min_distance_pix);
+
+		// append the peaks of this reference to all the other peaks
+		peaks.insert(peaks.end(), my_ref_peaks.begin(), my_ref_peaks.end());
+
+	} // end for iref
+
+
+	//Now that we have done all references, prune the list again...
+	prunePeakClusters(peaks, min_distance_pix);
+
+	// And remove all too close neighbours
+	removeTooCloselyNeighbouringPeaks(peaks, min_distance_pix);
+
+	// Write out a STAR file with the coordinates
+	MetaDataTable MDout;
+	for (int ipeak =0; ipeak < peaks.size(); ipeak++)
+	{
+		MDout.addObject();
+		MDout.setValue(EMDL_IMAGE_COORD_X, (double)(peaks[ipeak].x));
+		MDout.setValue(EMDL_IMAGE_COORD_Y, (double)(peaks[ipeak].y));
+		MDout.setValue(EMDL_ORIENT_PSI, peaks[ipeak].psi);
+		MDout.setValue(EMDL_PARTICLE_CLASS, peaks[ipeak].ref + 1); // start counting at 1
+		MDout.setValue(EMDL_PARTICLE_AUTOPICK_FOM, peaks[ipeak].fom);
+	}
+	FileName fn_tmp = fn_mic.withoutExtension() + "_" + fn_out + ".star";
+	MDout.write(fn_tmp);
+
+}
+
+void AutoPicker::calculateStddevAndMeanUnderMask(const MultidimArray<Complex > &_Fmic, const MultidimArray<Complex > &_Fmic2,
+		MultidimArray<Complex > &_Fmsk, int nr_nonzero_pixels_mask, MultidimArray<double> &_Mstddev, MultidimArray<double> &_Mmean)
+{
+
+	MultidimArray<Complex > Faux, Faux2;
+	MultidimArray<double> Maux(micrograph_size, micrograph_size);
+	FourierTransformer transformer;
+
+	_Mstddev.initZeros(micrograph_size, micrograph_size);
+	double normfft = (double)(micrograph_size * micrograph_size) / (double)nr_nonzero_pixels_mask;
+
+	// Calculate convolution of micrograph and mask, to get average under mask at all points
+	Faux.resize(_Fmic);
+#ifdef DEBUG
+	Image<double> tt;
+#endif
+
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Faux)
+	{
+		DIRECT_MULTIDIM_ELEM(Faux, n) = DIRECT_MULTIDIM_ELEM(_Fmic, n) * conj(DIRECT_MULTIDIM_ELEM(_Fmsk, n));
+	}
+	windowFourierTransform(Faux, Faux2, micrograph_size);
+	transformer.inverseFourierTransform(Faux2, Maux);
+	Maux *= normfft;
+	_Mmean = Maux;
+	CenterFFT(_Mmean, false);
+
+#ifdef DEBUG
+	tt()=Maux;
+	CenterFFT(tt(), false);
+	tt.write("Mavg_mic.spi");
+#endif
+
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(_Mstddev)
+	{
+		// store minus average-squared already in _Mstddev
+		DIRECT_MULTIDIM_ELEM(_Mstddev, n) = -DIRECT_MULTIDIM_ELEM(Maux, n) * DIRECT_MULTIDIM_ELEM(Maux, n);
+	}
+
+	// Calculate convolution of micrograph-squared and mask
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Faux)
+	{
+		DIRECT_MULTIDIM_ELEM(Faux, n) = DIRECT_MULTIDIM_ELEM(_Fmic2, n) * conj(DIRECT_MULTIDIM_ELEM(_Fmsk, n));
+	}
+	windowFourierTransform(Faux, Faux2, micrograph_size);
+	transformer.inverseFourierTransform(Faux2, Maux);
+
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(_Mstddev)
+	{
+		// we already stored minus average-squared in _Mstddev
+		DIRECT_MULTIDIM_ELEM(_Mstddev, n) += normfft * DIRECT_MULTIDIM_ELEM(Maux, n);
+		if (DIRECT_MULTIDIM_ELEM(_Mstddev, n) > 0.)
+			DIRECT_MULTIDIM_ELEM(_Mstddev, n) = sqrt(DIRECT_MULTIDIM_ELEM(_Mstddev, n) );
+		else
+			DIRECT_MULTIDIM_ELEM(_Mstddev, n) = 0.;
+	}
+
+	CenterFFT(_Mstddev, false);
+
+#ifdef DEBUG
+	tt()=_Mstddev;
+	tt.write("Msig_mic.spi");
+#endif
+
+
+}
+
+void AutoPicker::peakSearch(const MultidimArray<double> &Mfom, const MultidimArray<double> &Mpsi, int iref,
+		int skip_side, std::vector<Peak> &peaks)
+{
+
+	peaks.clear();
+	Peak peak;
+	peak.ref = iref;
+
+	// Skip the pixels along the side of the micrograph!
+	// At least 1, so dont have to check for the borders!
+	skip_side = XMIPP_MAX(1, skip_side);
+	for (int i = FIRST_XMIPP_INDEX(micrograph_ysize) + skip_side; i <= LAST_XMIPP_INDEX(micrograph_ysize) - skip_side; i++)
+	{
+		for (int j = FIRST_XMIPP_INDEX(micrograph_xsize) + skip_side; j <= LAST_XMIPP_INDEX(micrograph_xsize) - skip_side; j++)
+		{
+
+			double myval = A2D_ELEM(Mfom, i, j);
+			// check if this element is above the threshold
+			if (myval  >= min_fraction_expected_Pratio)
+			{
+				// This is a peak if all four neighbours are also above the threshold, AND have lower values than myval
+				if (A2D_ELEM(Mfom, i-1, j) < min_fraction_expected_Pratio || A2D_ELEM(Mfom, i-1, j) > myval )
+					continue;
+				if (A2D_ELEM(Mfom, i+1, j) < min_fraction_expected_Pratio || A2D_ELEM(Mfom, i+1, j) > myval )
+					continue;
+				if (A2D_ELEM(Mfom, i, j-1) < min_fraction_expected_Pratio || A2D_ELEM(Mfom, i, j-1) > myval )
+					continue;
+				if (A2D_ELEM(Mfom, i, j+1) < min_fraction_expected_Pratio || A2D_ELEM(Mfom, i, j+1) > myval )
+					continue;
+				peak.x = j - FIRST_XMIPP_INDEX(micrograph_xsize);
+				peak.y = i - FIRST_XMIPP_INDEX(micrograph_ysize);
+				peak.psi = A2D_ELEM(Mpsi, i, j);
+				peak.fom = A2D_ELEM(Mfom, i, j);
+				peak.relative_fom = myval;
+				peaks.push_back(peak);
+			}
+		}
+	}
+
+}
+
+void AutoPicker::prunePeakClusters(std::vector<Peak> &peaks, int min_distance)
+{
+	int mind2 = min_distance*min_distance;
+	int nclus = 0;
+
+	std::vector<Peak> pruned_peaks;
+	while (peaks.size() > 0)
+	{
+		nclus++;
+		std::vector<Peak> cluster;
+		cluster.push_back(peaks[0]);
+		peaks.erase(peaks.begin());
+		for (int iclus = 0; iclus < cluster.size(); iclus++)
+		{
+			int my_x = cluster[iclus].x;
+			int my_y = cluster[iclus].y;
+			for (int ipeakp = 0; ipeakp < peaks.size(); ipeakp++)
+			{
+				int dx = my_x - peaks[ipeakp].x;
+				int dy = my_y - peaks[ipeakp].y;
+				if (dx*dx + dy*dy < particle_radius2)
+				{
+					// Put ipeakp in the cluster, and remove from the peaks list
+					cluster.push_back(peaks[ipeakp]);
+					peaks.erase(peaks.begin()+ipeakp);
+					ipeakp--;
+				}
+			}
+		}
+
+		// Now search for the peak from the cluster with the best ccf.
+		// Then search again if there are any other peaks in the cluster that are further than particle_diameter apart from the selected peak
+		// If so, again search for the maximum
+		int ipass = 0;
+		while (cluster.size() > 0)
+		{
+			double best_relative_fom=-1.;
+			Peak bestpeak;
+			for (int iclus = 0; iclus < cluster.size(); iclus++)
+			{
+				if ( cluster[iclus].relative_fom > best_relative_fom)
+				{
+					best_relative_fom = cluster[iclus].relative_fom;
+					bestpeak = cluster[iclus];
+				}
+			}
+
+			// Store this peak as pruned
+			pruned_peaks.push_back(bestpeak);
+
+			// Remove all peaks within mind2 from the clusters
+			for (int iclus = 0; iclus < cluster.size(); iclus++)
+			{
+				int dx = cluster[iclus].x - bestpeak.x;
+				int dy = cluster[iclus].y - bestpeak.y;
+				if (dx*dx + dy*dy < mind2)
+				{
+					cluster.erase(cluster.begin()+iclus);
+					iclus--;
+				}
+			}
+			ipass++;
+		}
+	} // end while peaks.size > 0
+
+	// Set the pruned peaks back into the input vector
+	peaks = pruned_peaks;
+
+}
+
+void AutoPicker::removeTooCloselyNeighbouringPeaks(std::vector<Peak> &peaks, int min_distance)
+{
+	// Now only keep those peaks that are at least min_particle_distance number of pixels from any other peak
+	std::vector<Peak> pruned_peaks;
+	int mind2 = min_distance*min_distance;
+	for (int ipeak = 0; ipeak < peaks.size(); ipeak++)
+	{
+		int my_x = peaks[ipeak].x;
+		int my_y = peaks[ipeak].y;
+		int my_mind2 = 99999;
+		for (int ipeakp = 0; ipeakp < peaks.size(); ipeakp++)
+		{
+			if (ipeakp != ipeak)
+			{
+				int dx = peaks[ipeakp].x - my_x;
+				int dy = peaks[ipeakp].y - my_y;
+				int d2 = dx*dx + dy*dy;
+				if ( d2 < my_mind2 )
+					my_mind2 = d2;
+			}
+		}
+		if (my_mind2 > mind2)
+			pruned_peaks.push_back(peaks[ipeak]);
+	}
+
+	// Set the pruned peaks back into the input vector
+	peaks = pruned_peaks;
+
+}
+
+
diff --git a/src/autopicker.h b/src/autopicker.h
new file mode 100644
index 0000000..eda96ad
--- /dev/null
+++ b/src/autopicker.h
@@ -0,0 +1,150 @@
+/*
+ * autopicker.h
+ *
+ *  Created on: Sep 18, 2013
+ *      Author: "Sjors H.W. Scheres"
+ */
+
+#ifndef AUTOPICKER_H_
+#define AUTOPICKER_H_
+#include "src/image.h"
+#include "src/multidim_array.h"
+#include "src/metadata_table.h"
+#include "src/projector.h"
+#include "src/ctf.h"
+#include "src/fftw.h"
+#include "src/time.h"
+#include "src/mask.h"
+
+struct Peak
+{
+	int x;
+	int y;
+	int ref;
+	double psi;
+	double fom;
+	double relative_fom;
+};
+
+class AutoPicker
+{
+public:
+
+	// I/O Parser
+	IOParser parser;
+
+	// Verbosity
+	int verb;
+
+	// Input & Output rootname
+	FileName fn_in, fn_ref, fns_autopick, fn_out;
+
+	// Pixel size (for low-pass filter and particle diameter)
+	double angpix;
+
+	// Metadata of the micrographs
+	MetaDataTable MDmic;
+
+	// Particle diameter (in Angstroms)
+	double particle_diameter;
+	int particle_radius2;
+
+	// Low pass filetr cutoff (in Angstroms)
+	double lowpass;
+
+	// Original size of the reference images
+	int particle_size;
+
+	// Dimension of the filtered image
+	int current_size;
+
+	// Vector with all original reference images
+	std::vector<MultidimArray<double> > Mrefs;
+
+	// FTs of the reference images (either for autopicking or for feature calculation)
+	std::vector<Projector > PPref;
+
+	///// Autopicking stuff
+
+	// Re-read precalculated best_localCCF and SPI arrays from disc
+	bool do_read_fom_maps;
+
+	// Write precalculated best_localCCF and SPI arrays to disc
+	bool do_write_fom_maps;
+
+	// All micrographs to autopick from
+	std::vector<FileName> fn_micrographs;
+
+	// Original size of the micrographs
+	int micrograph_size, micrograph_xsize, micrograph_ysize;
+
+	// Is density in micrograph inverted wrt templates?
+	bool do_invert;
+
+	// Correct the references for CTF effects?
+	bool do_ctf;
+
+	// Keep the CTFs unchanged until the first peak?
+	bool intact_ctf_first_peak;
+
+	// Apart from keeping particle_size/2 away from the sides, should we exclude more? E.g. to get rid of Polara bar code?
+	int autopick_skip_side;
+
+	// In-plane rotational sampling (in degrees)
+	double psi_sampling;
+
+	// Fraction of expected probability ratio to consider as peaks
+	double min_fraction_expected_Pratio;
+
+	// Number of Angstroms any 2 particle peaks need to be apart
+	double min_particle_distance;
+
+	// Size of the downsize micrographs for autopicking
+	int downsize_mic;
+
+	// Number of non-zero pixels in the circular mask, and of its inverse (for background normalisation in do_diff2)
+	int nr_pixels_circular_mask, nr_pixels_circular_invmask;
+
+	// Array with Fourier-transform of the (circular) mask, and of its inverse
+	MultidimArray<Complex > Fmsk, Finvmsk;
+
+public:
+	// Read command line arguments
+	void read(int argc, char **argv);
+
+	// Print usage instructions
+	void usage();
+
+	// Initialise some general stuff after reading
+	void initialise();
+
+	// General function to decide what to do
+	void run();
+
+	void autoPickOneMicrograph(FileName &fn_mic);
+
+private:
+
+	// Uses Roseman2003 formulae to calculate stddev under the mask through FFTs
+	// The FFTs of the micrograph (Fmic), micrograph-squared (Fmic2) and the mask (Fmsk) need to be provided at downsize_mic
+	// The putput (Mstddev) will be at (binned) micrograph_size
+	void calculateStddevAndMeanUnderMask(const MultidimArray<Complex > &Fmic, const MultidimArray<Complex > &Fmic2,
+			MultidimArray<Complex > &Fmsk, int nr_nonzero_pixels_mask, MultidimArray<double> &Mstddev, MultidimArray<double> &Mmean);
+
+	// Peak search for all pixels above a given threshold in the map
+	void peakSearch(const MultidimArray<double> &Mccf, const MultidimArray<double> &Mpsi, int iref, int skip_side, std::vector<Peak> &peaks);
+
+	// Now prune the coordinates: within min_particle_distance: all peaks are the same cluster
+	// From each cluster, take the single peaks with the highest ccf
+	// If then, there is another peaks at a distance of at least min_particle_distance: take that one as well, and so forth...
+	void prunePeakClusters(std::vector<Peak> &peaks, int min_distance);
+
+
+	// Only keep those peaks that are at the given distance apart from each other
+	void removeTooCloselyNeighbouringPeaks(std::vector<Peak> &peaks, int min_distance);
+
+
+};
+
+
+#endif /* AUTOPICKER_H_ */
diff --git a/src/autopicker_mpi.cpp b/src/autopicker_mpi.cpp
new file mode 100644
index 0000000..4c71f8e
--- /dev/null
+++ b/src/autopicker_mpi.cpp
@@ -0,0 +1,70 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/autopicker_mpi.h"
+
+void AutoPickerMpi::read(int argc, char **argv)
+{
+    // Define a new MpiNode
+    node = new MpiNode(argc, argv);
+
+    // First read in non-parallelisation-dependent variables
+    AutoPicker::read(argc, argv);
+
+    // Don't put any output to screen for mpi slaves
+    verb = (node->isMaster()) ? 1 : 0;
+
+    if (do_write_fom_maps)
+    	REPORT_ERROR("AutoPickerMpi::read ERROR: --write_fom_maps is very heavy on disc I/O and therefore disabled in parallel execution. Use the sequential program instead!");
+
+    // Possibly also read parallelisation-dependent variables here
+
+    // Print out MPI info
+	printMpiNodesMachineNames(*node);
+
+
+}
+void AutoPickerMpi::run()
+{
+
+	// Each node does part of the work
+	long int my_first_micrograph, my_last_micrograph, my_nr_micrographs;
+	divide_equally(fn_micrographs.size(), node->size, node->rank, my_first_micrograph, my_last_micrograph);
+	my_nr_micrographs = my_last_micrograph - my_first_micrograph + 1;
+
+	int barstep;
+	if (verb > 0)
+	{
+		std::cout << " Autopicking ..." << std::endl;
+		init_progress_bar(my_nr_micrographs);
+		barstep = XMIPP_MAX(1, my_nr_micrographs / 60);
+	}
+
+	for (long int imic = my_first_micrograph; imic <= my_last_micrograph; imic++)
+    {
+    	if (verb > 0 && imic % barstep == 0)
+			progress_bar(imic);
+
+    	autoPickOneMicrograph(fn_micrographs[imic]);
+	}
+	if (verb > 0)
+		progress_bar(my_nr_micrographs);
+
+
+}
diff --git a/src/autopicker_mpi.h b/src/autopicker_mpi.h
new file mode 100644
index 0000000..9ad2ab3
--- /dev/null
+++ b/src/autopicker_mpi.h
@@ -0,0 +1,37 @@
+/*
+ * autopicker_mpi.h
+ *
+ *  Created on: Sep 18, 2013
+ *      Author: "Sjors H.W. Scheres"
+ */
+
+#ifndef AUTOPICKER_MPI_H_
+#define AUTOPICKER_MPI_H_
+
+#include "src/mpi.h"
+#include "src/autopicker.h"
+#include "src/parallel.h"
+
+class AutoPickerMpi: public AutoPicker
+{
+private:
+	MpiNode *node;
+
+public:
+	/** Destructor, calls MPI_Finalize */
+    ~AutoPickerMpi()
+    {
+        delete node;
+    }
+
+    /** Read
+     * This could take care of mpi-parallelisation-dependent variables
+     */
+    void read(int argc, char **argv);
+
+    // Parallelized run function
+    void run();
+
+};
+
+#endif /* AUTOPICKER_MPI_H_ */
diff --git a/src/backprojector.cpp b/src/backprojector.cpp
new file mode 100644
index 0000000..b8e3869
--- /dev/null
+++ b/src/backprojector.cpp
@@ -0,0 +1,1323 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/*
+ * backprojector.cpp
+ *
+ *  Created on: 24 Aug 2010
+ *      Author: scheres
+ */
+
+#include "src/backprojector.h"
+
+void BackProjector::initialiseDataAndWeight(int current_size)
+{
+
+	initialiseData(current_size);
+	weight.resize(data);
+
+}
+
+void BackProjector::initZeros(int current_size)
+{
+
+	initialiseDataAndWeight(current_size);
+	data.initZeros();
+	weight.initZeros();
+}
+
+void BackProjector::backproject(const MultidimArray<Complex > &f2d,
+		                        const Matrix2D<double> &A, bool inv,
+		                        const MultidimArray<double> *Mweight)
+{
+	double fx, fy, fz, mfx, mfy, mfz, xp, yp, zp;
+	int first_x, x0, x1, y0, y1, z0, z1, y, y2, r2;
+	bool is_neg_x;
+	double dd000, dd001, dd010, dd011, dd100, dd101, dd110, dd111;
+	Complex my_val;
+	Matrix2D<double> Ainv;
+	double my_weight = 1.;
+
+	// f2d should already be in the right size (ori_size,orihalfdim)
+    // AND the points outside max_r should already be zero...
+
+	// Use the inverse matrix
+    if (inv)
+    	Ainv = A;
+    else
+    	Ainv = A.transpose();
+
+    // Go from the 2D slice coordinates to the 3D coordinates
+    Ainv *= (double)padding_factor;  // take scaling into account directly
+    int max_r2 = r_max * r_max;
+    int min_r2_nn = r_min_nn * r_min_nn;
+
+//#define DEBUG_BACKP
+#ifdef DEBUG_BACKP
+    std::cerr << " XSIZE(f2d)= "<< XSIZE(f2d) << std::endl;
+    std::cerr << " YSIZE(f2d)= "<< YSIZE(f2d) << std::endl;
+    std::cerr << " XSIZE(data)= "<< XSIZE(data) << std::endl;
+    std::cerr << " YSIZE(data)= "<< YSIZE(data) << std::endl;
+    std::cerr << " STARTINGX(data)= "<< STARTINGX(data) << std::endl;
+    std::cerr << " STARTINGY(data)= "<< STARTINGY(data) << std::endl;
+    std::cerr << " STARTINGZ(data)= "<< STARTINGZ(data) << std::endl;
+    std::cerr << " max_r= "<< r_max << std::endl;
+    std::cerr << " Ainv= " << Ainv << std::endl;
+#endif
+
+    for (int i=0; i < YSIZE(f2d); i++)
+	{
+		// Dont search beyond square with side max_r
+		if (i <= r_max)
+		{
+			y = i;
+			first_x = 0;
+		}
+		else if (i >= YSIZE(f2d) - r_max)
+		{
+			y = i - YSIZE(f2d);
+			// x==0 plane is stored twice in the FFTW format. Dont set it twice in BACKPROJECTION!
+			first_x = 1;
+		}
+		else
+			continue;
+
+		y2 = y * y;
+		for (int x=first_x; x <= r_max; x++)
+		{
+	    	// Only include points with radius < max_r (exclude points outside circle in square)
+			r2 = x * x + y2;
+			if (r2 > max_r2)
+				continue;
+
+			// Get the relevant value in the input image
+			my_val = DIRECT_A2D_ELEM(f2d, i, x);
+
+			// Get the weight
+			if (Mweight != NULL)
+				my_weight = DIRECT_A2D_ELEM(*Mweight, i, x);
+			// else: my_weight was already initialised to 1.
+
+			if (my_weight > 0.)
+			{
+
+				// Get logical coordinates in the 3D map
+				xp = Ainv(0,0) * x + Ainv(0,1) * y;
+				yp = Ainv(1,0) * x + Ainv(1,1) * y;
+				zp = Ainv(2,0) * x + Ainv(2,1) * y;
+
+				if (interpolator == TRILINEAR || r2 < min_r2_nn)
+				{
+
+					// Only asymmetric half is stored
+					if (xp < 0)
+					{
+						// Get complex conjugated hermitian symmetry pair
+						xp = -xp;
+						yp = -yp;
+						zp = -zp;
+						is_neg_x = true;
+					}
+					else
+					{
+						is_neg_x = false;
+					}
+
+					// Trilinear interpolation (with physical coords)
+					// Subtract STARTINGY and STARTINGZ to accelerate access to data (STARTINGX=0)
+					// In that way use DIRECT_A3D_ELEM, rather than A3D_ELEM
+					x0 = FLOOR(xp);
+					fx = xp - x0;
+					x1 = x0 + 1;
+
+					y0 = FLOOR(yp);
+					fy = yp - y0;
+					y0 -=  STARTINGY(data);
+					y1 = y0 + 1;
+
+					z0 = FLOOR(zp);
+					fz = zp - z0;
+					z0 -= STARTINGZ(data);
+					z1 = z0 + 1;
+
+					mfx = 1. - fx;
+					mfy = 1. - fy;
+					mfz = 1. - fz;
+
+					dd000 = mfz * mfy * mfx;
+					dd001 = mfz * mfy *  fx;
+					dd010 = mfz *  fy * mfx;
+					dd011 = mfz *  fy *  fx;
+					dd100 =  fz * mfy * mfx;
+					dd101 =  fz * mfy *  fx;
+					dd110 =  fz *  fy * mfx;
+					dd111 =  fz *  fy *  fx;
+
+					if (is_neg_x)
+						my_val = conj(my_val);
+
+					// Store slice in 3D weighted sum
+					DIRECT_A3D_ELEM(data, z0, y0, x0) += dd000 * my_val;
+					DIRECT_A3D_ELEM(data, z0, y0, x1) += dd001 * my_val;
+					DIRECT_A3D_ELEM(data, z0, y1, x0) += dd010 * my_val;
+					DIRECT_A3D_ELEM(data, z0, y1, x1) += dd011 * my_val;
+					DIRECT_A3D_ELEM(data, z1, y0, x0) += dd100 * my_val;
+					DIRECT_A3D_ELEM(data, z1, y0, x1) += dd101 * my_val;
+					DIRECT_A3D_ELEM(data, z1, y1, x0) += dd110 * my_val;
+					DIRECT_A3D_ELEM(data, z1, y1, x1) += dd111 * my_val;
+					// Store corresponding weights
+					DIRECT_A3D_ELEM(weight, z0, y0, x0) += dd000 * my_weight;
+					DIRECT_A3D_ELEM(weight, z0, y0, x1) += dd001 * my_weight;
+					DIRECT_A3D_ELEM(weight, z0, y1, x0) += dd010 * my_weight;
+					DIRECT_A3D_ELEM(weight, z0, y1, x1) += dd011 * my_weight;
+					DIRECT_A3D_ELEM(weight, z1, y0, x0) += dd100 * my_weight;
+					DIRECT_A3D_ELEM(weight, z1, y0, x1) += dd101 * my_weight;
+					DIRECT_A3D_ELEM(weight, z1, y1, x0) += dd110 * my_weight;
+					DIRECT_A3D_ELEM(weight, z1, y1, x1) += dd111 * my_weight;
+
+				} // endif TRILINEAR
+				else if (interpolator == NEAREST_NEIGHBOUR )
+				{
+
+					x0 = ROUND(xp);
+					y0 = ROUND(yp);
+					z0 = ROUND(zp);
+
+					if (x0 < 0)
+					{
+						A3D_ELEM(data, -z0, -y0, -x0) += conj(my_val);
+						A3D_ELEM(weight, -z0, -y0, -x0) += my_weight;
+					}
+					else
+					{
+						A3D_ELEM(data, z0, y0, x0) += my_val;
+						A3D_ELEM(weight, z0, y0, x0) += my_weight;
+					}
+
+				} // endif NEAREST_NEIGHBOUR
+				else
+				{
+					REPORT_ERROR("FourierInterpolator::backproject%%ERROR: unrecognized interpolator ");
+				}
+			} // endif weight>0.
+		} // endif x-loop
+	} // endif y-loop
+}
+
+void BackProjector::backrotate2D(const MultidimArray<Complex > &f2d,
+		                         const Matrix2D<double> &A, bool inv,
+		                         const MultidimArray<double> *Mweight)
+{
+	double fx, fy, mfx, mfy, xp, yp;
+	int first_x, x0, x1, y0, y1, y, y2, r2;
+	bool is_neg_x;
+	double dd00, dd01, dd10, dd11;
+	Complex my_val;
+	Matrix2D<double> Ainv;
+	double my_weight = 1.;
+
+	// f2d should already be in the right size (ori_size,orihalfdim)
+    // AND the points outside max_r should already be zero...
+
+	// Use the inverse matrix
+    if (inv)
+    	Ainv = A;
+    else
+    	Ainv = A.transpose();
+
+    // Go from the 2D slice coordinates to the data-array coordinates
+    Ainv *= (double)padding_factor;  // take scaling into account directly
+    int max_r2 = r_max * r_max;
+    int min_r2_nn = r_min_nn * r_min_nn;
+
+//#define DEBUG_BACKROTATE
+#ifdef DEBUG_BACKROTATE
+    std::cerr << " XSIZE(f2d)= "<< XSIZE(f2d) << std::endl;
+    std::cerr << " YSIZE(f2d)= "<< YSIZE(f2d) << std::endl;
+    std::cerr << " XSIZE(data)= "<< XSIZE(data) << std::endl;
+    std::cerr << " YSIZE(data)= "<< YSIZE(data) << std::endl;
+    std::cerr << " STARTINGX(data)= "<< STARTINGX(data) << std::endl;
+    std::cerr << " STARTINGY(data)= "<< STARTINGY(data) << std::endl;
+    std::cerr << " STARTINGZ(data)= "<< STARTINGZ(data) << std::endl;
+    std::cerr << " max_r= "<< r_max << std::endl;
+    std::cerr << " Ainv= " << Ainv << std::endl;
+#endif
+
+    for (int i=0; i < YSIZE(f2d); i++)
+	{
+		// Don't search beyond square with side max_r
+		if (i <= r_max)
+		{
+			y = i;
+			first_x = 0;
+		}
+		else if (i >= YSIZE(f2d) - r_max)
+		{
+			y = i - YSIZE(f2d);
+			// x==0 plane is stored twice in the FFTW format. Dont set it twice in BACKPROJECTION!
+			first_x = 1;
+		}
+		else
+			continue;
+
+		y2 = y * y;
+		for (int x=first_x; x <= r_max; x++)
+		{
+	    	// Only include points with radius < max_r (exclude points outside circle in square)
+			r2 = x * x + y2;
+			if (r2 > max_r2)
+				continue;
+
+			// Get the relevant value in the input image
+			my_val = DIRECT_A2D_ELEM(f2d, i, x);
+
+			// Get the weight
+			if (Mweight != NULL)
+				my_weight = DIRECT_A2D_ELEM(*Mweight, i, x);
+			// else: my_weight was already initialised to 1.
+
+			if (my_weight > 0.)
+			{
+				// Get logical coordinates in the 3D map
+				xp = Ainv(0,0) * x + Ainv(0,1) * y;
+				yp = Ainv(1,0) * x + Ainv(1,1) * y;
+
+				if (interpolator == TRILINEAR || r2 < min_r2_nn)
+				{
+					// Only asymmetric half is stored
+					if (xp < 0)
+					{
+						// Get complex conjugated hermitian symmetry pair
+						xp = -xp;
+						yp = -yp;
+						is_neg_x = true;
+					}
+					else
+					{
+						is_neg_x = false;
+					}
+
+					// Trilinear interpolation (with physical coords)
+					// Subtract STARTINGY to accelerate access to data (STARTINGX=0)
+					// In that way use DIRECT_A2D_ELEM, rather than A2D_ELEM
+					x0 = FLOOR(xp);
+					fx = xp - x0;
+					x1 = x0 + 1;
+
+					y0 = FLOOR(yp);
+					fy = yp - y0;
+					y0 -=  STARTINGY(data);
+					y1 = y0 + 1;
+
+					mfx = 1. - fx;
+					mfy = 1. - fy;
+
+					dd00 = mfy * mfx;
+					dd01 = mfy *  fx;
+					dd10 =  fy * mfx;
+					dd11 =  fy *  fx;
+
+					if (is_neg_x)
+						my_val = conj(my_val);
+
+					// Store slice in 3D weighted sum
+					DIRECT_A2D_ELEM(data, y0, x0) += dd00 * my_val;
+					DIRECT_A2D_ELEM(data, y0, x1) += dd01 * my_val;
+					DIRECT_A2D_ELEM(data, y1, x0) += dd10 * my_val;
+					DIRECT_A2D_ELEM(data, y1, x1) += dd11 * my_val;
+
+					// Store corresponding weights
+					DIRECT_A2D_ELEM(weight, y0, x0) += dd00 * my_weight;
+					DIRECT_A2D_ELEM(weight, y0, x1) += dd01 * my_weight;
+					DIRECT_A2D_ELEM(weight, y1, x0) += dd10 * my_weight;
+					DIRECT_A2D_ELEM(weight, y1, x1) += dd11 * my_weight;
+
+				} // endif TRILINEAR
+				else if (interpolator == NEAREST_NEIGHBOUR )
+				{
+					x0 = ROUND(xp);
+					y0 = ROUND(yp);
+					if (x0 < 0)
+					{
+						A2D_ELEM(data, -y0, -x0) += conj(my_val);
+						A2D_ELEM(weight, -y0, -x0) += my_weight;
+					}
+					else
+					{
+						A2D_ELEM(data, y0, x0) += my_val;
+						A2D_ELEM(weight, y0, x0) += my_weight;
+					}
+				} // endif NEAREST_NEIGHBOUR
+				else
+				{
+					REPORT_ERROR("FourierInterpolator::backrotate2D%%ERROR: unrecognized interpolator ");
+				}
+			} // endif weight > 0.
+		} // endif x-loop
+	} // endif y-loop
+}
+
+void BackProjector::getLowResDataAndWeight(MultidimArray<Complex > &lowres_data, MultidimArray<double> &lowres_weight,
+		int lowres_r_max)
+{
+
+	int lowres_r2_max = padding_factor * padding_factor * lowres_r_max * lowres_r_max;
+	int lowres_pad_size = 2 * (padding_factor * lowres_r_max + 1) + 1;
+
+	// Check for dimension
+	if (ref_dim != 3)
+		REPORT_ERROR("BackProjector::getLowResDataAndWeight%%ERROR: only implemented for 3D case....");
+
+	// Check lowres_r_max is not too big
+	if (lowres_r_max > r_max)
+		REPORT_ERROR("BackProjector::getLowResDataAndWeight%%ERROR: lowres_r_max is bigger than r_max");
+
+	// Initialize lowres_data and low_res_weight arrays
+	lowres_data.clear();
+	lowres_data.resize(lowres_pad_size, lowres_pad_size, lowres_pad_size / 2 + 1);
+	lowres_data.setXmippOrigin();
+	lowres_data.xinit=0;
+	lowres_weight.clear();
+	lowres_weight.resize(lowres_pad_size, lowres_pad_size, lowres_pad_size / 2 + 1);
+	lowres_weight.setXmippOrigin();
+	lowres_weight.xinit=0;
+
+	// fill lowres arrays with relevant values
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(lowres_data)
+	{
+		if (k*k + i*i + j*j <= lowres_r2_max)
+		{
+			A3D_ELEM(lowres_data, k, i, j) = A3D_ELEM(data, k , i, j);
+			A3D_ELEM(lowres_weight, k, i, j) = A3D_ELEM(weight, k , i, j);
+		}
+	}
+
+}
+
+void BackProjector::setLowResDataAndWeight(MultidimArray<Complex > &lowres_data, MultidimArray<double> &lowres_weight,
+		int lowres_r_max)
+{
+
+	int lowres_r2_max = padding_factor * padding_factor * lowres_r_max * lowres_r_max;
+	int lowres_pad_size = 2 * (padding_factor * lowres_r_max + 1) + 1;
+
+	// Check for dimension
+	if (ref_dim != 3)
+		REPORT_ERROR("BackProjector::getLowResDataAndWeight%%ERROR: only implemented for 3D case....");
+
+	// Check lowres_r_max is not too big
+	if (lowres_r_max > r_max)
+		REPORT_ERROR("BackProjector::getLowResDataAndWeight%%ERROR: lowres_r_max is bigger than r_max");
+
+	// Check sizes of lowres_data and lowres_weight
+	if (ZSIZE(lowres_data) != lowres_pad_size || YSIZE(lowres_data) != lowres_pad_size || XSIZE(lowres_data) != lowres_pad_size / 2 + 1)
+		REPORT_ERROR("BackProjector::setLowResDataAndWeight%%ERROR: lowres_data is not of expected size...");
+	if (ZSIZE(lowres_weight) != lowres_pad_size || YSIZE(lowres_weight) != lowres_pad_size || XSIZE(lowres_weight) != lowres_pad_size / 2 + 1)
+		REPORT_ERROR("BackProjector::setLowResDataAndWeight%%ERROR: lowres_weight is not of expected size...");
+
+	// Re-set origin to the expected place
+	lowres_data.setXmippOrigin();
+	lowres_data.xinit=0;
+	lowres_weight.setXmippOrigin();
+	lowres_weight.xinit=0;
+
+	// Overwrite data and weight with the lowres arrays
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(lowres_data)
+	{
+		if (k*k + i*i + j*j <= lowres_r2_max)
+		{
+			A3D_ELEM(data, k, i, j) = A3D_ELEM(lowres_data, k , i, j);
+			A3D_ELEM(weight, k, i, j) = A3D_ELEM(lowres_weight, k , i, j);
+		}
+	}
+
+}
+
+
+void BackProjector::getDownsampledAverage(MultidimArray<Complex > &avg)
+{
+	MultidimArray<double> down_weight;
+
+	// Pre-set down_data and down_weight sizes
+	int down_size = 2 * (r_max + 1) + 1;
+	int r2_max = r_max * r_max;
+	// Short side of data array
+	switch (ref_dim)
+	{
+	case 2:
+	   avg.initZeros(down_size, down_size / 2 + 1);
+	   break;
+	case 3:
+	   avg.initZeros(down_size, down_size, down_size / 2 + 1);
+	   break;
+	default:
+	   REPORT_ERROR("BackProjector::getDownsampledAverage%%ERROR: Dimension of the data array should be 2 or 3");
+	}
+	// Set origin in the y.z-center, but on the left side for x.
+	avg.setXmippOrigin();
+	avg.xinit=0;
+	// Resize down_weight the same as down_data
+	down_weight.initZeros(avg);
+
+	// Now calculate the down-sized sum
+	int kp, ip, jp;
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(data)
+	{
+		kp = ROUND((double)k/padding_factor);
+		ip = ROUND((double)i/padding_factor);
+		jp = ROUND((double)j/padding_factor);
+
+// TMP
+//#define CHECK_SIZE
+#ifdef CHECK_SIZE
+		if (kp > FINISHINGZ(avg) || ip > FINISHINGY(avg) || jp > FINISHINGX(avg) ||
+				kp < STARTINGZ(avg) || ip < STARTINGY(avg) || jp < STARTINGX(avg))
+		{
+			std::cerr << " kp= " << kp << " ip= " << ip << " jp= " << jp << std::endl;
+			avg.printShape();
+			REPORT_ERROR("BackProjector::getDownsampledAverage: indices out of range");
+		}
+#endif
+		A3D_ELEM(avg, kp, ip, jp) += A3D_ELEM(data, k , i, j);
+		A3D_ELEM(down_weight, kp, ip, jp) += A3D_ELEM(weight, k , i, j);
+	}
+
+	// Then enforce Hermitian symmetry in the downsampled arrays
+	// We already took the average.... so not completely correct, but does not really matter for FSC calculation anyway
+	// enforceHermitianSymmetry(avg, down_weight);
+
+	// And enforce symmetry in the downsampled arrays
+	symmetrise(avg, down_weight, r2_max);
+
+	// Calculate the straightforward average in the downsampled arrays
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(avg)
+	{
+		if (DIRECT_MULTIDIM_ELEM(down_weight, n) > 0.)
+			DIRECT_MULTIDIM_ELEM(avg, n) /= DIRECT_MULTIDIM_ELEM(down_weight, n);
+		else
+			DIRECT_MULTIDIM_ELEM(avg, n) = 0.;
+	}
+
+
+}
+
+void BackProjector::calculateDownSampledFourierShellCorrelation(MultidimArray<Complex > &avg1,
+																MultidimArray<Complex > &avg2,
+																MultidimArray<double> &fsc)
+{
+
+    if (!avg1.sameShape(avg2))
+    	REPORT_ERROR("ERROR BackProjector::calculateDownSampledFourierShellCorrelation: two arrays have different sizes");
+
+    MultidimArray<double> num, den1, den2;
+    num.initZeros(ori_size/2 + 1);
+    den1.initZeros(num);
+    den2.initZeros(num);
+    fsc.initZeros(num);
+
+    FOR_ALL_ELEMENTS_IN_ARRAY3D(avg1)
+    {
+    	double R = sqrt(k*k + i*i + j*j);
+        if (R > r_max)
+            continue;
+        int idx=ROUND(R);
+        Complex z1=A3D_ELEM(avg1, k, i, j);
+        Complex z2=A3D_ELEM(avg2, k, i, j);
+        double absz1=abs(z1);
+        double absz2=abs(z2);
+        num(idx)+=(conj(z1) * z2).real;
+        den1(idx)+= absz1*absz1;
+        den2(idx)+= absz2*absz2;
+    }
+
+    FOR_ALL_ELEMENTS_IN_ARRAY1D(fsc)
+    {
+    	if (den1(i)*den2(i) > 0.)
+    		fsc(i) = num(i)/sqrt(den1(i)*den2(i));
+    }
+
+    // Always set zero-resolution shell to FSC=1
+    // Raimond Ravelli reported a problem with FSC=1 at res=0 on 13feb2013...
+    // (because of a suboptimal normalisation scheme, but anyway)
+    fsc(0) = 1.;
+
+}
+
+
+void BackProjector::reconstruct(MultidimArray<double> &vol_out,
+                                int max_iter_preweight,
+                                bool do_map,
+                                double tau2_fudge,
+                                MultidimArray<double> &tau2,
+                                MultidimArray<double> &sigma2,
+                                MultidimArray<double> &data_vs_prior,
+                                MultidimArray<double> fsc, // only input
+                                double normalise,
+                                bool update_tau2_with_fsc,
+                                bool is_whole_instead_of_half,
+                                int nr_threads,
+                                int minres_map)
+
+{
+
+
+    FourierTransformer transformer;
+	// The threads are giving me a headache. Let's switch them off
+    // Somehow I get lots of bad/non-reproducible errors when having these...
+    //transformer.setThreadsNumber(nr_threads);
+	MultidimArray<Complex > Fconv;
+	MultidimArray<double> Fweight, Fnewweight;
+	int max_r2 = r_max * r_max * padding_factor * padding_factor;
+
+//#define DEBUG_RECONSTRUCT
+#ifdef DEBUG_RECONSTRUCT
+	Image<double> ttt;
+	FileName fnttt;
+	ttt()=weight;
+	ttt.write("reconstruct_initial_weight.spi");
+#endif
+
+	// At the x=0 line, we have collected either the positive y-z coordinate, or its negative Friedel pair.
+	// Sum these two together for both the data and the weight arrays
+	enforceHermitianSymmetry(data, weight);
+
+#ifdef DEBUG_RECONSTRUCT
+	ttt()=weight;
+	ttt.write("reconstruct_hermitian_weight.spi");
+#endif
+
+	// First enforce Hermitian symmetry, then symmetry!
+	// This way the redundancy at the x=0 plane is handled correctly
+	symmetrise(data, weight, max_r2);
+#ifdef DEBUG_RECONSTRUCT
+	ttt()=weight;
+	ttt.write("reconstruct_symmetrised_weight.spi");
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(data)
+	{
+		DIRECT_MULTIDIM_ELEM(ttt(), n) = DIRECT_MULTIDIM_ELEM(data, n).real;
+	}
+	ttt.write("reconstruct_symmetrised_data_real.spi");
+
+	std::cerr << " pad_size= " << pad_size << " padding_factor= " << padding_factor << " max_r2= " << max_r2 << std::endl;
+#endif
+
+
+	// Set Fweight, Fnewweight and Fconv to the right size
+	if (ref_dim == 2)
+		vol_out.resize(pad_size, pad_size);
+	else
+		vol_out.resize(pad_size, pad_size, pad_size);
+
+	transformer.setReal(vol_out);
+	transformer.getFourierAlias(Fconv);
+
+	// clear vol_out to save memory!
+	vol_out.clear();
+
+	Fweight.resize(Fconv);
+	Fnewweight.resize(Fconv);
+	// Go from projector-centered to FFTW-uncentered
+	decenter(weight, Fweight, max_r2);
+
+	// Take oversampling into account
+	double oversampling_correction = (ref_dim == 3) ? (padding_factor * padding_factor * padding_factor) : (padding_factor * padding_factor);
+	MultidimArray<double> counter;
+
+
+	// First calculate the radial average of the (inverse of the) power of the noise in the reconstruction
+	// This is the left-hand side term in the nominator of the Wiener-filter-like update formula
+	// and it is stored inside the weight vector
+	// Then, if (do_map) add the inverse of tau2-spectrum values to the weight
+	sigma2.initZeros(ori_size/2 + 1);
+	counter.initZeros(ori_size/2 + 1);
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Fconv)
+	{
+		int r2 = kp * kp + ip * ip + jp * jp;
+		if (r2 < max_r2)
+		{
+			int ires = ROUND( sqrt((double)r2) / padding_factor );
+			double invw = oversampling_correction * DIRECT_A3D_ELEM(Fweight, k, i, j);
+			DIRECT_A1D_ELEM(sigma2, ires) += invw;
+			DIRECT_A1D_ELEM(counter, ires) += 1.;
+		}
+	}
+
+	// Average (inverse of) sigma2 in reconstruction
+	FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(sigma2)
+	{
+		if (DIRECT_A1D_ELEM(sigma2, i) > 1e-10)
+			DIRECT_A1D_ELEM(sigma2, i) = DIRECT_A1D_ELEM(counter, i) / DIRECT_A1D_ELEM(sigma2, i);
+		else if (DIRECT_A1D_ELEM(sigma2, i) == 0)
+			DIRECT_A1D_ELEM(sigma2, i) = 0.;
+		else
+		{
+			std::cerr << " DIRECT_A1D_ELEM(sigma2, i)= " << DIRECT_A1D_ELEM(sigma2, i) << std::endl;
+			REPORT_ERROR("BackProjector::reconstruct: ERROR: unexpectedly small, yet non-zero sigma2 value, this should not happen...a");
+		}
+	}
+
+	if (update_tau2_with_fsc)
+	{
+		tau2.resize(ori_size/2 + 1);
+		data_vs_prior.initZeros(ori_size/2 + 1);
+		// Then calculate new tau2 values, based on the FSC
+		if (!fsc.sameShape(sigma2) || !fsc.sameShape(tau2))
+		{
+			fsc.printShape(std::cerr);
+			tau2.printShape(std::cerr);
+			sigma2.printShape(std::cerr);
+			REPORT_ERROR("ERROR BackProjector::reconstruct: sigma2, tau2 and fsc have different sizes");
+		}
+		FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(sigma2)
+		{
+			// FSC cannot be negative or zero for conversion into tau2
+			double myfsc = XMIPP_MAX(0.001, DIRECT_A1D_ELEM(fsc, i));
+			if (is_whole_instead_of_half)
+			{
+				// Factor two because of twice as many particles
+				// Sqrt-term to get 60-degree phase errors....
+				myfsc = sqrt(2. * myfsc / (myfsc + 1.));
+			}
+			myfsc = XMIPP_MIN(0.999, myfsc);
+			double myssnr = myfsc / (1. - myfsc);
+			double fsc_based_tau = myssnr * DIRECT_A1D_ELEM(sigma2, i);
+			DIRECT_A1D_ELEM(tau2, i) = fsc_based_tau;
+			// data_vs_prior is merely for reporting: it is not used for anything in the reconstruction
+			DIRECT_A1D_ELEM(data_vs_prior, i) = myssnr;
+
+		}
+	}
+
+	// Apply MAP-additional term to the Fnewweight array
+	// This will regularise the actual reconstruction
+	if (do_map)
+	{
+		// Then, add the inverse of tau2-spectrum values to the weight
+		// and also calculate spherical average of data_vs_prior ratios
+		if (!update_tau2_with_fsc)
+			data_vs_prior.initZeros(ori_size/2 + 1);
+		counter.initZeros(ori_size/2 + 1);
+		FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Fconv)
+ 		{
+			int r2 = kp * kp + ip * ip + jp * jp;
+			if (r2 < max_r2)
+			{
+				int ires = ROUND( sqrt((double)r2) / padding_factor );
+				double invw = DIRECT_A3D_ELEM(Fweight, k, i, j);
+
+				double invtau2;
+				if (DIRECT_A1D_ELEM(tau2, ires) > 0.)
+				{
+					// Calculate inverse of tau2
+					invtau2 = 1. / (oversampling_correction * tau2_fudge * DIRECT_A1D_ELEM(tau2, ires));
+				}
+				else if (DIRECT_A1D_ELEM(tau2, ires) == 0.)
+				{
+					// If tau2 is zero, use small value instead
+					invtau2 = 1./ ( 0.001 * invw);
+				}
+				else
+				{
+					std::cerr << " sigma2= " << sigma2 << std::endl;
+					std::cerr << " fsc= " << fsc << std::endl;
+					std::cerr << " tau2= " << tau2 << std::endl;
+					REPORT_ERROR("ERROR BackProjector::reconstruct: Negative or zero values encountered for tau2 spectrum!");
+				}
+
+				// Keep track of spectral evidence-to-prior ratio and remaining noise in the reconstruction
+				if (!update_tau2_with_fsc)
+					DIRECT_A1D_ELEM(data_vs_prior, ires) += invw / invtau2;
+				DIRECT_A1D_ELEM(counter, ires) += 1.;
+
+				// Only for (ires >= minres_map) add Wiener-filter like term
+				if (ires >= minres_map)
+				{
+					// Now add the inverse-of-tau2_class term
+					invw += invtau2;
+					// Store the new weight again in Fweight
+					DIRECT_A3D_ELEM(Fweight, k, i, j) = invw;
+				}
+			}
+		}
+
+		// Average data_vs_prior
+		if (!update_tau2_with_fsc)
+		{
+			FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(data_vs_prior)
+			{
+				if (i > r_max)
+					DIRECT_A1D_ELEM(data_vs_prior, i) = 0.;
+				else if (DIRECT_A1D_ELEM(counter, i) < 0.001)
+					DIRECT_A1D_ELEM(data_vs_prior, i) = 999.;
+				else
+					DIRECT_A1D_ELEM(data_vs_prior, i) /= DIRECT_A1D_ELEM(counter, i);
+			}
+		}
+
+	} //end if do_map
+
+	// Divide both data and Fweight by normalisation factor to prevent FFT's with very large values....
+#ifdef DEBUG_RECONSTRUCT
+	std::cerr << " normalise= " << normalise << std::endl;
+#endif
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fweight)
+	{
+		DIRECT_MULTIDIM_ELEM(Fweight, n) /= normalise;
+	}
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(data)
+	{
+		DIRECT_MULTIDIM_ELEM(data, n) /= normalise;
+	}
+
+	// Initialise Fnewweight with 1's and 0's. (also see comments below)
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(weight)
+	{
+		if (k * k + i * i + j * j < max_r2)
+			A3D_ELEM(weight, k, i, j) = 1.;
+		else
+			A3D_ELEM(weight, k, i, j) = 0.;
+	}
+	decenter(weight, Fnewweight, max_r2);
+
+	// Iterative algorithm as in  Eq. [14] in Pipe & Menon (1999)
+	// or Eq. (4) in Matej (2001)
+	for (int iter = 0; iter < max_iter_preweight; iter++)
+	{
+
+		// Set Fnewweight * Fweight in the transformer
+		// In Matej et al (2001), weights w_P^i are convoluted with the kernel,
+		// and the initial w_P^0 are 1 at each sampling point
+		// Here the initial weights are also 1 (see initialisation Fnewweight above),
+		// but each "sampling point" counts "Fweight" times!
+		// That is why Fnewweight is multiplied by Fweight prior to the convolution
+		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fconv)
+		{
+			DIRECT_MULTIDIM_ELEM(Fconv, n) = DIRECT_MULTIDIM_ELEM(Fnewweight, n) * DIRECT_MULTIDIM_ELEM(Fweight, n);
+		}
+
+        // convolute through Fourier-transform (as both grids are rectangular)
+        // Note that convoluteRealSpace acts on the complex array inside the transformer
+        convoluteBlobRealSpace(transformer);
+
+        double w, corr_min = 99.e99, corr_max = -99.e99, corr_avg=0., corr_nn=0.;
+        FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Fconv)
+        {
+        	if (kp * kp + ip * ip + jp * jp < max_r2)
+        	{
+
+        		// Make sure no division by zero can occur....
+        		w = XMIPP_MAX(1e-6, abs(DIRECT_A3D_ELEM(Fconv, k, i, j)));
+        		// Monitor min, max and avg conv_weight
+        		corr_min = XMIPP_MIN(corr_min, w);
+        		corr_max = XMIPP_MAX(corr_max, w);
+        		corr_avg += w;
+        		corr_nn += 1.;
+        		// Apply division of Eq. [14] in Pipe & Menon (1999)
+        		DIRECT_A3D_ELEM(Fnewweight, k, i, j) /= w;
+        	}
+        }
+
+#ifdef DEBUG_RECONSTRUCT
+        std::cerr << " PREWEIGHTING ITERATION: "<< iter + 1 << " OF " << max_iter_preweight << std::endl;
+        // report of maximum and minimum values of current conv_weight
+        std::cerr << " corr_avg= " << corr_avg / corr_nn << std::endl;
+        std::cerr << " corr_min= " << corr_min << std::endl;
+        std::cerr << " corr_max= " << corr_max << std::endl;
+#endif
+	}
+
+#ifdef DEBUG_RECONSTRUCT
+	ttt()=Fnewweight;
+	ttt.write("reconstruct_gridding_weight.spi");
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fconv)
+	{
+		DIRECT_MULTIDIM_ELEM(ttt(), n) = abs(DIRECT_MULTIDIM_ELEM(Fconv, n));
+	}
+	ttt.write("reconstruct_gridding_correction_term.spi");
+#endif
+
+	// Clear memory
+	Fweight.clear();
+
+	// Note that Fnewweight now holds the approximation of the inverse of the weights on a regular grid
+
+	// Now do the actual reconstruction with the data array
+	// Apply the iteratively determined weight
+	Fconv.initZeros(); // to remove any stuff from the input volume
+	decenter(data, Fconv, max_r2);
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fconv)
+	{
+		DIRECT_MULTIDIM_ELEM(Fconv, n) *= DIRECT_MULTIDIM_ELEM(Fnewweight, n);
+	}
+
+	// Clear memory
+	Fnewweight.clear();
+
+// Gridding theory says one now has to interpolate the fine grid onto the coarse one using a blob kernel
+// and then do the inverse transform and divide by the FT of the blob (i.e. do the gridding correction)
+// In practice, this gives all types of artefacts (perhaps I never found the right implementation?!)
+// Therefore, window the Fourier transform and then do the inverse transform
+//#define RECONSTRUCT_CONVOLUTE_BLOB
+#ifdef RECONSTRUCT_CONVOLUTE_BLOB
+
+	// Apply the same blob-convolution as above to the data array
+	// Mask real-space map beyond its original size to prevent aliasing in the downsampling step below
+	convoluteBlobRealSpace(transformer, true);
+
+	// Now just pick every 3rd pixel in Fourier-space (i.e. down-sample)
+	// and do a final inverse FT
+	if (ref_dim == 2)
+		vol_out.resize(ori_size, ori_size);
+	else
+		vol_out.resize(ori_size, ori_size, ori_size);
+
+	FourierTransformer transformer2;
+	MultidimArray<Complex > Ftmp;
+	transformer2.setReal(vol_out); // cannot use the first transformer because Fconv is inside there!!
+	transformer2.getFourierAlias(Ftmp);
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Ftmp)
+	{
+		if (kp * kp + ip * ip + jp * jp < r_max * r_max)
+		{
+			DIRECT_A3D_ELEM(Ftmp, k, i, j) = FFTW_ELEM(Fconv, kp * padding_factor, ip * padding_factor, jp * padding_factor);
+		}
+		else
+		{
+			DIRECT_A3D_ELEM(Ftmp, k, i, j) = 0.;
+		}
+	}
+
+	// inverse FFT leaves result in vol_out
+	transformer2.inverseFourierTransform();
+
+	// Shift the map back to its origin
+	CenterFFT(vol_out, false);
+
+	// Un-normalize FFTW (because original FFTs were done with the size of 2D FFTs)
+	if (ref_dim==3)
+		vol_out /= ori_size;
+
+	// Mask out corners to prevent aliasing artefacts
+	softMaskOutsideMap(vol_out);
+
+	// Gridding correction for the blob
+	double normftblob = tab_ftblob(0.);
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(vol_out)
+	{
+
+		double r = sqrt((double)(k*k+i*i+j*j));
+		double rval = r / (ori_size * padding_factor);
+		A3D_ELEM(vol_out, k, i, j) /= tab_ftblob(rval) / normftblob;
+		//if (k==0 && i==0)
+		//	std::cerr << " j= " << j << " rval= " << rval << " tab_ftblob(rval) / normftblob= " << tab_ftblob(rval) / normftblob << std::endl;
+	}
+
+
+#else
+
+
+
+	// rather than doing the blob-convolution to downsample the data array, do a windowing operation:
+	// This is the same as convolution with a SINC. It seems to give better maps.
+	// Then just make the blob look as much as a SINC as possible....
+	// The "standard" r1.9, m2 and a15 blob looks quite like a sinc until the first zero (perhaps that's why it is standard?)
+	//for (double r = 0.1; r < 10.; r+=0.01)
+	//{
+	//	double sinc = sin(PI * r / padding_factor ) / ( PI * r / padding_factor);
+	//	std::cout << " r= " << r << " sinc= " << sinc << " blob= " << blob_val(r, blob) << std::endl;
+	//}
+
+	// Now do inverse FFT and window to original size in real-space
+	// Pass the transformer to prevent making and clearing a new one before clearing the one declared above....
+	// The latter may give memory problems as detected by electric fence....
+	windowToOridimRealSpace(transformer, Fconv, vol_out, nr_threads);
+
+#endif
+
+#ifdef DEBUG_RECONSTRUCT
+	ttt()=vol_out;
+	ttt.write("reconstruct_before_gridding_correction.spi");
+#endif
+
+	// Correct for the linear/nearest-neighbour interpolation that led to the data array
+	griddingCorrect(vol_out);
+
+
+	// If the tau-values were calculated based on the FSC, then now re-calculate the power spectrum of the actual reconstruction
+	if (update_tau2_with_fsc)
+	{
+
+		// New tau2 will be the power spectrum of the new map
+		MultidimArray<double> spectrum, count;
+
+		// Calculate this map's power spectrum
+		// Don't call getSpectrum() because we want to use the same transformer object to prevent memory trouble....
+		spectrum.initZeros(XSIZE(vol_out));
+	    count.initZeros(XSIZE(vol_out));
+	    // recycle the same transformer for all imagses
+	    transformer.FourierTransform(vol_out, Fconv, false);
+	    FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Fconv)
+	    {
+	    	long int idx = ROUND(sqrt(kp*kp + ip*ip + jp*jp));
+	    	spectrum(idx) += norm(dAkij(Fconv, k, i, j));
+	        count(idx) += 1.;
+	    }
+	    spectrum /= count;
+
+		// Factor two because of two-dimensionality of the complex plane
+		// (just like sigma2_noise estimates, the power spectra should be divided by 2)
+		double normfft = (ref_dim==3) ? (double)(ori_size * ori_size) : 1.;
+		spectrum *= normfft / 2.;
+
+		// New SNR^MAP will be power spectrum divided by the noise in the reconstruction (i.e. sigma2)
+		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(data_vs_prior)
+		{
+			DIRECT_MULTIDIM_ELEM(tau2, n) =  tau2_fudge * DIRECT_MULTIDIM_ELEM(spectrum, n);
+		}
+
+	}
+
+	// Completely empty the transformer object
+	transformer.cleanup();
+
+#ifdef DEBUG_RECONSTRUCT
+    std::cerr<<"done with reconstruct"<<std::endl;
+#endif
+
+}
+
+void BackProjector::enforceHermitianSymmetry(MultidimArray<Complex > &my_data,
+											 MultidimArray<double> &my_weight)
+{
+
+	for (int iz = STARTINGZ(my_data); iz <=FINISHINGZ(my_data); iz++)
+	{
+		// Make sure all points are only included once.
+		int starty = (iz < 0) ? 0 : 1;
+		for (int iy = starty; iy <= FINISHINGY(my_data); iy++)
+		{
+			// I just need to sum the two points, not divide by 2!
+			Complex fsum = (A3D_ELEM(my_data, iz, iy, 0) + conj(A3D_ELEM(my_data, -iz, -iy, 0)));
+			A3D_ELEM(my_data, iz, iy, 0) = fsum;
+			A3D_ELEM(my_data, -iz, -iy, 0) = conj(fsum);
+			double sum = (A3D_ELEM(my_weight, iz, iy, 0) + A3D_ELEM(my_weight, -iz, -iy, 0));
+			A3D_ELEM(my_weight, iz, iy, 0) = sum;
+			A3D_ELEM(my_weight, -iz, -iy, 0) = sum;
+		}
+	}
+
+}
+
+void BackProjector::symmetrise(MultidimArray<Complex > &my_data,
+		 MultidimArray<double> &my_weight, int my_rmax2)
+{
+
+//#define DEBUG_SYMM
+#ifdef DEBUG_SYMM
+	std::cerr << " SL.SymsNo()= " << SL.SymsNo() << std::endl;
+	std::cerr << " SL.true_symNo= " << SL.true_symNo << std::endl;
+#endif
+
+	if (SL.SymsNo() > 0 && ref_dim == 3)
+	{
+		Matrix2D<double> L(4, 4), R(4, 4); // A matrix from the list
+		MultidimArray<double> sum_weight;
+		MultidimArray<Complex > sum_data;
+        double x, y, z, fx, fy, fz, xp, yp, zp, r2;
+        bool is_neg_x;
+        int x0, x1, y0, y1, z0, z1;
+    	Complex d000, d001, d010, d011, d100, d101, d110, d111;
+    	Complex dx00, dx01, dx10, dx11, dxy0, dxy1;
+    	double dd000, dd001, dd010, dd011, dd100, dd101, dd110, dd111;
+    	double ddx00, ddx01, ddx10, ddx11, ddxy0, ddxy1;
+
+        // First symmetry operator (not stored in SL) is the identity matrix
+		sum_weight = my_weight;
+		sum_data = my_data;
+		// Loop over all other symmetry operators
+	    for (int isym = 0; isym < SL.SymsNo(); isym++)
+	    {
+	        SL.get_matrices(isym, L, R);
+#ifdef DEBUG_SYMM
+	        std::cerr << " isym= " << isym << " R= " << R << std::endl;
+#endif
+
+	        // Loop over all points in the output (i.e. rotated, or summed) array
+	        FOR_ALL_ELEMENTS_IN_ARRAY3D(sum_weight)
+	        {
+
+	        	x = (double)j; // STARTINGX(sum_weight) is zero!
+	        	y = (double)i;
+	        	z = (double)k;
+	        	r2 = x*x + y*y + z*z;
+	        	if (r2 <= my_rmax2)
+	        	{
+	        		// coords_output(x,y) = A * coords_input (xp,yp)
+					xp = x * R(0, 0) + y * R(0, 1) + z * R(0, 2);
+					yp = x * R(1, 0) + y * R(1, 1) + z * R(1, 2);
+					zp = x * R(2, 0) + y * R(2, 1) + z * R(2, 2);
+
+					// Only asymmetric half is stored
+					if (xp < 0)
+					{
+						// Get complex conjugated hermitian symmetry pair
+						xp = -xp;
+						yp = -yp;
+						zp = -zp;
+						is_neg_x = true;
+					}
+					else
+					{
+						is_neg_x = false;
+					}
+
+					// Trilinear interpolation (with physical coords)
+					// Subtract STARTINGY and STARTINGZ to accelerate access to data (STARTINGX=0)
+					// In that way use DIRECT_A3D_ELEM, rather than A3D_ELEM
+	    			x0 = FLOOR(xp);
+					fx = xp - x0;
+					x1 = x0 + 1;
+
+					y0 = FLOOR(yp);
+					fy = yp - y0;
+					y0 -=  STARTINGY(my_data);
+					y1 = y0 + 1;
+
+					z0 = FLOOR(zp);
+					fz = zp - z0;
+					z0 -= STARTINGZ(my_data);
+					z1 = z0 + 1;
+
+#ifdef CHECK_SIZE
+					if (x0 < 0 || y0 < 0 || z0 < 0 ||
+						x1 < 0 || y1 < 0 || z1 < 0 ||
+						x0 >= XSIZE(my_data) || y0  >= YSIZE(my_data) || z0 >= ZSIZE(my_data) ||
+						x1 >= XSIZE(my_data) || y1  >= YSIZE(my_data)  || z1 >= ZSIZE(my_data) 	)
+					{
+						std::cerr << " x0= " << x0 << " y0= " << y0 << " z0= " << z0 << std::endl;
+						std::cerr << " x1= " << x1 << " y1= " << y1 << " z1= " << z1 << std::endl;
+						my_data.printShape();
+						REPORT_ERROR("BackProjector::symmetrise: checksize!!!");
+					}
+#endif
+					// First interpolate (complex) data
+					d000 = DIRECT_A3D_ELEM(my_data, z0, y0, x0);
+					d001 = DIRECT_A3D_ELEM(my_data, z0, y0, x1);
+					d010 = DIRECT_A3D_ELEM(my_data, z0, y1, x0);
+					d011 = DIRECT_A3D_ELEM(my_data, z0, y1, x1);
+					d100 = DIRECT_A3D_ELEM(my_data, z1, y0, x0);
+					d101 = DIRECT_A3D_ELEM(my_data, z1, y0, x1);
+					d110 = DIRECT_A3D_ELEM(my_data, z1, y1, x0);
+					d111 = DIRECT_A3D_ELEM(my_data, z1, y1, x1);
+
+					dx00 = LIN_INTERP(fx, d000, d001);
+					dx01 = LIN_INTERP(fx, d100, d101);
+					dx10 = LIN_INTERP(fx, d010, d011);
+					dx11 = LIN_INTERP(fx, d110, d111);
+					dxy0 = LIN_INTERP(fy, dx00, dx10);
+					dxy1 = LIN_INTERP(fy, dx01, dx11);
+
+					// Take complex conjugated for half with negative x
+					if (is_neg_x)
+						A3D_ELEM(sum_data, k, i, j) += conj(LIN_INTERP(fz, dxy0, dxy1));
+					else
+						A3D_ELEM(sum_data, k, i, j) += LIN_INTERP(fz, dxy0, dxy1);
+
+					// Then interpolate (real) weight
+					dd000 = DIRECT_A3D_ELEM(my_weight, z0, y0, x0);
+					dd001 = DIRECT_A3D_ELEM(my_weight, z0, y0, x1);
+					dd010 = DIRECT_A3D_ELEM(my_weight, z0, y1, x0);
+					dd011 = DIRECT_A3D_ELEM(my_weight, z0, y1, x1);
+					dd100 = DIRECT_A3D_ELEM(my_weight, z1, y0, x0);
+					dd101 = DIRECT_A3D_ELEM(my_weight, z1, y0, x1);
+					dd110 = DIRECT_A3D_ELEM(my_weight, z1, y1, x0);
+					dd111 = DIRECT_A3D_ELEM(my_weight, z1, y1, x1);
+
+					ddx00 = LIN_INTERP(fx, dd000, dd001);
+					ddx01 = LIN_INTERP(fx, dd100, dd101);
+					ddx10 = LIN_INTERP(fx, dd010, dd011);
+					ddx11 = LIN_INTERP(fx, dd110, dd111);
+					ddxy0 = LIN_INTERP(fy, ddx00, ddx10);
+					ddxy1 = LIN_INTERP(fy, ddx01, ddx11);
+
+					A3D_ELEM(sum_weight, k, i, j) +=  LIN_INTERP(fz, ddxy0, ddxy1);
+
+	        	} // end if r2 <= my_rmax2
+
+	        } // end loop over all elements of sum_weight
+
+	    } // end loop over symmetry operators
+
+	    my_data = sum_data;
+	    my_weight = sum_weight;
+	    // Average
+	    // The division should only be done if we would search all (C1) directions, not if we restrict the angular search!
+	    /*
+	    FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(data)
+	    {
+	    	DIRECT_MULTIDIM_ELEM(data, n) = DIRECT_MULTIDIM_ELEM(sum_data, n) / (double)(SL.SymsNo() + 1);
+	    	DIRECT_MULTIDIM_ELEM(weight, n) = DIRECT_MULTIDIM_ELEM(sum_weight, n) / (double)(SL.SymsNo() + 1);
+	    }
+	    */
+	}
+
+}
+
+void BackProjector::convoluteBlobRealSpace(FourierTransformer &transformer, bool do_mask)
+{
+
+	MultidimArray<double> Mconv;
+	int padhdim = pad_size / 2;
+
+	// Set up right dimension of real-space array
+	// TODO: resize this according to r_max!!!
+	if (ref_dim==2)
+		Mconv.resize(pad_size, pad_size);
+	else
+		Mconv.resize(pad_size, pad_size, pad_size);
+
+	// inverse FFT
+	transformer.setReal(Mconv);
+	transformer.inverseFourierTransform();
+
+	// Blob normalisation in Fourier space
+	double normftblob = tab_ftblob(0.);
+
+	// TMP DEBUGGING
+	//struct blobtype blob;
+	//blob.order = 0;
+	//blob.radius = 1.9 * padding_factor;
+	//blob.alpha = 15;
+
+	// Multiply with FT of the blob kernel
+	FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Mconv)
+    {
+		int kp = (k < padhdim) ? k : k - pad_size;
+		int ip = (i < padhdim) ? i : i - pad_size;
+		int jp = (j < padhdim) ? j : j - pad_size;
+    	double rval = sqrt ( (double)(kp * kp + ip * ip + jp * jp) ) / (ori_size * padding_factor);
+    	//if (kp==0 && ip==0 && jp > 0)
+		//	std::cerr << " jp= " << jp << " rval= " << rval << " tab_ftblob(rval) / normftblob= " << tab_ftblob(rval) / normftblob << " ori_size/2= " << ori_size/2 << std::endl;
+    	// In the final reconstruction: mask the real-space map beyond its original size to prevent aliasing ghosts
+    	// Note that rval goes until 1/2 in the oversampled map
+    	if (do_mask && rval > 1./(2. * padding_factor))
+    		DIRECT_A3D_ELEM(Mconv, k, i, j) = 0.;
+    	else
+    		DIRECT_A3D_ELEM(Mconv, k, i, j) *= (tab_ftblob(rval) / normftblob);
+    }
+
+    // forward FFT to go back to Fourier-space
+    transformer.FourierTransform();
+
+}
+
+void BackProjector::windowToOridimRealSpace(FourierTransformer &transformer, MultidimArray<Complex > &Fin, MultidimArray<double> &Mout, int nr_threads)
+{
+
+	MultidimArray<Complex > Ftmp;
+	int padoridim = padding_factor * ori_size;
+	double normfft;
+
+//#define DEBUG_WINDOWORIDIMREALSPACE
+#ifdef DEBUG_WINDOWORIDIMREALSPACE
+	Image<double> tt;
+	tt().resize(ZSIZE(Fin), YSIZE(Fin), XSIZE(Fin));
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fin)
+	{
+		DIRECT_MULTIDIM_ELEM(tt(), n) = abs(DIRECT_MULTIDIM_ELEM(Fin, n));
+	}
+	tt.write("windoworidim_Fin.spi");
+#endif
+
+	if (ref_dim == 2)
+	{
+		Mout.resize(padoridim, padoridim);
+		normfft = (double)(padding_factor * padding_factor);
+	}
+	else
+	{
+		Mout.resize(padoridim, padoridim, padoridim);
+		normfft = (double)(padding_factor * padding_factor * padding_factor * ori_size);
+	}
+	Mout.setXmippOrigin();
+
+	// Resize incoming complex array to the correct size
+	windowFourierTransform(Fin, Ftmp, padoridim);
+
+#ifdef DEBUG_WINDOWORIDIMREALSPACE
+	tt().resize(ZSIZE(Ftmp), YSIZE(Ftmp), XSIZE(Ftmp));
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Ftmp)
+	{
+		DIRECT_MULTIDIM_ELEM(tt(), n) = abs(DIRECT_MULTIDIM_ELEM(Ftmp, n));
+	}
+	tt.write("windoworidim_Fresized.spi");
+#endif
+
+	// Do the inverse FFT
+	transformer.inverseFourierTransform(Ftmp, Mout);
+	Mout.setXmippOrigin();
+
+	// Shift the map back to its origin
+	CenterFFT(Mout,true);
+
+#ifdef DEBUG_WINDOWORIDIMREALSPACE
+	tt()=Mout;
+	tt.write("windoworidim_Munwindowed.spi");
+#endif
+
+	// Window in real-space
+	if (ref_dim==2)
+	{
+		Mout.window(FIRST_XMIPP_INDEX(ori_size), FIRST_XMIPP_INDEX(ori_size),
+				       LAST_XMIPP_INDEX(ori_size), LAST_XMIPP_INDEX(ori_size));
+	}
+	else
+	{
+		Mout.window(FIRST_XMIPP_INDEX(ori_size), FIRST_XMIPP_INDEX(ori_size), FIRST_XMIPP_INDEX(ori_size),
+				       LAST_XMIPP_INDEX(ori_size), LAST_XMIPP_INDEX(ori_size), LAST_XMIPP_INDEX(ori_size));
+	}
+	Mout.setXmippOrigin();
+
+	// Normalisation factor of FFTW
+	// The Fourier Transforms are all "normalised" for 2D transforms of size = ori_size x ori_size
+	Mout /= normfft;
+
+#ifdef DEBUG_WINDOWORIDIMREALSPACE
+	tt()=Mout;
+	tt.write("windoworidim_Mwindowed.spi");
+#endif
+
+	// Mask out corners to prevent aliasing artefacts
+	softMaskOutsideMap(Mout);
+
+#ifdef DEBUG_WINDOWORIDIMREALSPACE
+	tt()=Mout;
+	tt.write("windoworidim_Mwindowed_masked.spi");
+	FourierTransformer ttf;
+	ttf.FourierTransform(Mout, Ftmp);
+	tt().resize(ZSIZE(Ftmp), YSIZE(Ftmp), XSIZE(Ftmp));
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Ftmp)
+	{
+		DIRECT_MULTIDIM_ELEM(tt(), n) = abs(DIRECT_MULTIDIM_ELEM(Ftmp, n));
+	}
+	tt.write("windoworidim_Fnew.spi");
+#endif
+
+
+}
diff --git a/src/backprojector.h b/src/backprojector.h
new file mode 100644
index 0000000..3a01093
--- /dev/null
+++ b/src/backprojector.h
@@ -0,0 +1,276 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+/*
+ * backprojector.h
+ *
+ *  Created on: 24 Aug 2010
+ *      Author: scheres
+ */
+
+#ifndef BACKPROJECTOR_H_
+#define BACKPROJECTOR_H_
+
+#include "src/projector.h"
+#include "src/mask.h"
+#include "src/tabfuncs.h"
+#include "src/symmetries.h"
+
+class BackProjector: public Projector
+{
+public:
+	// For backward projection: sum of weights
+	MultidimArray<double> weight;
+
+	// Tabulated blob values
+	TabFtBlob tab_ftblob;
+
+	// Symmetry object
+    SymList SL;
+
+public:
+
+    /** Empty constructor
+	 *
+	 * A BackProjector is created.
+	 *
+	 * @code
+	 * BackProjector BPref(orisize, 3, "d2");
+	 * @endcode
+	 */
+	BackProjector(int _ori_size, int _ref_dim, FileName fn_sym,
+			      int _interpolator = TRILINEAR, int _padding_factor_3d = 2, int _r_min_nn = 10,
+			      int _blob_order = 0, double _blob_radius = 1.9, double _blob_alpha = 15)
+	{
+    	// Store original dimension
+    	ori_size = _ori_size;
+
+    	// Set dimensionality of the references
+    	ref_dim = _ref_dim;
+
+    	// Set the symmetry object
+    	SL.read_sym_file(fn_sym);
+
+    	// Padding factor for the map
+    	padding_factor = _padding_factor_3d;
+
+    	// Interpolation scheme
+    	interpolator = _interpolator;
+
+    	// Minimum radius for NN interpolation
+    	r_min_nn = _r_min_nn;
+
+    	// Precalculate tabulated ftblob values
+    	tab_ftblob.initialise(_blob_radius * padding_factor, _blob_alpha, _blob_order, 10000);
+
+	}
+
+    /** Copy constructor
+     *
+     * The created BackProjector is a perfect copy of the input array but with a
+     * different memory assignment.
+     *
+     * @code
+     * BackProjector V2(V1);
+     * @endcode
+     */
+	BackProjector(const BackProjector& op)
+    {
+		clear();
+        *this = op;
+    }
+
+	/** Assignment.
+     *
+     * You can build as complex assignment expressions as you like. Multiple
+     * assignment is allowed.
+     */
+	BackProjector& operator=(const BackProjector& op)
+    {
+        if (&op != this)
+        {
+         	// Projector stuff (is this necessary in C++?)
+        	data = op.data;
+        	ori_size = op.ori_size;
+        	pad_size = op.pad_size;
+        	r_max = op.r_max;
+        	r_min_nn = op.r_min_nn;
+        	interpolator = op.interpolator;
+        	padding_factor = op.padding_factor;
+        	ref_dim = op.ref_dim;
+         	// BackProjector stuff
+        	weight = op.weight;
+        	tab_ftblob = op.tab_ftblob;
+        	SL = op.SL;
+        }
+        return *this;
+    }
+
+    /** Destructor
+	  *
+	  * Clears everything
+	  *
+	  * @code
+	  * FourierInterpolator fourint;
+	  * @endcode
+	  */
+	~BackProjector()
+	{
+		clear();
+	}
+
+	void clear()
+	{
+		weight.clear();
+		Projector::clear();
+	}
+
+	// Initialise data and weight arrays to the given size and set all values to zero
+	void initialiseDataAndWeight(int current_size = -1);
+
+	// Initialise data and weight arrays to the given size and set all values to zero
+	void initZeros(int current_size = -1);
+
+	/*
+	* Set a 2D Fourier Transform back into the 2D or 3D data array
+	* Depending on the dimension of the map, this will be a backprojection or a rotation operation
+	*/
+	void set2DFourierTransform(const MultidimArray<Complex > &img_in,
+							   const Matrix2D<double> &A, bool inv,
+						       const MultidimArray<double> *Mweight = NULL)
+	{
+		// Back-rotation of a 3D Fourier Transform
+		switch (ref_dim)
+		{
+		case 2:
+			backrotate2D(img_in, A, inv, Mweight);
+			break;
+		case 3:
+			backproject(img_in, A, inv, Mweight);
+			break;
+		default:
+			REPORT_ERROR("Backprojector::set2DSlice%%ERROR: Dimension of the data array should be 2 or 3");
+		}
+	}
+
+	/*
+	* Set an in-plane rotated version of the 2D map into the data array (mere interpolation)
+	* If a exp_Mweight is given, rather than adding 1 to all relevant pixels in the weight array, we use exp_Mweight
+	*/
+	void backrotate2D(const MultidimArray<Complex > &img_in,
+			          const Matrix2D<double> &A, bool inv,
+			          const MultidimArray<double> *Mweight = NULL);
+
+	/*
+	* Set a 2D slice in the 3D map (backward projection)
+	* If a exp_Mweight is given, rather than adding 1 to all relevant pixels in the weight array, we use exp_Mweight
+	*/
+	void backproject(const MultidimArray<Complex > &img_in,
+			         const Matrix2D<double> &A, bool inv,
+			         const MultidimArray<double> *Mweight = NULL);
+
+	/*
+	 * Get only the lowest resolution components from the data and weight array
+	 * (to be joined together for two independent halves in order to force convergence in the same orientation)
+	 */
+	void getLowResDataAndWeight(MultidimArray<Complex > &lowres_data, MultidimArray<double> &lowres_weight,
+			int lowres_r_max);
+
+	/*
+	 * Set only the lowest resolution components from the data and weight array
+	 * (to be joined together for two independent halves in order to force convergence in the same orientation)
+	 */
+	void setLowResDataAndWeight(MultidimArray<Complex > &lowres_data, MultidimArray<double> &lowres_weight,
+			int lowres_r_max);
+
+	/*
+	 *  Get complex array at the original size as the straightforward average
+	 *  padding_factor*padding_factor*padding_factor voxels
+	 *  This will then be used for FSC calculation between two random halves
+	 */
+	void getDownsampledAverage(MultidimArray<Complex > &avg);
+
+	/*
+	 * From two of the straightforward downsampled averages, calculate an FSC curve
+	 */
+	void calculateDownSampledFourierShellCorrelation(MultidimArray<Complex > &avg1,
+			                                         MultidimArray<Complex > &avg2,
+			                                         MultidimArray<double> &fsc);
+
+	/* Get the 3D reconstruction
+         * If do_map is true, 1 will be added to all weights
+         * alpha will contain the noise-reduction spectrum
+	*/
+	void reconstruct(MultidimArray<double> &vol_out,
+                     int max_iter_preweight,
+                     bool do_map,
+                     double tau2_fudge,
+                     MultidimArray<double> &tau2,
+                     MultidimArray<double> &sigma2,
+                     MultidimArray<double> &evidence_vs_prior,
+                     MultidimArray<double> fsc,
+                     double normalise = 1.,
+                     bool update_tau2_with_fsc = false,
+                     bool is_whole_instead_of_half = false,
+                     int nr_threads = 1,
+                     int minres_map = -1);
+
+	/* Enforce hermitian symmetry on data and on weight (all points in the x==0 plane)
+	* Because the interpolations are numerical, hermitian symmetry may be broken.
+	* Repairing it here gives like a 2-fold averaging correction for interpolation errors...
+    */
+	void enforceHermitianSymmetry(MultidimArray<Complex > &mydata,
+								  MultidimArray<double> &myweight);
+
+	/* Applies the symmetry from the SymList object to the weight and the data array
+	 */
+	void symmetrise(MultidimArray<Complex > &mydata,
+					MultidimArray<double> &myweight, int my_rmax2);
+
+   /* Convolute in Fourier-space with the blob by multiplication in real-space
+	 * Note the convlution is done on the complex array inside the transformer object!!
+	 */
+	void convoluteBlobRealSpace(FourierTransformer &transformer, bool do_mask = false);
+
+	/* Calculate the inverse FFT of Fin and windows the result to ori_size
+	 * Also pass the transformer, to prevent making and clearing a new one before clearing the one in reconstruct()
+	 */
+	void windowToOridimRealSpace(FourierTransformer &transformer, MultidimArray<Complex > &Fin, MultidimArray<double> &Mout, int nr_threads = 1);
+
+   /*
+	* Go from the Projector-centered fourier transform back to FFTW-uncentered one
+	*/
+   template <typename T>
+   void decenter(MultidimArray<T> &Min, MultidimArray<T> &Mout, int my_rmax2)
+   {
+
+	   // Mout should already have the right size
+	   // Initialize to zero
+	   Mout.initZeros();
+	   FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Mout)
+	   {
+		   if (kp*kp + ip*ip + jp*jp <= my_rmax2)
+			   DIRECT_A3D_ELEM(Mout, k, i, j) = A3D_ELEM(Min, kp, ip, jp);
+	   }
+   }
+
+};
+
+#endif /* BACKPROJECTOR_H_ */
diff --git a/src/complex.cpp b/src/complex.cpp
new file mode 100644
index 0000000..1421e89
--- /dev/null
+++ b/src/complex.cpp
@@ -0,0 +1,164 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/complex.h"
+
+// Constructor with two arguments
+Complex::Complex(double _r, double _i)
+{
+    real = _r;
+    imag = _i;
+}
+
+Complex Complex::operator+ (Complex &op)
+{
+    return Complex(real + op.real, imag + op.imag);
+}
+
+void Complex::operator+= (Complex &op)
+{
+	real += op.real;
+	imag += op.imag;
+}
+
+Complex Complex::operator- (Complex &op)
+{
+    return Complex(real - op.real, imag - op.imag);
+}
+void Complex::operator-= (Complex &op)
+{
+	real -= op.real;
+	imag -= op.imag;
+}
+
+Complex Complex::operator* (Complex &op)
+{
+    return Complex((real * op.real) - (imag * op.imag), (real * op.imag) + (imag * op.real));
+}
+
+Complex Complex::operator* (double op)
+{
+    return Complex(real*op, imag*op);
+}
+
+void Complex::operator*= (double op)
+{
+	real *= op;
+	imag *= op;
+}
+
+Complex Complex::operator/(double op)
+{
+    return Complex(real/op, imag/op);
+}
+
+Complex Complex::operator/(Complex &op)
+{
+    double cd = op.norm();
+    double realval = real*op.real + imag*op.imag;
+    double imagval = imag*op.real - real*op.imag;
+	return Complex(realval/cd, imagval/cd);
+}
+
+void Complex::operator/=(double op)
+{
+	real /= op;
+	imag /= op;
+}
+
+
+Complex operator+(const Complex& lhs, const Complex& rhs)
+{
+	return Complex(lhs.real + rhs.real, lhs.imag + rhs.imag);
+}
+
+Complex operator-(const Complex& lhs, const Complex& rhs)
+{
+	return Complex(lhs.real - rhs.real, lhs.imag - rhs.imag);
+
+}
+
+Complex operator*(const Complex& lhs, const Complex& rhs)
+{
+	return Complex((lhs.real * rhs.real) - (lhs.imag * rhs.imag), (lhs.real * rhs.imag) + (lhs.imag * rhs.real));
+}
+
+Complex operator*(const Complex& lhs, const double& val)
+{
+	return Complex(lhs.real * val , lhs.imag * val);
+}
+
+Complex operator*(const double& val, const Complex& rhs)
+{
+	return Complex(rhs.real * val , rhs.imag * val);
+}
+
+Complex operator/(const Complex& lhs, const double& val)
+{
+	return Complex(lhs.real / val , lhs.imag / val);
+}
+
+void operator+=(Complex& lhs, const Complex& rhs)
+{
+	lhs.real += rhs.real;
+	lhs.imag += rhs.imag;
+}
+void operator-=(Complex& lhs, const Complex& rhs)
+{
+	lhs.real -= rhs.real;
+	lhs.imag -= rhs.imag;
+}
+
+Complex Complex::conj()
+{
+    return Complex(real, -imag);
+}
+Complex conj(const Complex& op)
+{
+	return Complex(op.real, -op.imag);
+}
+
+
+double Complex::abs()
+{
+    return sqrt(real*real + imag*imag);
+}
+double abs(const Complex& op)
+{
+	return sqrt(op.real*op.real + op.imag*op.imag);
+}
+
+double Complex::norm()
+{
+    return real*real + imag*imag;
+}
+double norm(const Complex& op)
+{
+	return op.real*op.real + op.imag*op.imag;
+}
+
+double Complex::arg()
+{
+    return atan2(imag, real);
+}
+
+double arg(const Complex& op)
+{
+	return atan2(op.imag, op.real);
+}
diff --git a/src/complex.h b/src/complex.h
new file mode 100644
index 0000000..2c2197e
--- /dev/null
+++ b/src/complex.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#ifndef COMPLEX_H_
+#define COMPLEX_H_
+#include <iostream>
+#include <cmath>
+
+class Complex
+{
+
+	public:
+
+	double real;
+	double imag;
+
+    // Constructor
+	Complex(double _r = 0.0, double _i = 0.0);
+
+    Complex operator+(Complex &op);
+    void operator+=(Complex &op);
+
+    Complex operator-(Complex &op);
+    void operator-=(Complex &op);
+
+    Complex operator*(Complex &op);
+
+    void operator*=(double op);
+
+    Complex operator*(double op);
+
+    Complex operator/(Complex &op);
+
+    Complex operator/(double op);
+
+    void operator/=(double op);
+
+    // Complex conjugated
+    Complex conj();
+
+    // Abs value: sqrt(real*real+imag*imag)
+    double abs();
+
+    // Norm value: real*real+imag*imag
+    double norm();
+
+    // Phase angle: atan2(imag,real)
+    double arg();
+
+
+};
+
+Complex conj(const Complex& op);
+double abs(const Complex& op);
+double norm(const Complex& op);
+double arg(const Complex& op);
+
+Complex operator+(const Complex& lhs, const Complex& rhs);
+Complex operator-(const Complex& lhs, const Complex& rhs);
+Complex operator*(const Complex& lhs, const Complex& rhs);
+Complex operator*(const Complex& lhs, const double& val);
+Complex operator*(const double& val, const Complex& rhs);
+Complex operator/(const Complex& lhs, const double& val);
+
+void operator+=(Complex& lhs, const Complex& rhs);
+void operator-=(Complex& lhs, const Complex& rhs);
+
+#endif
diff --git a/src/ctf.cpp b/src/ctf.cpp
new file mode 100644
index 0000000..0f3bb68
--- /dev/null
+++ b/src/ctf.cpp
@@ -0,0 +1,203 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include "src/ctf.h"
+#include "src/args.h"
+#include "src/fftw.h"
+#include "src/metadata_table.h"
+
+/* Read -------------------------------------------------------------------- */
+void CTF::read(MetaDataTable &MD1, MetaDataTable &MD2, long int objectID)
+{
+
+	if (!MD1.getValue(EMDL_CTF_VOLTAGE, kV, objectID))
+		if (!MD2.getValue(EMDL_CTF_VOLTAGE, kV, objectID))
+			kV=200;
+
+	if (!MD1.getValue(EMDL_CTF_DEFOCUSU, DeltafU, objectID))
+		if (!MD2.getValue(EMDL_CTF_DEFOCUSU, DeltafU, objectID))
+			DeltafU=0;
+
+	if (!MD1.getValue(EMDL_CTF_DEFOCUSV, DeltafV, objectID))
+		if (!MD2.getValue(EMDL_CTF_DEFOCUSV, DeltafV, objectID))
+			DeltafV=DeltafU;
+
+	if (!MD1.getValue(EMDL_CTF_DEFOCUS_ANGLE, azimuthal_angle, objectID))
+		if (!MD2.getValue(EMDL_CTF_DEFOCUS_ANGLE, azimuthal_angle, objectID))
+			azimuthal_angle=0;
+
+	if (!MD1.getValue(EMDL_CTF_CS, Cs, objectID))
+		if (!MD2.getValue(EMDL_CTF_CS, Cs, objectID))
+			Cs=0;
+
+	if (!MD1.getValue(EMDL_CTF_BFACTOR, Bfac, objectID))
+		if (!MD2.getValue(EMDL_CTF_BFACTOR, Bfac, objectID))
+			Bfac=0;
+
+	if (!MD1.getValue(EMDL_CTF_SCALEFACTOR, scale, objectID))
+		if (!MD2.getValue(EMDL_CTF_SCALEFACTOR, scale, objectID))
+			scale=1;
+
+	if (!MD1.getValue(EMDL_CTF_Q0, Q0, objectID))
+		if (!MD2.getValue(EMDL_CTF_Q0, Q0, objectID))
+			Q0=0;
+
+	initialise();
+}
+void CTF::setValues(double _defU, double _defV, double _defAng, double _voltage,
+		double _Cs, double _Q0, double _Bfac, double _scale)
+{
+	kV              = _voltage;
+	DeltafU         = _defU;
+	DeltafV         = _defV;
+	azimuthal_angle = _defAng;
+	Cs              = _Cs;
+	Bfac            = _Bfac;
+	scale           = _scale;
+	Q0              = _Q0;
+
+	initialise();
+}
+/* Read from 1 MetaDataTable ----------------------------------------------- */
+void CTF::read(MetaDataTable &MD)
+{
+	MetaDataTable MDempty;
+	MDempty.addObject(); // add one empty object
+	read(MD, MDempty);
+}
+
+/* Write ------------------------------------------------------------------- */
+void CTF::write(std::ostream &out)
+{
+    MetaDataTable MD;
+    MD.addObject();
+    MD.setValue(EMDL_CTF_VOLTAGE, kV);
+    MD.setValue(EMDL_CTF_DEFOCUSU, DeltafU);
+    MD.setValue(EMDL_CTF_DEFOCUSV, DeltafV);
+    MD.setValue(EMDL_CTF_DEFOCUS_ANGLE, azimuthal_angle);
+    MD.setValue(EMDL_CTF_CS, Cs);
+    MD.setValue(EMDL_CTF_BFACTOR, Bfac);
+    MD.setValue(EMDL_CTF_SCALEFACTOR, scale);
+    MD.setValue(EMDL_CTF_Q0, Q0);
+    MD.write(out);
+}
+
+/* Default values ---------------------------------------------------------- */
+void CTF::clear()
+{
+    kV = 200;
+    DeltafU = DeltafV = azimuthal_angle = 0;
+    Cs = Bfac = 0;
+    Q0 = 0;
+    scale = 1;
+}
+
+/* Initialise the CTF ------------------------------------------------------ */
+void CTF::initialise()
+{
+
+	// Change units
+    double local_Cs = Cs * 1e7;
+    double local_kV = kV * 1e3;
+    rad_azimuth = DEG2RAD(azimuthal_angle);
+
+    // Average focus and deviation
+    defocus_average   = -(DeltafU + DeltafV) * 0.5;
+    defocus_deviation = -(DeltafU - DeltafV) * 0.5;
+
+    // lambda=h/sqrt(2*m*e*kV)
+    //    h: Planck constant
+    //    m: electron mass
+    //    e: electron charge
+    // lambda=0.387832/sqrt(kV*(1.+0.000978466*kV)); // Hewz: Angstroms
+    // lambda=h/sqrt(2*m*e*kV)
+    lambda=12.2643247 / sqrt(local_kV * (1. + local_kV * 0.978466e-6)); // See http://en.wikipedia.org/wiki/Electron_diffraction
+
+    // Helpful constants
+    // ICE: X(u)=-PI/2*deltaf(u)*lambda*u^2+PI/2*Cs*lambda^3*u^4
+    //          = K1*deltaf(u)*u^2         +K2*u^4
+    K1 = PI / 2 * 2 * lambda;
+    K2 = PI / 2 * local_Cs * lambda * lambda * lambda;
+    K3 = sqrt(1-Q0*Q0);
+    K4 = -Bfac / 4.;
+
+    if (Q0 < 0. || Q0 > 1.)
+    	REPORT_ERROR("CTF::initialise ERROR: AmplitudeContrast Q0 cannot be smaller than zero or larger than one!");
+
+    if (ABS(DeltafU) < 1e-6 && ABS(DeltafV) < 1e-6 && ABS(Q0) < 1e-6 && ABS(Cs) < 1e-6)
+    	REPORT_ERROR("CTF::initialise: ERROR: CTF initialises to all-zero values. Was a correct STAR file provided?");
+
+}
+
+/* Generate a complete CTF Image ------------------------------------------------------ */
+void CTF::getFftwImage(MultidimArray<double> &result, int orixdim, int oriydim, double angpix,
+		    		bool do_abs, bool do_only_flip_phases, bool do_intact_until_first_peak, bool do_damping)
+{
+
+	double xs = (double)orixdim * angpix;
+	double ys = (double)oriydim * angpix;
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM2D(result)
+	{
+		double x = (double)jp / xs;
+		double y = (double)ip / ys;
+		DIRECT_A2D_ELEM(result, i, j) = getCTF(x, y, do_abs, do_only_flip_phases, do_intact_until_first_peak, do_damping);
+	}
+}
+
+void CTF::getCenteredImage(MultidimArray<double> &result, double Tm,
+		    		bool do_abs, bool do_only_flip_phases, bool do_intact_until_first_peak, bool do_damping)
+{
+	result.setXmippOrigin();
+	double xs = (double)XSIZE(result) * Tm;
+	double ys = (double)YSIZE(result) * Tm;
+
+	FOR_ALL_ELEMENTS_IN_ARRAY2D(result)
+	{
+		double x = (double)j / xs;
+		double y = (double)i / ys;
+		A2D_ELEM(result, i, j) = getCTF(x, y, do_abs, do_only_flip_phases, do_intact_until_first_peak, do_damping);
+	}
+
+}
+
diff --git a/src/ctf.h b/src/ctf.h
new file mode 100644
index 0000000..ce566df
--- /dev/null
+++ b/src/ctf.h
@@ -0,0 +1,217 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef _CTF_HH
+#define _CTF_HH
+
+#include "src/multidim_array.h"
+#include "src/metadata_table.h"
+#include <map>
+
+class CTF
+{
+protected:
+
+    // Different constants
+    double K1;
+    double K2;
+    double K3;
+    double K4;
+
+    // Azimuthal angle in radians
+    double rad_azimuth;
+
+    // defocus_average = (defocus_u + defocus_v)/2
+    double defocus_average;
+
+    // defocus_deviation = (defocus_u - defocus_v)/2
+    double defocus_deviation;
+
+public:
+
+    /// Accelerating Voltage (in KiloVolts)
+    double kV;
+
+    /// Defocus in U (in Angstroms). Positive values are underfocused
+    double DeltafU;
+
+    /// Defocus in V (in Angstroms). Postive values are underfocused
+    double DeltafV;
+
+    /// Azimuthal angle (between X and U) in degrees
+    double azimuthal_angle;
+
+    // Electron wavelength (Amstrongs)
+    double lambda;
+
+    // Radius of the aperture (in micras)
+    // double aperture;
+    /// Spherical aberration (in milimeters). Typical value 5.6
+    double Cs;
+
+    /// Chromatic aberration (in milimeters). Typical value 2
+    double Ca;
+
+    /** Mean energy loss (eV) due to interaction with sample.
+        Typical value 1*/
+    double espr;
+
+    /// Objective lens stability (deltaI/I) (ppm). Typical value 1
+    double ispr;
+
+    /// Convergence cone semiangle (in mrad). Typical value 0.5
+    double alpha;
+
+    /// Longitudinal mechanical displacement (Angstrom). Typical value 100
+    double DeltaF;
+
+    /// Transversal mechanical displacement (Angstrom). Typical value 3
+    double DeltaR;
+
+    /// Amplitude contrast. Typical values 0.07 for cryo, 0.2 for negative stain
+    double Q0;
+
+    // B-factor fall-off
+    double Bfac;
+
+    // Overall scale-factor of CTF
+    double scale;
+
+    /** Empty constructor. */
+    CTF() { clear(); }
+
+    /** Read CTF parameters from MetaDataTables MD1 and MD2
+     * If a parameter is not found in MD1 it is tried to be read from MD2
+     * Only if it is also not present in the second then a default value is used
+     * This is useful if micrograph-specific parameters are stored in a separate MD from the image-specific parameters
+     */
+    void read(MetaDataTable &MD1, MetaDataTable &MD2, long int objectID = -1);
+
+    /** Just set all values explicitly */
+    void setValues(double _defU, double _defV, double _defAng,
+    		double _voltage, double _Cs, double _Q0, double _Bfac, double _scale = 1.);
+
+    /** Read from a single MetaDataTable */
+    void read(MetaDataTable &MD);
+
+    /** Write to output. */
+    void write(std::ostream &out);
+
+    /// Clear.
+    void clear();
+
+    /// Set up the CTF object, read parameters from MetaDataTables with micrograph and particle information
+    /// If no MDmic is provided or it does not contain certain parameters, these parameters are tried to be read from MDimg
+    void initialise();
+
+    /// Compute CTF at (U,V). Continuous frequencies
+    inline double getCTF(double X, double Y,
+    		bool do_abs = false, bool do_only_flip_phases = false, bool do_intact_until_first_peak = false, bool do_damping = true) const
+    {
+        double u2 = X * X + Y * Y;
+        double u = sqrt(u2);
+        double u4 = u2 * u2;
+        // if (u2>=ua2) return 0;
+        double deltaf = getDeltaF(X, Y);
+        double argument = K1 * deltaf * u2 + K2 * u4;
+        double retval;
+        if (do_intact_until_first_peak && ABS(argument) < PI/2.)
+        {
+        	retval = 1.;
+        }
+        else
+        {
+        	double sine_part,cosine_part;
+            retval = -(K3*sin(argument) - Q0*cos(argument)); // Q0 should be positive
+        }
+        if (do_damping)
+        {
+        	double E = exp(K4 * u2); // B-factor decay (K4 = -Bfac/4);
+        	retval *= E;
+        }
+        if (do_abs)
+        {
+        	retval = ABS(retval);
+        }
+        else if (do_only_flip_phases)
+        {
+        	retval = (retval < 0.) ? -1. : 1.;
+        }
+        return scale * retval;
+    }
+
+    /// Compute Deltaf at a given direction
+    inline double getDeltaF(double X, double Y) const
+    {
+        if (ABS(X) < XMIPP_EQUAL_ACCURACY &&
+            ABS(Y) < XMIPP_EQUAL_ACCURACY)
+            return 0;
+
+        double ellipsoid_ang = atan2(Y, X) - rad_azimuth;
+        /*
+        * For a derivation of this formulae confer
+        * Principles of Electron Optics page 1380
+        * in particular term defocus and twofold axial astigmatism
+        * take into account that a1 and a2 are the coefficient
+        * of the zernike polynomials difference of defocus at 0
+        * and at 45 degrees. In this case a2=0
+        */
+        double cos_ellipsoid_ang_2 = cos(2*ellipsoid_ang);
+        return (defocus_average + defocus_deviation*cos_ellipsoid_ang_2);
+
+    }
+
+    /// Generate (Fourier-space, i.e. FFTW format) image with all CTF values.
+    /// The dimensions of the result array should have been set correctly already
+    void getFftwImage(MultidimArray < double > &result, int orixdim, int oriydim, double angpix,
+    		bool do_abs = false, bool do_only_flip_phases = false, bool do_intact_until_first_peak = false, bool do_damping = true);
+
+    /// Generate a centered image (with hermitian symmetry)
+    void getCenteredImage(MultidimArray < double > &result, double angpix,
+    		bool do_abs = false, bool do_only_flip_phases = false, bool do_intact_until_first_peak = false, bool do_damping = true);
+
+
+};
+//@}
+#endif
diff --git a/src/ctffind_runner.cpp b/src/ctffind_runner.cpp
new file mode 100644
index 0000000..2639d83
--- /dev/null
+++ b/src/ctffind_runner.cpp
@@ -0,0 +1,307 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/ctffind_runner.h"
+
+void CtffindRunner::read(int argc, char **argv, int rank)
+{
+
+	parser.setCommandLine(argc, argv);
+	int gen_section = parser.addSection("General options");
+	int ctf_section = parser.addSection("CTF estimation");
+	fn_in = parser.getOption("--i", "STAR file with all input micrographs, or a unix wildcard to all micrograph files, e.g. \"mics/*.mrc\"");
+	fn_out = parser.getOption("--o", "Name for the STAR file with CTF params for each micrograph", "micrographs_ctf.star");
+	do_only_join_results = parser.checkOption("--only_make_star", "Don't run CTFFIND3, only join the logfile results in a STAR file");
+	continue_old = parser.checkOption("--only_do_unfinished", "Only run CTFFIND3 for those micrographs for which there is not yet a logfile with Final values.");
+
+	// Use a smaller squared part of the micrograph to estimate CTF (e.g. to avoid film labels...)
+	ctf_win =  textToInteger(parser.getOption("--ctfWin", "Size (in pixels) of a centered, squared window to use for CTF-estimation", "-1"));
+
+	fn_ctffind3_exe = parser.getOption("--ctffind3_exe","Location of ctffind3 executable (or through RLN_CTFFIND3_EXECUTABLE environment variable)","");
+
+	// First parameter line in CTFFIND
+	Cs = textToFloat(parser.getOption("--CS", "Spherical Aberration (mm) ","2.0"));
+	Voltage = textToFloat(parser.getOption("--HT", "Voltage (kV)","300"));
+	AmplitudeConstrast = textToFloat(parser.getOption("--AmpCnst", "Amplitude constrast", "0.1"));
+	Magnification = textToFloat(parser.getOption("--XMAG", "Magnification", "60000"));
+	PixelSize = textToFloat(parser.getOption("--DStep", "Detector pixel size (um)", "14"));
+	// Second parameter line in CTFFIND
+	box_size = textToFloat(parser.getOption("--Box", "Size of the boxes to calculate FFTs", "512"));
+	resol_min = textToFloat(parser.getOption("--ResMin", "Minimum resolution (in A) to include in calculations", "100"));
+	resol_max = textToFloat(parser.getOption("--ResMax", "Maximum resolution (in A) to include in calculations", "7"));
+	min_defocus = textToFloat(parser.getOption("--dFMin", "Minimum defocus value (in A) to search", "10000"));
+	max_defocus = textToFloat(parser.getOption("--dFMax", "Maximum defocus value (in A) to search", "50000"));
+	step_defocus = textToFloat(parser.getOption("--FStep", "defocus step size (in A) for search", "250"));
+	amount_astigmatism  = textToFloat(parser.getOption("--dAst", "amount of astigmatism (in A)", "0"));
+
+	// Initialise verb for non-parallel execution
+	verb = 1;
+
+	// Check for errors in the command-line option
+	if (parser.checkForErrors())
+		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+}
+
+void CtffindRunner::usage()
+{
+	parser.writeUsage(std::cerr);
+}
+
+void CtffindRunner::initialise()
+{
+
+	// Get the CTFFIND3 executable
+	if (fn_ctffind3_exe == "")
+	{
+		char * penv;
+		penv = getenv ("RLN_CTFFIND3_EXECUTABLE");
+		if (penv!=NULL)
+			fn_ctffind3_exe = (std::string)penv;
+	}
+
+	// Set up which micrographs to estimate CTFs from
+	if (fn_in.isStarFile())
+	{
+		MetaDataTable MDin;
+		MDin.read(fn_in);
+		fn_micrographs.clear();
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDin)
+		{
+			FileName fn_mic;
+			MDin.getValue(EMDL_MICROGRAPH_NAME, fn_mic);
+			fn_micrographs.push_back(fn_mic);
+		}
+	}
+	else
+	{
+		fn_in.globFiles(fn_micrographs);
+	}
+
+	// If we're continuing an old run, see which micrographs have not been finished yet...
+	if (continue_old)
+	{
+		std::vector<FileName> fns_todo;
+		for (long int imic = 0; imic < fn_micrographs.size(); imic++)
+		{
+			FileName fn_microot = fn_micrographs[imic].without(".mrc");
+			double defU, defV, defAng, CC, HT, CS, AmpCnst, XMAG, DStep;
+			if (!getCtffind3Results(fn_microot, defU, defV, defAng, CC,
+					HT, CS, AmpCnst, XMAG, DStep, false)) // false: dont die if not found Final values
+				fns_todo.push_back(fn_micrographs[imic]);
+		}
+
+		fn_micrographs = fns_todo;
+
+	}
+
+
+	if (verb > 0)
+	{
+		std::cout << " Using CTFFINDs executable in: " << fn_ctffind3_exe << std::endl;
+		std::cout << " to estimate CTF parameters for the following micrographs: " << std::endl;
+		if (continue_old)
+			std::cout << " (skipping all micrographs for which a logfile with Final values already exists " << std::endl;
+		for(unsigned  int  i = 0; i < fn_micrographs.size(); ++i)
+			std::cout << "  * " << fn_micrographs[i] << std::endl;
+	}
+}
+
+void CtffindRunner::run()
+{
+
+	if (!do_only_join_results)
+	{
+		int barstep;
+		if (verb > 0)
+		{
+			std::cout << " Estimating CTF parameters using Niko Grigorieff's CTFFIND3 ..." << std::endl;
+			init_progress_bar(fn_micrographs.size());
+			barstep = XMIPP_MAX(1, fn_micrographs.size() / 60);
+		}
+
+		for (long int imic = 0; imic < fn_micrographs.size(); imic++)
+		{
+			if (verb > 0 && imic % barstep == 0)
+				progress_bar(imic);
+
+			executeCtffind3(fn_micrographs[imic]);
+		}
+
+		if (verb > 0)
+			progress_bar(fn_micrographs.size());
+	}
+
+	joinCtffindResults();
+
+}
+
+void CtffindRunner::joinCtffindResults()
+{
+	MetaDataTable MDctf;
+	for (long int imic = 0; imic < fn_micrographs.size(); imic++)
+    {
+		FileName fn_microot = fn_micrographs[imic].without(".mrc");
+		double defU, defV, defAng, CC, HT, CS, AmpCnst, XMAG, DStep;
+		bool has_this_ctf = getCtffind3Results(fn_microot, defU, defV, defAng, CC,
+				HT, CS, AmpCnst, XMAG, DStep);
+
+		if (!has_this_ctf)
+			REPORT_ERROR("CtffindRunner::joinCtffind3Results ERROR; cannot get CTF values for");
+
+		FileName fn_ctf = fn_microot + ".ctf:mrc";
+		MDctf.addObject();
+		MDctf.setValue(EMDL_MICROGRAPH_NAME, fn_micrographs[imic]);
+	    MDctf.setValue(EMDL_CTF_IMAGE, fn_ctf);
+		MDctf.setValue(EMDL_CTF_DEFOCUSU, defU);
+	    MDctf.setValue(EMDL_CTF_DEFOCUSV, defV);
+	    MDctf.setValue(EMDL_CTF_DEFOCUS_ANGLE, defAng);
+	    MDctf.setValue(EMDL_CTF_VOLTAGE, HT);
+	    MDctf.setValue(EMDL_CTF_CS, CS);
+	    MDctf.setValue(EMDL_CTF_Q0, AmpCnst);
+	    MDctf.setValue(EMDL_CTF_MAGNIFICATION, XMAG);
+	    MDctf.setValue(EMDL_CTF_DETECTOR_PIXEL_SIZE, DStep);
+	    MDctf.setValue(EMDL_CTF_FOM, CC);
+    }
+	MDctf.write(fn_out);
+}
+
+void CtffindRunner::executeCtffind3(FileName fn_mic)
+{
+
+	FileName fn_root = fn_mic.withoutExtension();
+	FileName fn_script = fn_root + "_ctffind3.com";
+	FileName fn_log = fn_root + "_ctffind3.log";
+	FileName fn_ctf = fn_root + ".ctf";
+    FileName fn_mic_win;
+
+	std::ofstream  fh;
+	fh.open((fn_script).c_str(), std::ios::out);
+	if (!fh)
+	 REPORT_ERROR( (std::string)"CtffindRunner::execute_ctffind3 cannot create file: " + fn_script);
+
+        // If given, then put a square window of ctf_win on the micrograph for CTF estimation
+        if (ctf_win > 0)
+        {
+            // Window micrograph to a smaller, squared sub-micrograph to estimate CTF on
+            fn_mic_win = fn_root + "_win.mrc";
+            // Read in micrograph, window and write out again
+            Image<double> I;
+            I.read(fn_mic);
+            I().setXmippOrigin();
+            I().window(FIRST_XMIPP_INDEX(ctf_win), FIRST_XMIPP_INDEX(ctf_win), LAST_XMIPP_INDEX(ctf_win), LAST_XMIPP_INDEX(ctf_win));
+            // Calculate mean, stddev, min and max
+            double avg, stddev, minval, maxval;
+            I().computeStats(avg, stddev, minval, maxval);
+            I.MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN, minval);
+            I.MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX, maxval);
+            I.MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG, avg);
+            I.MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV, stddev);
+            I.write(fn_mic_win);
+        }
+        else
+            fn_mic_win = fn_mic;
+
+	// Write script to run x3dna
+	fh << "#!/usr/bin/env csh"<<std::endl;
+	fh << fn_ctffind3_exe << " > " << fn_log << " << EOF"<<std::endl;
+	fh << fn_mic_win << std::endl;
+	fh << fn_ctf << std::endl;
+	// CS[mm], HT[kV], AmpCnst, XMAG, DStep[um]
+	fh << Cs << ", " << Voltage << ", " << AmplitudeConstrast << ", " << Magnification << ", " << PixelSize<< std::endl;
+	// Box, ResMin[A], ResMax[A], dFMin[A], dFMax[A], FStep[A], dAst[A]
+	fh << box_size << ", " << resol_min << ", " << resol_max << ", " << min_defocus << ", " << max_defocus << ", " << step_defocus << ", " << amount_astigmatism << std::endl;
+	fh <<"EOF"<<std::endl;
+	fh.close();
+
+	// Execute ctffind3
+	if (!system(NULL))
+	 REPORT_ERROR("There is a problem with the system call to run ctffind3");
+	FileName fn_cmnd = "csh "+ fn_script;
+	system ( fn_cmnd.c_str() );
+
+	// Remove windowed file again
+	if (ctf_win > 0)
+	{
+		if( remove( fn_mic_win.c_str() ) != 0 )
+			REPORT_ERROR( "Error deleting windowed micrograph file..." );
+	}
+
+}
+
+bool getCtffind3Results(FileName fn_microot, double &defU, double &defV, double &defAng, double &CC,
+		double &HT, double &CS, double &AmpCnst, double &XMAG, double &DStep, bool die_if_not_found)
+{
+
+	FileName fn_log = fn_microot + "_ctffind3.log";
+	std::ifstream in(fn_log.data(), std::ios_base::in);
+    if (in.fail())
+    	return false;
+
+    // Start reading the ifstream at the top
+    in.seekg(0);
+
+    // Proceed until the next "Final values" statement
+    // The loop statement may be necessary for data blocks that have a list AND a table inside them
+    bool Final_is_found = false;
+    bool Cs_is_found = false;
+    std::string line;
+    std::vector<std::string> words;
+    while (getline(in, line, '\n'))
+    {
+        // Find data_ lines
+
+    	 if (line.find("CS[mm], HT[kV], AmpCnst, XMAG, DStep[um]") != std::string::npos)
+    	 {
+    		 Cs_is_found = true;
+    		 getline(in, line, '\n');
+    		 tokenize(line, words);
+    		 if (words.size() < 5)
+    			 REPORT_ERROR("ERROR: Unexpected number of words on data line with CS[mm], HT[kV], etc in " + fn_log);
+    		 CS = textToFloat(words[0]);
+    		 HT = textToFloat(words[1]);
+    		 AmpCnst = textToFloat(words[2]);
+    		 XMAG = textToFloat(words[3]);
+    		 DStep = textToFloat(words[4]);
+    	 }
+
+    	if (line.find("Final Values") != std::string::npos)
+        {
+        	Final_is_found = true;
+            tokenize(line, words);
+            if (words.size() < 6)
+            	REPORT_ERROR("ERROR: Unexpected number of words on Final values line in " + fn_log);
+            defU = textToFloat(words[0]);
+            defV = textToFloat(words[1]);
+            defAng = textToFloat(words[2]);
+            CC = textToFloat(words[3]);
+        }
+    }
+    if (!Cs_is_found && die_if_not_found)
+    	REPORT_ERROR("ERROR: cannot find line with Cs[mm], HT[kV], etc values in " + fn_log);
+    if (!Final_is_found && die_if_not_found)
+    	REPORT_ERROR("ERROR: cannot find line with Final values in " + fn_log);
+
+    in.close();
+
+    return Final_is_found;
+
+}
+
+
diff --git a/src/ctffind_runner.h b/src/ctffind_runner.h
new file mode 100644
index 0000000..eb55415
--- /dev/null
+++ b/src/ctffind_runner.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef CTFFIND_RUNNER_H_
+#define CTFFIND_RUNNER_H_
+
+#include  <glob.h>
+#include  <vector>
+#include  <string>
+#include  <stdlib.h>
+#include  <stdio.h>
+#include "src/metadata_table.h"
+#include "src/image.h"
+#include <src/time.h>
+
+class CtffindRunner
+{
+public:
+
+	// I/O Parser
+	IOParser parser;
+
+	// Verbosity
+	int verb;
+
+	// Output rootname
+	FileName fn_in, fn_out;
+
+	// Filenames of all the micrographs to estimate the CTF from
+	std::vector<FileName> fn_micrographs;
+
+	// Dimension of squared area of the micrograph to use for CTF estimation
+	int ctf_win;
+
+	// CTFFIND3 executable
+	FileName fn_ctffind3_exe;
+
+	// Continue an old run: only estimate CTF if logfile WITH Final Values line does not yet exist, otherwise skip the micrograph
+	bool continue_old;
+
+	////// CTFFIND3 parameters
+	// Size of the box to calculate FFTw
+	double box_size;
+
+	// Minimum and maximum resolution (in A) to be taken into account
+	double resol_min, resol_max;
+
+	// Defocus search parameters (in A, positive is underfocus)
+	double min_defocus, max_defocus, step_defocus;
+
+	// Amount of astigmatism (in A)
+	double amount_astigmatism;
+
+	// Voltage (kV)
+	double Voltage;
+
+	// Spherical aberration
+	double Cs;
+
+	// Amplitude contrast (e.g. 0.07)
+	double AmplitudeConstrast;
+
+	// Magnification
+	double Magnification;
+
+	// Detector pixel size (um)
+	double PixelSize;
+
+	// Flag to only join results into a star file
+	bool do_only_join_results;
+
+public:
+	// Read command line arguments
+	void read(int argc, char **argv, int rank = 0);
+
+	// Print usage instructions
+	void usage();
+
+	// Initialise some stuff after reading
+	void initialise();
+
+	// Execute all CTFFIND3 jobs to get CTF parameters
+	void run();
+
+	// Harvest all CTFFIND3 results into a single STAR file
+	void joinCtffindResults();
+
+	// Execute CTFFIND3 for a single micrograph
+	void executeCtffind3(FileName fn_mic);
+
+};
+
+// Get micrograph metadata
+bool getCtffind3Results(FileName fn_mic, double &defU, double &defV, double &defAng, double &CC,
+		double &HT, double &CS, double &AmpCnst, double &XMAG, double &DStep, bool die_if_not_found = true);
+
+
+#endif /* CTFFIND_RUNNER_H_ */
diff --git a/src/ctffind_runner_mpi.cpp b/src/ctffind_runner_mpi.cpp
new file mode 100644
index 0000000..4913e42
--- /dev/null
+++ b/src/ctffind_runner_mpi.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/ctffind_runner_mpi.h"
+
+void CtffindRunnerMpi::read(int argc, char **argv)
+{
+    // Define a new MpiNode
+    node = new MpiNode(argc, argv);
+
+    // First read in non-parallelisation-dependent variables
+    CtffindRunner::read(argc, argv);
+
+    // Don't put any output to screen for mpi slaves
+    verb = (node->isMaster()) ? 1 : 0;
+
+    // Possibly also read parallelisation-dependent variables here
+
+    // Print out MPI info
+	printMpiNodesMachineNames(*node);
+
+
+}
+void CtffindRunnerMpi::run()
+{
+
+	if (!do_only_join_results)
+	{
+		// Each node does part of the work
+		long int my_first_micrograph, my_last_micrograph, my_nr_micrographs;
+		divide_equally(fn_micrographs.size(), node->size, node->rank, my_first_micrograph, my_last_micrograph);
+		my_nr_micrographs = my_last_micrograph - my_first_micrograph + 1;
+
+		int barstep;
+		if (verb > 0)
+		{
+			std::cout << " Estimating CTF parameters using Niko Grigorieff's CTFFIND3 ..." << std::endl;
+			init_progress_bar(my_nr_micrographs);
+			barstep = XMIPP_MAX(1, my_nr_micrographs / 60);
+		}
+
+		for (long int imic = my_first_micrograph; imic <= my_last_micrograph; imic++)
+		{
+			if (verb > 0 && imic % barstep == 0)
+				progress_bar(imic);
+
+			executeCtffind3(fn_micrographs[imic]);
+		}
+		if (verb > 0)
+			progress_bar(my_nr_micrographs);
+	}
+
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	// Only the master writes the joined result file
+	if (node->isMaster())
+	{
+		joinCtffindResults();
+	}
+
+}
+
diff --git a/src/ctffind_runner_mpi.h b/src/ctffind_runner_mpi.h
new file mode 100644
index 0000000..e0356ce
--- /dev/null
+++ b/src/ctffind_runner_mpi.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef CTFFIND_RUNNER_MPI_H_
+#define CTFFIND_RUNNER_MPI_H_
+
+#include "src/mpi.h"
+#include "src/ctffind_runner.h"
+#include "src/parallel.h"
+
+class CtffindRunnerMpi: public CtffindRunner
+{
+private:
+	MpiNode *node;
+
+public:
+	/** Destructor, calls MPI_Finalize */
+    ~CtffindRunnerMpi()
+    {
+        delete node;
+    }
+
+    /** Read
+     * This could take care of mpi-parallelisation-dependent variables
+     */
+    void read(int argc, char **argv);
+
+    // Parallelized run function
+    void run();
+
+};
+
+#endif /* CTFFIND_RUNNER_MPI_H_ */
diff --git a/src/displayer.cpp b/src/displayer.cpp
new file mode 100644
index 0000000..b155974
--- /dev/null
+++ b/src/displayer.cpp
@@ -0,0 +1,1965 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include "src/displayer.h"
+//#define DEBUG
+
+/************************************************************************/
+void DisplayBox::draw()
+{
+	if (!img_data) return;
+
+	short xpos = x() + xoff;
+    short ypos = y() + yoff;
+
+    /* Ensure that the full window is redrawn */
+    //fl_push_clip(x(),y(),w(),h());
+
+    /* Redraw the whole image */
+    fl_draw_image((const uchar *)img_data, xpos, ypos, (short)xsize_data, (short)ysize_data, 1);
+    /* Draw a red rectangle around the particle if it is selected */
+    if (selected)
+        fl_color(FL_RED);
+    else
+    	fl_color(FL_BLACK);
+
+    fl_line_style(FL_SOLID, 2);
+    int x1 = xpos;
+    int y1 = ypos;
+    int x2 = xpos + xsize_data;
+    int y2 = ypos + ysize_data;
+    fl_line(x1, y1, x1, y2);
+    fl_line(x1, y2, x2, y2);
+    fl_line(x2, y2, x2, y1);
+    fl_line(x2, y1, x1, y1);
+
+    //fl_pop_clip();
+}
+
+void DisplayBox::setData(MultidimArray<double> &img, MetaDataContainer *MDCin, int _ipos,
+		double _minval, double _maxval, double _scale, bool do_relion_scale)
+{
+
+	scale = _scale;
+	minval = _minval;
+	maxval = _maxval;
+	ipos = _ipos;
+	selected = NOTSELECTED;
+
+	// Set its own MetaDataTable
+	MDimg.setIsList(true);
+	MDimg.addObject(MDCin);
+
+	// For volumes only show the central slice
+	if (ZSIZE(img) > 1)
+	{
+		MultidimArray<double> slice;
+		img.getSlice(ZSIZE(img)/2, slice);
+		img=slice;
+	}
+
+	// create array for the scaled image data
+	xsize_data = CEIL(XSIZE(img) * scale);
+	ysize_data = CEIL(YSIZE(img) * scale);
+	xoff = (xsize_data < w() ) ? (w() - xsize_data) / 2 : 0;
+	yoff = (ysize_data < h() ) ? (h() - ysize_data) / 2 : 0;
+	img_data = new char [xsize_data * ysize_data];
+	double range = maxval - minval;
+	double step = range / 255; // 8-bit scaling range from 0 to 255
+	double* old_ptr=NULL;
+    long int n;
+
+    // For micrographs use relion-scaling to avoid bias in down-sampled positions
+    // For multi-image viewers, do not use this scaling as it is slower...
+    if (do_relion_scale && ABS(scale - 1.0) > 0.01)
+    	selfScaleToSize(img, xsize_data, ysize_data);
+
+    // Use the same nearest-neighbor algorithm as in the copy function of Fl_Image...
+    if (ABS(scale - 1.0) > 0.01 && !do_relion_scale)
+    {
+    	int xmod   = XSIZE(img) % xsize_data;
+		int xstep  = XSIZE(img) / xsize_data;
+		int ymod   = YSIZE(img) % ysize_data;
+		int ystep  = YSIZE(img) / ysize_data;
+		int line_d = XSIZE(img);
+		int dx, dy, sy, xerr, yerr;
+
+		// scale the image using a nearest-neighbor algorithm...
+		for (dy = ysize_data, sy = 0, yerr = ysize_data, n = 0; dy > 0; dy --)
+		{
+			for (dx = xsize_data, xerr = xsize_data, old_ptr = img.data + sy * line_d; dx > 0; dx --, n++)
+			{
+				img_data[n] = (char)FLOOR((*old_ptr - minval) / step);
+				old_ptr += xstep;
+				xerr    -= xmod;
+				if (xerr <= 0)
+				{
+					xerr    += xsize_data;
+					old_ptr += 1;
+				}
+			}
+
+			sy   += ystep;
+			yerr -= ymod;
+			if (yerr <= 0)
+			{
+				yerr += ysize_data;
+				sy ++;
+			}
+		}
+
+    }
+    else
+    {
+    	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(img, n, old_ptr)
+		{
+    		img_data[n] = (char)FLOOR((*old_ptr - minval) / step);
+		}
+    }
+
+}
+
+
+
+bool DisplayBox::toggleSelect()
+{
+
+	selected = !selected;
+	redraw();
+	return selected;
+}
+
+bool DisplayBox::select()
+{
+
+	selected = true;
+	redraw();
+	return selected;
+}
+
+bool DisplayBox::unSelect()
+{
+
+	selected = NOTSELECTED;
+	redraw();
+	return selected;
+}
+
+int basisViewerWindow::fillCanvas(int viewer_type, MetaDataTable &MDin, EMDLabel display_label, bool _do_read_whole_stacks, bool _do_apply_orient,
+		double _minval, double _maxval, double _sigma_contrast, double _scale, double _ori_scale, int _ncol, bool _do_class,
+		MetaDataTable *_MDdata, int _nr_regroup, bool _is_data, MetaDataTable *_MDgroups)
+{
+    // Scroll bars
+    Fl_Scroll scroll(0, 0, w(), h());
+
+    // Pre-set the canvas to the correct size
+    FileName fn_img;
+    Image<double> img;
+    MDin.getValue(display_label, fn_img);
+	img.read(fn_img, false);
+	int nimgs = MDin.numberOfObjects();
+	if (viewer_type == MULTIVIEWER)
+	{
+		int xsize_canvas = _ncol * (CEIL(XSIZE(img())*_scale) + BOX_OFFSET);
+		int nrow = CEIL((double)nimgs/_ncol);
+		int ysize_canvas = nrow * (CEIL(YSIZE(img())*_scale) + BOX_OFFSET);
+		multiViewerCanvas canvas(0, 0, xsize_canvas, ysize_canvas);
+		canvas.SetScroll(&scroll);
+		canvas.do_read_whole_stacks = _do_read_whole_stacks;
+		canvas.is_data = _is_data;
+		canvas.ori_scale = _ori_scale;
+		canvas.display_label = display_label;
+		canvas.sigma_contrast = _sigma_contrast;
+		canvas.fill(MDin, display_label, _do_apply_orient, _minval, _maxval, _sigma_contrast, _scale, _ncol);
+		canvas.nr_regroups = _nr_regroup;
+		if (canvas.nr_regroups > 0)
+			canvas.MDgroups = _MDgroups;
+		if (_do_class)
+		{
+			canvas.do_class = true;
+			canvas.MDdata = _MDdata;
+		}
+		else
+		{
+			canvas.do_class = false;
+		}
+		resizable(*this);
+		show();
+		return Fl::run();
+	}
+	else if (viewer_type == SINGLEVIEWER)
+	{
+		if (nimgs>1)
+			REPORT_ERROR("ERROR: trying to launch a singleViewerCanvas with multiple images...");
+		int xsize_canvas = CEIL(XSIZE(img())*_scale);
+		int ysize_canvas = CEIL(YSIZE(img())*_scale);
+		singleViewerCanvas canvas(0, 0, xsize_canvas, ysize_canvas);
+		canvas.SetScroll(&scroll);
+		canvas.fill(MDin, display_label, _do_apply_orient, _minval, _maxval, _sigma_contrast, _scale, 1);
+		canvas.do_read_whole_stacks = false;
+		resizable(*this);
+		show();
+		return Fl::run();
+	}
+}
+
+int basisViewerWindow::fillPickerViewerCanvas(MultidimArray<double> image, double _minval, double _maxval, double _sigma_contrast,
+		double _scale, int _particle_radius, FileName _fn_coords,
+		FileName _fn_color, FileName _fn_mic, FileName _color_label, double _color_blue_value, double _color_red_value)
+{
+    // Scroll bars
+    Fl_Scroll scroll(0, 0, w(), h());
+	int xsize_canvas = CEIL(XSIZE(image)*_scale);
+	int ysize_canvas = CEIL(YSIZE(image)*_scale);
+	pickerViewerCanvas canvas(0, 0, xsize_canvas, ysize_canvas);
+	canvas.particle_radius = _particle_radius;
+	canvas.SetScroll(&scroll);
+	canvas.fill(image, _minval, _maxval, _sigma_contrast, _scale);
+	canvas.fn_coords = _fn_coords;
+	canvas.fn_color = _fn_color;
+	canvas.fn_mic = _fn_mic;
+	canvas.color_label = EMDL::str2Label(_color_label);
+	canvas.smallest_color_value = XMIPP_MIN(_color_blue_value, _color_red_value);
+	canvas.biggest_color_value = XMIPP_MAX(_color_blue_value, _color_red_value);
+	canvas.do_blue_to_red = (_color_blue_value < _color_red_value);
+	canvas.do_read_whole_stacks = false;
+	if (_fn_coords != "" && exists(_fn_coords))
+	{
+		canvas.loadCoordinates(false);
+		canvas.redraw();
+	}
+	resizable(*this);
+	show();
+	return Fl::run();
+
+}
+
+int basisViewerWindow::fillSingleViewerCanvas(MultidimArray<double> image, double _minval, double _maxval, double _sigma_contrast, double _scale)
+{
+    // Scroll bars
+    Fl_Scroll scroll(0, 0, w(), h());
+
+    // Pre-set the canvas to the correct size
+	int xsize_canvas = CEIL(XSIZE(image)*_scale);
+	int ysize_canvas = CEIL(YSIZE(image)*_scale);
+	singleViewerCanvas canvas(0, 0, xsize_canvas, ysize_canvas);
+	canvas.SetScroll(&scroll);
+	canvas.fill(image, _minval, _maxval, _sigma_contrast, _scale);
+	canvas.do_read_whole_stacks = false;
+	resizable(*this);
+	show();
+	return Fl::run();
+
+}
+int basisViewerCanvas::fill(MetaDataTable &MDin, EMDLabel display_label, bool _do_apply_orient, double _minval, double _maxval,
+		double _sigma_contrast, double _scale, int _ncol)
+{
+
+	ncol = _ncol;
+	int nr_imgs = MDin.numberOfObjects();
+	if (nr_imgs > 1)
+	{
+		xoff = BOX_OFFSET/2;
+		yoff = BOX_OFFSET/2;
+	}
+	else
+	{
+		xoff = 0;
+		yoff = 0;
+	}
+
+	int barstep;
+	if (nr_imgs > 1)
+	{
+		std::cout << "Reading in all images..." << std::endl;
+		init_progress_bar(nr_imgs);
+		barstep = XMIPP_MAX(1, nr_imgs/ 60);
+	}
+
+	nrow = 0;
+	long int ipos = 0;
+	int irow = 0;
+	int icol = 0;
+	FileName fn_my_stack, fn_next_stack, fn_img, fn_tmp;
+	long int my_number, my_next_number, my_stack_first_ipos = 0;
+	std::vector<long int> numbers_in_stack;
+
+	long int number_of_images = MDin.numberOfObjects();
+	boxes.clear();
+	boxes.resize(number_of_images);
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDin)
+	{
+		// Read in image stacks as a whole, i.e. don't re-open and close stack for every individual image to save speed
+		MDin.getValue(display_label, fn_img, ipos);
+		fn_img.decompose(my_number, fn_my_stack);
+
+		// See whether the next image has the same stackname....
+		if (ipos+1 < number_of_images)
+		{
+			MDin.getValue(display_label, fn_tmp, ipos+1);
+			fn_tmp.decompose(my_next_number, fn_next_stack);
+		}
+		else
+			fn_next_stack = "";
+
+		numbers_in_stack.push_back(my_number - 1); // start counting at 0!
+
+		// If next stack is a different one, read the current stack and process all images in it
+		if (fn_next_stack != fn_my_stack)
+		{
+
+			Image<double> stack, img;
+			fImageHandler* hFile;
+			if (do_read_whole_stacks)
+				// Read the entire stack into memory
+				stack.read(fn_my_stack);
+			else
+				// Open the stack file
+				hFile = img.openFile(fn_my_stack);
+
+			// 1. Process the current stack
+			for (long int inum = 0; inum < numbers_in_stack.size(); inum++)
+			{
+				// Get the image we want from the stack
+				if (do_read_whole_stacks)
+					stack().getImage(numbers_in_stack[inum], img());
+				else
+					img.readFromOpenFile(fn_my_stack, hFile, numbers_in_stack[inum]);
+				long int my_ipos = my_stack_first_ipos + inum;
+
+				if (_do_apply_orient)
+				{
+					double psi;
+					Matrix1D<double> offset(2);
+					MDin.getValue(EMDL_ORIENT_PSI, psi, my_ipos);
+					MDin.getValue(EMDL_ORIENT_ORIGIN_X, XX(offset), my_ipos);
+					MDin.getValue(EMDL_ORIENT_ORIGIN_Y, YY(offset), my_ipos);
+
+					Matrix2D<double> A;
+					rotation2DMatrix(psi, A);
+				    MAT_ELEM(A,0, 2) = XX(offset);
+				    MAT_ELEM(A,1, 2) = YY(offset);
+				    selfApplyGeometry(img(), A, IS_NOT_INV, DONT_WRAP);
+				}
+
+				// Dont change the user-provided _minval and _maxval in the getImageContrast routine!
+				double myminval = _minval;
+				double mymaxval = _maxval;
+				getImageContrast(img(), myminval, mymaxval, _sigma_contrast);
+
+				long int my_sorted_ipos = my_ipos;
+				if (MDin.containsLabel(EMDL_SORTED_IDX))
+				{
+					// First get the sorted index
+					MDin.getValue(EMDL_SORTED_IDX, my_sorted_ipos, my_ipos);
+					// Then set the original index in the sorted index, so that particles can be written out in the correct order
+					MDin.setValue(EMDL_SORTED_IDX, my_ipos, my_ipos);
+				}
+				icol = my_sorted_ipos % ncol;
+				irow = my_sorted_ipos / ncol;
+				nrow = XMIPP_MAX(nrow, irow+1);
+				if (my_ipos == 0)
+				{
+					xsize_box = CEIL(_scale * XSIZE(img())) + 2 * xoff; // 2 pixels on each side in between all images
+					ysize_box = CEIL(_scale * YSIZE(img())) + 2 * yoff;
+				}
+				int ycoor = irow * ysize_box;
+				int xcoor = icol * xsize_box;
+
+				DisplayBox* my_box = new DisplayBox(xcoor, ycoor, xsize_box, ysize_box, "");
+				my_box->setData(img(), MDin.getObject(my_ipos), my_ipos, myminval, mymaxval, _scale, false);
+				my_box->redraw();
+				boxes[my_sorted_ipos] = my_box;//boxes.push_back(my_box);
+			}
+
+			// Close the stack file again
+			if (!do_read_whole_stacks)
+				img.closeFile(hFile);
+
+			// 2. Reset numbers_in_stack and my_stack_first_ipos for next stack
+			numbers_in_stack.clear();
+			my_stack_first_ipos = ipos + 1;
+		}
+
+		ipos++;
+
+		if (nr_imgs > 1 && ipos % barstep == 0)
+			progress_bar(ipos);
+	}
+
+	if (nr_imgs > 1)
+		progress_bar(nr_imgs);
+
+
+
+}
+int basisViewerCanvas::fill(MultidimArray<double> &image, double _minval, double _maxval, double _sigma_contrast, double _scale)
+{
+	xoff = yoff = 0;
+	nrow = ncol = 1;
+	getImageContrast(image, _minval, _maxval, _sigma_contrast);
+	xsize_box = CEIL(_scale * XSIZE(image));
+	ysize_box = CEIL(_scale * YSIZE(image));
+	DisplayBox* my_box = new DisplayBox(0, 0, xsize_box, ysize_box, "dummy");
+	MetaDataTable MDtmp;
+	MDtmp.addObject();
+	//FileName fn_tmp = "dummy";
+	//MDtmp.setValue(EMDL_IMAGE_NAME, fn_tmp);
+	my_box->setData(image, MDtmp.getObject(), 0, _minval, _maxval, _scale, true);
+	my_box->redraw();
+	boxes.push_back(my_box);
+
+}
+
+void basisViewerCanvas::getImageContrast(MultidimArray<double> &image, double &minval, double &maxval, double &sigma_contrast)
+{
+	// First check whether to apply sigma-contrast, i.e. set minval and maxval to the mean +/- sigma_contrast times the stddev
+	bool redo_minmax = (sigma_contrast > 0. || minval != maxval);
+
+	if (sigma_contrast > 0. || minval == maxval)
+	{
+		double avg, stddev;
+		image.computeStats(avg, stddev, minval, maxval);
+		if (sigma_contrast > 0.)
+		{
+			minval = avg - sigma_contrast * stddev;
+			maxval = avg + sigma_contrast * stddev;
+			redo_minmax = true;
+		}
+	}
+
+	if (redo_minmax)
+	{
+		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(image)
+		{
+			double val = DIRECT_MULTIDIM_ELEM(image, n);
+			if (val > maxval)
+				DIRECT_MULTIDIM_ELEM(image, n) = maxval;
+			else if (val < minval)
+				DIRECT_MULTIDIM_ELEM(image, n) = minval;
+		}
+	}
+}
+
+void basisViewerCanvas::draw()
+{
+	for (int ipos = 0 ; ipos < boxes.size(); ipos++)
+		boxes[ipos]->redraw();
+}
+
+
+int multiViewerCanvas::handle(int ev)
+{
+	if (ev==FL_PUSH)
+	{
+		int xc = (int)Fl::event_x() - scroll->x() + scroll->hscrollbar.value();
+		int yc = (int)Fl::event_y() - scroll->y() + scroll->scrollbar.value();
+		int xpos = xc / xsize_box;
+		int ypos = yc / ysize_box;
+		int ipos = ypos * ncol + xpos;
+		// Check there was no click in the area outside the boxes...
+		if (xpos < ncol && ypos < nrow && ipos < boxes.size())
+		{
+			if (Fl::event_button() == FL_LEFT_MOUSE)
+			{
+				// Shift-left-click will select a whole range
+				if (Fl::event_state(FL_SHIFT))
+				{
+					if (has_shift)
+					{
+						int postshift_ipos = ipos;
+						int ipos0 = (postshift_ipos > preshift_ipos) ? preshift_ipos : postshift_ipos;
+						int iposF = (postshift_ipos > preshift_ipos) ? postshift_ipos : preshift_ipos;
+						// Select all images from ipos0 to iposF
+						// TODO!!! Cannot do this here: have to define an event for the multiview window as a whole!
+						// This multiview window should have all the DisplayBoxes inside it....
+						for (int my_ipos = ipos0; my_ipos <= iposF; my_ipos++)
+						{
+							boxes[my_ipos]->select();
+						}
+						has_shift = false;
+					}
+					else
+					{
+						preshift_ipos = ipos;
+						has_shift = true;
+					}
+
+				}
+				else
+				{
+					boxes[ipos]->toggleSelect();
+				}
+			}
+			else  if ( Fl::event_button() == FL_RIGHT_MOUSE )
+			{
+				Fl_Menu_Item rclick_menu;
+				if (do_class)
+				{
+					Fl_Menu_Item rclick_menu[] = {
+						{ "Save backup selection" },
+						{ "Load backup selection" },
+						{ "Clear selection" },
+						{ "Invert selection" },
+						{ "Select all classes below" },
+						{ "Select all classes above" },
+						{ "Print metadata this class" },
+						{ "Show original image" },
+						{ "Show particles from selected classes" },
+						{ "Save STAR with particles from selected classes" },
+						{ "Save STAR with selected classes" },
+						{ "Quit" },
+						{ 0 }
+					};
+
+					const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
+					if ( !m )
+						return 0;
+					else if ( strcmp(m->label(), "Save backup selection") == 0 )
+						saveBackupSelection();
+					else if ( strcmp(m->label(), "Load backup selection") == 0 )
+						loadBackupSelection();
+					else if ( strcmp(m->label(), "Clear selection") == 0 )
+						clearSelection();
+					else if ( strcmp(m->label(), "Invert selection") == 0 )
+						invertSelection();
+					else if ( strcmp(m->label(), "Select all classes below") == 0 )
+						selectFromHereBelow(ipos);
+					else if ( strcmp(m->label(), "Select all classes above") == 0 )
+						selectFromHereAbove(ipos);
+					else if ( strcmp(m->label(), "Print metadata this class") == 0 )
+						printMetaData(ipos);
+					else if ( strcmp(m->label(), "Show original image") == 0 )
+						showOriginalImage(ipos);
+					else if ( strcmp(m->label(), "Show particles from selected classes") == 0 )
+						showSelectedParticles(SELECTED);
+					else if ( strcmp(m->label(), "Save STAR with particles from selected classes") == 0 )
+						saveSelectedParticles(SELECTED);
+					else if ( strcmp(m->label(), "Save STAR with selected classes") == 0 )
+						saveSelected(SELECTED);
+					else if ( strcmp(m->label(), "Quit") == 0 )
+						exit(0);
+				}
+				else
+				{
+					Fl_Menu_Item rclick_menu[] = {
+						{ "Save backup selection" },
+						{ "Load backup selection" },
+						{ "Clear selection" },
+						{ "Invert selection" },
+						{ "Select all below" },
+						{ "Select all above" },
+						{ "Show average of selection" },
+						{ "Show stddev of selection" },
+						{ "Show original image" },
+						{ "Print metadata to screen" },
+						{ "Save STAR with selected images" },
+						{ "Quit" },
+						{ 0 }
+					};
+
+					const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
+					if ( !m )
+						return 0;
+					else if ( strcmp(m->label(), "Save backup selection") == 0 )
+						saveBackupSelection();
+					else if ( strcmp(m->label(), "Load backup selection") == 0 )
+						loadBackupSelection();
+					else if ( strcmp(m->label(), "Clear selection") == 0 )
+						clearSelection();
+					else if ( strcmp(m->label(), "Invert selection") == 0 )
+						invertSelection();
+					else if ( strcmp(m->label(), "Select all below") == 0 )
+						selectFromHereBelow(ipos);
+					else if ( strcmp(m->label(), "Select all above") == 0 )
+						selectFromHereAbove(ipos);
+					else if ( strcmp(m->label(), "Print metadata to screen") == 0 )
+						printMetaData(ipos);
+					else if ( strcmp(m->label(), "Show average of selection") == 0 )
+						showAverage(SELECTED, false);
+					else if ( strcmp(m->label(), "Show stddev of selection") == 0 )
+						showAverage(SELECTED, true);
+					else if ( strcmp(m->label(),  "Show original image") == 0 )
+						showOriginalImage(ipos);
+					else if ( strcmp(m->label(), "Save STAR with selected images") == 0 )
+						saveSelected(SELECTED);
+					else if ( strcmp(m->label(), "Quit") == 0 )
+						exit(0);
+
+				}
+				return(1);          // (tells caller we handled this event)
+			}
+		} // endif ipos within valid region
+
+	}
+	return 0;
+}
+
+void multiViewerCanvas::saveBackupSelection()
+{
+	MetaDataTable MDout;
+	for (long int ipos = 0; ipos < boxes.size(); ipos++)
+	{
+		MDout.addObject();
+		MDout.setValue(EMDL_SELECTED, boxes[ipos]->selected);
+	}
+	MDout.write(".relion_display_backup_selection.star");
+	std::cout <<" Written out .relion_display_backup_selection.star" << std::endl;
+}
+
+void multiViewerCanvas::loadBackupSelection()
+{
+	MetaDataTable MDin;
+	MDin.read(".relion_display_backup_selection.star");
+	if (MDin.numberOfObjects() != boxes.size())
+		REPORT_ERROR("multiViewerCanvas::loadBackupSelection ERROR: .relion_display_backup_selection.star does not have the expected number of entries...");
+
+	long int ipos = 0;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDin)
+	{
+		bool is_selected;
+		MDin.getValue(EMDL_SELECTED, is_selected);
+		if (is_selected)
+			boxes[ipos]->select();
+		else
+			boxes[ipos]->unSelect();
+		ipos++;
+	}
+
+}
+
+void multiViewerCanvas::clearSelection()
+{
+	for (long int ipos = 0; ipos < boxes.size(); ipos++)
+	{
+		boxes[ipos]->unSelect();
+	}
+}
+
+void multiViewerCanvas::invertSelection()
+{
+	for (long int ipos = 0; ipos < boxes.size(); ipos++)
+	{
+		boxes[ipos]->toggleSelect();
+	}
+}
+
+void multiViewerCanvas::selectFromHereBelow(int iposp)
+{
+	for (long int ipos = iposp; ipos < boxes.size(); ipos++)
+	{
+		boxes[ipos]->select();
+	}
+}
+
+void multiViewerCanvas::selectFromHereAbove(int iposp)
+{
+	for (long int ipos = 0; ipos <= iposp; ipos++)
+	{
+		boxes[ipos]->select();
+	}
+
+}
+void multiViewerCanvas::printMetaData(int ipos)
+{
+	boxes[ipos]->MDimg.write(std::cout);
+}
+
+void multiViewerCanvas::showAverage(bool selected, bool show_stddev)
+{
+	int xsize = boxes[0]->xsize_data;
+	int ysize = boxes[0]->ysize_data;
+	MultidimArray<double> sum(ysize, xsize);
+	MultidimArray<double> sum2(ysize, xsize);
+
+	int nn = 0;
+	for (long int ipos = 0; ipos < boxes.size(); ipos++)
+	{
+		if (boxes[ipos]->selected == selected)
+		{
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(sum)
+			{
+				int ival = boxes[ipos]->img_data[n];
+				if (ival < 0) ival += 256;
+				DIRECT_MULTIDIM_ELEM(sum, n) += ival;
+				DIRECT_MULTIDIM_ELEM(sum2, n) += ival * ival;
+			}
+			nn++;
+		}
+	}
+	sum  /= nn;
+	sum2 /= nn;
+
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(sum)
+	{
+		DIRECT_MULTIDIM_ELEM(sum2, n) -=  DIRECT_MULTIDIM_ELEM(sum, n) * DIRECT_MULTIDIM_ELEM(sum, n);
+	}
+    sum2 *= nn / (nn - 1);
+
+    // Show the average
+    if (show_stddev)
+    {
+        basisViewerWindow stddev(xsize, ysize, "Stddev");
+        stddev.fillSingleViewerCanvas(sum2, 0., 0., 0., 1.); // scale=1 now means: keep same scale as the one in the boxes!!!
+    }
+    else
+    {
+    	basisViewerWindow avg(xsize, ysize, "Average");
+    	avg.fillSingleViewerCanvas(sum, 0., 0., 0., 1.); // scale=1 now means: keep same scale as the one in the boxes!!!
+    }
+
+}
+
+void multiViewerCanvas::showOriginalImage(int ipos)
+{
+
+	// Make system call because otherwise the green drawing for distance measurements doesn't work....
+	FileName fn_img;
+	boxes[ipos]->MDimg.getValue(display_label, fn_img);
+
+	std::string cl = "relion_display  --i " + fn_img + " --scale " + integerToString(ori_scale);
+    if (sigma_contrast > 0.)
+    	cl += " --sigma_contrast " + floatToString(sigma_contrast);
+	// send job in the background
+	cl += " &";
+
+	system(cl.c_str());
+
+	/*
+	FileName fn_img;
+	boxes[ipos]->MDimg.getValue(display_label, fn_img);
+	Image<double> img;
+	img.read(fn_img);
+    basisViewerWindow win(CEIL(ori_scale*XSIZE(img())), CEIL(ori_scale*YSIZE(img())), fn_img.c_str());
+    if (sigma_contrast > 0.)
+    {
+    	win.fillSingleViewerCanvas(img(), 0., 0., sigma_contrast, ori_scale);
+    }
+    else
+    {
+    	win.fillSingleViewerCanvas(img(), boxes[ipos]->minval, boxes[ipos]->maxval, 0., ori_scale);
+    }
+    */
+}
+
+
+void multiViewerCanvas::makeStarFileSelectedParticles(bool selected, MetaDataTable &MDpart)
+{
+	MDpart.clear();
+	int myclass, iclass;
+	for (long int ipos = 0; ipos < boxes.size(); ipos++)
+	{
+		if (boxes[ipos]->selected == selected)
+		{
+			// Get class number (may not be ipos+1 if resorted!)
+			boxes[ipos]->MDimg.getValue(EMDL_PARTICLE_CLASS, myclass);
+			FOR_ALL_OBJECTS_IN_METADATA_TABLE(*MDdata)
+			{
+				MDdata->getValue(EMDL_PARTICLE_CLASS, iclass);
+				if (iclass == myclass)
+					MDpart.addObject(MDdata->getObject());
+			}
+		}
+	}
+
+	// Maintain the original image ordering
+	if (MDpart.containsLabel(EMDL_SORTED_IDX))
+		MDpart.sort(EMDL_SORTED_IDX);
+}
+
+void multiViewerCanvas::saveSelectedParticles(bool save_selected)
+{
+	MetaDataTable MDpart;
+	makeStarFileSelectedParticles(save_selected, MDpart);
+	if (nr_regroups > 0)
+		regroupSelectedParticles(MDpart, *MDgroups, nr_regroups);
+	int nparts = MDpart.numberOfObjects();
+	if (nparts > 0)
+	{
+		char *newfile;
+		newfile = fl_file_chooser("Save File As?", "*.star", "");
+		if (newfile==NULL)
+			return;
+		FileName fn_out(newfile);
+		MDpart.write(fn_out);
+		std::cout << "Saved "<<fn_out << " with " << nparts << " selected particles." << std::endl;
+	}
+	else
+		std::cout <<" No classes selected. First select one or more classes..." << std::endl;
+}
+
+void regroupSelectedParticles(MetaDataTable &MDdata, MetaDataTable &MDgroups, int nr_regroups)
+{
+
+	if (nr_regroups <= 0)
+		return;
+
+	// First sort the MDgroups based on refined intensity scale factor
+	MDgroups.sort(EMDL_MLMODEL_GROUP_SCALE_CORRECTION);
+
+	// Store original image order
+	long int nr_parts = MDdata.numberOfObjects();
+	for (long int j = 0; j < nr_parts; j++)
+		MDdata.setValue(EMDL_SORTED_IDX, j, j);
+
+	// Average group size
+	long average_group_size = nr_parts / nr_regroups;
+	int fillgroupschar = 1;
+	if (nr_regroups > 100)
+		fillgroupschar = 3;
+	else if (nr_regroups > 10)
+		fillgroupschar = 2;
+
+	// Loop through all existing, sorted groups
+	long old_nr_groups = MDgroups.numberOfObjects();
+	long curr_group_id, my_old_group_id, new_group_id = 1;
+	long nr_parts_in_new_group = 0;
+	MetaDataTable MDout;
+	for (long ig = 0; ig < old_nr_groups; ig++)
+	{
+		// Now search for curr_group_id in the input MetaDataTable
+		MDgroups.getValue(EMDL_MLMODEL_GROUP_NO, curr_group_id, ig);
+
+		if (nr_parts_in_new_group > average_group_size)
+		{
+			// This group is now full: start a new one
+			new_group_id++;
+			nr_parts_in_new_group = 0;
+		}
+
+		std::string new_group_name = "group_" + integerToString(new_group_id, fillgroupschar);
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDdata)
+		{
+			MDdata.getValue(EMDL_MLMODEL_GROUP_NO, my_old_group_id);
+			if (my_old_group_id == curr_group_id)
+			{
+				nr_parts_in_new_group++;
+				MDout.addObject(MDdata.getObject());
+				MDout.setValue(EMDL_MLMODEL_GROUP_NO, new_group_id);
+				MDout.setValue(EMDL_MLMODEL_GROUP_NAME, new_group_name);
+			}
+		}
+	}
+
+	// Maintain the original image ordering
+	if (MDout.containsLabel(EMDL_SORTED_IDX))
+		MDout.sort(EMDL_SORTED_IDX);
+
+	std::cout <<" Regrouped particles into " << new_group_id - 1 << " groups" << std::endl;
+	MDdata = MDout;
+
+}
+
+void multiViewerCanvas::showSelectedParticles(bool save_selected)
+{
+	MetaDataTable MDpart;
+	makeStarFileSelectedParticles(save_selected, MDpart);
+	int nparts = MDpart.numberOfObjects();
+	if (nparts > 0)
+	{
+        basisViewerWindow win(MULTIVIEW_WINDOW_WIDTH, MULTIVIEW_WINDOW_HEIGHT, "Particles in the selected classes");
+        win.fillCanvas(MULTIVIEWER, MDpart, EMDL_IMAGE_NAME, do_read_whole_stacks, true, 0., 0., 0., boxes[0]->scale, ori_scale, ncol);
+	}
+	else
+		std::cout <<" No classes selected. First select one or more classes..." << std::endl;
+
+}
+
+void multiViewerCanvas::saveSelected(bool save_selected)
+{
+	// Now save the MetaData
+	MetaDataTable MDout;
+	int nsel = 0;
+	for (long int ipos = 0; ipos < boxes.size(); ipos++)
+	{
+		if (boxes[ipos]->selected == save_selected)
+		{
+			nsel++;
+			MDout.addObject(boxes[ipos]->MDimg.getObject());
+		}
+	}
+	if (nsel > 0)
+	{
+		if (is_data && nr_regroups > 0)
+			regroupSelectedParticles(MDout, *MDgroups, nr_regroups);
+
+		char *newfile;
+		newfile = fl_file_chooser("Save File As?", "*.star", "");
+		if (newfile==NULL)
+			return;
+		FileName fn_out(newfile);
+
+		// Maintain the original image ordering
+		if (MDout.containsLabel(EMDL_SORTED_IDX))
+			MDout.sort(EMDL_SORTED_IDX);
+
+		MDout.write(fn_out);
+		std::cout << "Saved "<<fn_out << " with " << nsel << " selected images." << std::endl;
+	}
+	else
+		std::cout <<" No images to save...." << std::endl;
+}
+
+int singleViewerCanvas::handle(int ev)
+{
+	if (ev==FL_PUSH && Fl::event_button() == FL_LEFT_MOUSE)
+	{
+		int xc = (int)Fl::event_x() - scroll->x() + scroll->hscrollbar.value();
+		int yc = (int)Fl::event_y() - scroll->y() + scroll->scrollbar.value();
+		int rx = xc - x() - boxes[0]->xoff;
+		int ry = yc - y() - boxes[0]->yoff;
+		// Left mouse click writes value and coordinates to screen
+
+		if (rx < boxes[0]->xsize_data && ry < boxes[0]->ysize_data && rx >= 0 && ry >=0)
+		{
+			int ival = boxes[0]->img_data[ry*boxes[0]->xsize_data + rx];
+			if (ival < 0) ival += 256;
+			double step = (boxes[0]->maxval - boxes[0]->minval) / 255.;
+			double dval = ival * step + boxes[0]->minval;
+			int ysc = ROUND(ry/boxes[0]->scale);
+			int xsc = ROUND(rx/boxes[0]->scale);
+			int yscp = ysc - ROUND((boxes[0]->ysize_data/(2.* boxes[0]->scale)));
+			int xscp = xsc - ROUND((boxes[0]->xsize_data/(2.* boxes[0]->scale)));
+			std::cout <<" Image value at (" << xsc << "," << ysc << ") or (" << xscp << "," << yscp << ")~= " << dval <<std::endl;
+		}
+		return(1);
+	}
+	else if (ev==FL_PUSH && Fl::event_button() == FL_RIGHT_MOUSE)
+	{
+		Fl_Menu_Item rclick_menu[] = {
+			{ "Print metadata" },
+			{ "Help" },
+			{ "Quit" },
+			{ 0 }
+		};
+		const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
+		if ( !m )
+			return 0;
+		if ( strcmp(m->label(), "Print metadata") == 0 )
+			printMetaData();
+		else if ( strcmp(m->label(), "Help") == 0 )
+			printHelp();
+		else if ( strcmp(m->label(), "Quit") == 0 )
+			exit(0);
+		return(1);          // (tells caller we handled this event)
+	}
+	else if (ev==FL_PUSH && Fl::event_button() == FL_MIDDLE_MOUSE)
+	{
+		// Middle-mouse dragging for measuring distances
+		if (!has_dragged)
+		{
+			redraw();
+			predrag_xc = (int)Fl::event_x();
+			predrag_yc = (int)Fl::event_y();
+			has_dragged = true;
+			fl_color(FL_RED);
+			fl_circle(predrag_xc, predrag_yc, 3);
+		}
+		return(1);
+	}
+	else if (ev==FL_DRAG  && Fl::event_button() == FL_MIDDLE_MOUSE)
+	{
+		fl_color(FL_RED);
+		fl_circle(predrag_xc, predrag_yc, 3);
+	}
+	else if (ev==FL_RELEASE  && Fl::event_button() == FL_MIDDLE_MOUSE)
+	{
+		int postdrag_xc = (int)Fl::event_x();
+		int postdrag_yc = (int)Fl::event_y();
+		if (has_dragged)
+		{
+			fl_color(FL_RED);
+			fl_circle(predrag_xc, predrag_yc, 3);
+			fl_line(predrag_xc, predrag_yc, postdrag_xc, postdrag_yc);
+			fl_circle(postdrag_xc, postdrag_yc, 3);
+			int dx = postdrag_xc - predrag_xc;
+			int dy = postdrag_yc - predrag_yc;
+			double dist = sqrt((double)(dx*dx + dy*dy));
+			std::string text =  floatToString(dist/boxes[0]->scale) + " pixels";
+			fl_draw(text.c_str(), (postdrag_xc + predrag_xc)/2, (postdrag_yc + predrag_yc)/2);
+			// Also write to the screen, in case the text falls outside the screen
+			std::cout << "distance= " << dist/boxes[0]->scale << " pixels" << std::endl;
+			has_dragged = false;
+		}
+		return(1);
+	}
+
+	return 0;
+}
+
+void singleViewerCanvas::printHelp()
+{
+	std::cout <<" + Left-mouse click: print coordinates and intensity value to screen " << std::endl;
+	std::cout <<" + Middle-mouse drag: measure distances " << std::endl;
+	std::cout <<" + Right-mouse click: pop-up menu" << std::endl;
+}
+
+void pickerViewerCanvas::draw()
+{
+	double scale = boxes[0]->scale;
+
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDcoords)
+	{
+		double xcoor, ycoor;
+		MDcoords.getValue(EMDL_IMAGE_COORD_X, xcoor);
+		MDcoords.getValue(EMDL_IMAGE_COORD_Y, ycoor);
+
+		if (color_label != EMDL_UNDEFINED)
+		{
+			double colval;
+			if (EMDL::isInt(color_label))
+			{
+				int ival;
+				MDcoords.getValue(color_label, ival);
+				colval = (double)ival;
+			}
+			else
+			{
+				MDcoords.getValue(color_label, colval);
+			}
+			// Assume undefined values are set to -999....
+			if ((colval + 999.) < XMIPP_EQUAL_ACCURACY)
+			{
+				fl_color(FL_GREEN);
+			}
+			else
+			{
+				colval = XMIPP_MAX(colval, smallest_color_value);
+				colval = XMIPP_MIN(colval, biggest_color_value);
+				unsigned char red, blue;
+				if (do_blue_to_red)
+				{
+					red  = ROUND(255. * (colval - smallest_color_value) / (biggest_color_value - smallest_color_value));
+					blue = ROUND(255. * (biggest_color_value - colval)  / (biggest_color_value - smallest_color_value));
+				}
+				else
+				{
+					blue = ROUND(255. * (colval - smallest_color_value) / (biggest_color_value - smallest_color_value));
+					red  = ROUND(255. * (biggest_color_value - colval)  / (biggest_color_value - smallest_color_value));
+				}
+				fl_color(red,0,blue);
+			}
+		}
+		else
+		{
+			fl_color(FL_GREEN);
+		}
+		int xcoori, ycoori;
+		xcoori = ROUND(xcoor * scale) + scroll->x() - scroll->hscrollbar.value();
+		ycoori = ROUND(ycoor * scale) + scroll->y() - scroll->scrollbar.value();
+		fl_circle(xcoori, ycoori, particle_radius);
+	}
+}
+
+int pickerViewerCanvas::handle(int ev)
+{
+
+	if (ev==FL_PUSH || (ev==FL_DRAG && Fl::event_button() == FL_MIDDLE_MOUSE) )
+	{
+		double scale = boxes[0]->scale;
+		int xc = (int)Fl::event_x() - scroll->x() + scroll->hscrollbar.value();
+		int yc = (int)Fl::event_y() - scroll->y() + scroll->scrollbar.value();
+		double xcoor = (double)ROUND(xc/scale);
+		double ycoor = (double)ROUND(yc/scale);
+		double rad2 = particle_radius*particle_radius/(scale*scale);
+		if (Fl::event_button() == FL_LEFT_MOUSE)
+		{
+			// Left mouse for picking
+			// Check the pick is not inside an existing circle
+			double xcoor_p, ycoor_p;
+			FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDcoords)
+			{
+				MDcoords.getValue(EMDL_IMAGE_COORD_X, xcoor_p);
+				MDcoords.getValue(EMDL_IMAGE_COORD_Y, ycoor_p);
+				xcoor_p -= xcoor;
+				ycoor_p -= ycoor;
+
+				if (xcoor_p*xcoor_p + ycoor_p*ycoor_p < rad2)
+					return 0;
+			}
+			// Else store new coordinate
+
+			MDcoords.addObject();
+			MDcoords.setValue(EMDL_IMAGE_COORD_X, xcoor);
+			MDcoords.setValue(EMDL_IMAGE_COORD_Y, ycoor);
+			// If a autopicking file was read in, now store -999 in all the corresponding values....
+			if (MDcoords.containsLabel(EMDL_PARTICLE_CLASS))
+			{
+				int iclass = -999;
+				MDcoords.setValue(EMDL_PARTICLE_CLASS, iclass);
+			}
+			if (MDcoords.containsLabel(EMDL_ORIENT_PSI))
+			{
+				double psi = -999.;
+				MDcoords.setValue(EMDL_ORIENT_PSI, psi);
+			}
+			if (MDcoords.containsLabel(EMDL_PARTICLE_AUTOPICK_FOM))
+			{
+				double fom = -999.;
+				MDcoords.setValue(EMDL_PARTICLE_AUTOPICK_FOM, fom);
+			}
+			if (MDcoords.containsLabel(color_label))
+			{
+				double z = -999.;
+				MDcoords.setValue(color_label, z);
+			}
+
+			redraw();
+			return 1;
+		}
+		else if (Fl::event_button() == FL_MIDDLE_MOUSE)
+		{
+			boxes[0]->redraw();
+			// Middle mouse for deleting
+			double xcoor_p, ycoor_p;
+			FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDcoords)
+			{
+				MDcoords.getValue(EMDL_IMAGE_COORD_X, xcoor_p);
+				MDcoords.getValue(EMDL_IMAGE_COORD_Y, ycoor_p);
+				xcoor_p -= xcoor;
+				ycoor_p -= ycoor;
+
+				if (xcoor_p*xcoor_p + ycoor_p*ycoor_p < rad2)
+				{
+					MDcoords.removeObject();
+					break;
+				}
+			}
+			redraw();
+			return 1;
+		}
+		else if (Fl::event_button() == FL_RIGHT_MOUSE)
+		{
+			redraw();
+			Fl_Menu_Item rclick_menu[] = {
+				{ "Save STAR with coordinates" },
+				{ "Save_as STAR with coordinates" },
+				{ "Load coordinates" },
+				{ "Reload coordinates" },
+				{ "Clear coordinates" },
+				{ "Help" },
+				{ "Quit" },
+				{ 0 }
+			};
+			const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
+			if ( !m )
+				return 0;
+			else if ( strcmp(m->label(), "Save STAR with coordinates") == 0 )
+				saveCoordinates(false);
+			else if ( strcmp(m->label(), "Save_as STAR with coordinates") == 0 )
+				saveCoordinates(true);
+			else if ( strcmp(m->label(), "Load coordinates") == 0 )
+				loadCoordinates(true);
+			else if ( strcmp(m->label(), "Reload coordinates") == 0 )
+				loadCoordinates(false);
+			else if ( strcmp(m->label(), "Clear coordinates") == 0 )
+				clearCoordinates();
+			else if ( strcmp(m->label(), "Help") == 0 )
+				printHelp();
+			else if ( strcmp(m->label(), "Quit") == 0 )
+				exit(0);
+			redraw();
+			return(1);          // (tells caller we handled this event)
+		}
+		return 0;
+	}
+	// Update the drawing every time something happens ....
+	else if (ev==FL_RELEASE || ev==FL_LEAVE || ev==FL_ENTER || ev==FL_MOVE || ev == FL_FOCUS || ev == FL_UNFOCUS)
+	{
+		redraw();
+		return 1;
+	}
+	return 0;
+
+}
+void pickerViewerCanvas::saveCoordinates(bool ask_filename)
+{
+
+	if (MDcoords.numberOfObjects() < 1)
+	{
+		std::cout <<" No coordinates to save. Use left-mouse clicks to pick coordinates first..." << std::endl;
+		return;
+	}
+
+	FileName fn_out;
+	if (ask_filename)
+	{
+		char *newfile;
+		newfile = fl_file_chooser("Save File As?", "*.star", "");
+		if (newfile == NULL)
+			return;
+		FileName fn_tmp(newfile);
+		fn_out = fn_tmp;
+	}
+	else
+	{
+		fn_out = (fn_coords=="") ? "picked.star" : fn_coords;
+	}
+
+	// Never write out columns that come from the fn_color file....
+	if (fn_color != "" && color_label != EMDL_UNDEFINED)
+	{
+		MetaDataTable MDnew = MDcoords;
+		MDnew.deactivateLabel(color_label);
+		MDnew.write(fn_out); // write out a copy of the MDcoord to maintain the Z-score label active...
+	}
+	else
+	{
+		MDcoords.write(fn_out);
+	}
+	std::cout << "Saved "<<fn_out << " with " << MDcoords.numberOfObjects() << " selected coordinates." << std::endl;
+	return;
+
+}
+
+void pickerViewerCanvas::loadCoordinates(bool ask_filename)
+{
+	clearCoordinates();
+	FileName fn_coord_in;
+	if (ask_filename)
+	{
+		char *newfile;
+		newfile = fl_file_chooser("Load File?", "*.star", "");
+		if (newfile==NULL)
+			return;
+		FileName fn_tmp(newfile);
+		fn_coord_in = fn_tmp;
+	}
+	else
+	{
+		fn_coord_in = (fn_coords=="") ? "picked.star" : fn_coords;
+	}
+	MDcoords.read(fn_coord_in);
+
+	if (fn_color != "")
+	{
+		findColorColumnForCoordinates();
+	}
+
+}
+
+void pickerViewerCanvas::findColorColumnForCoordinates()
+{
+
+	MetaDataTable MDcolor, MDcolormic;
+	MDcolor.read(fn_color);
+
+	if (!MDcolor.containsLabel(color_label))
+		REPORT_ERROR("--color STAR file does not contain the specified color_label!");
+
+	// Pre-set all color_label column in the MDcoords to -999.
+	if (EMDL::isInt(color_label))
+	{
+		int ival = -999;
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDcoords)
+		{
+			MDcoords.setValue(color_label, ival);
+		}
+	}
+	else
+	{
+		double val = -999.;
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDcoords)
+		{
+			MDcoords.setValue(color_label, val);
+		}
+	}
+
+	FileName _fn_mic, _fn_img;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDcolor)
+	{
+		MDcolor.getValue(EMDL_MICROGRAPH_NAME, _fn_mic);
+		if (fn_mic == _fn_mic)
+		{
+			// Get the imagename
+			MDcolor.getValue(EMDL_IMAGE_NAME, _fn_img);
+			long int iimg;
+			std::string dum;
+			_fn_img.decompose(iimg, dum);
+			iimg--; // counting starts at 1 in STAR file!
+
+			// Check that this entry in the coord file has the same xpos and ypos
+			double my_xpos, my_ypos;
+			MDcoords.getValue(EMDL_IMAGE_COORD_X, my_xpos, iimg);
+			MDcoords.getValue(EMDL_IMAGE_COORD_Y, my_ypos, iimg);
+
+			double x, y;
+			MDcolor.getValue(EMDL_IMAGE_COORD_X, x);
+			MDcolor.getValue(EMDL_IMAGE_COORD_Y, y);
+
+			if ( ABS(x - my_xpos) + ABS(y - my_ypos) > XMIPP_EQUAL_ACCURACY)
+			{
+				std::cerr << " _fn_img= " << _fn_img << " iimg= " << iimg << " _fn_mic= " << _fn_mic << std::endl;
+				std::cerr << " x= " << x << " my_xpos= " << my_xpos << std::endl;
+				std::cerr << " y= " << y << " my_ypos= " << my_ypos << std::endl;
+				REPORT_ERROR("The image in the --color star file does not have the same coordinates as the ones in the --coord file!");
+			}
+			else
+			{
+				if (EMDL::isInt(color_label))
+				{
+					int ival;
+					MDcolor.getValue(color_label, ival);
+					MDcoords.setValue(color_label, ival, iimg);
+				}
+				else
+				{
+					double val;
+					MDcolor.getValue(color_label, val);
+					MDcoords.setValue(color_label, val, iimg);
+				}
+			}
+		}
+	}
+
+}
+
+void pickerViewerCanvas::clearCoordinates()
+{
+	boxes[0]->redraw();
+	MDcoords.clear();
+}
+
+void pickerViewerCanvas::printHelp()
+{
+	std::cout <<" + Left-mouse   click: pick particles " << std::endl;
+	std::cout <<" + Middle-mouse click: delete particles " << std::endl;
+	std::cout <<" + Right-mouse click: pop-up menu" << std::endl;
+	std::cout <<" + Refresh picked particles by moving out of the window and back in again ..." << std::endl;
+}
+
+void singleViewerCanvas::printMetaData()
+{
+	boxes[0]->MDimg.write(std::cout);
+}
+
+
+// Fill GUI window
+int displayerGuiWindow::fill(FileName &_fn_in)
+{
+	// display image name at the top
+	fn_in = _fn_in;
+	FileName fn_short = _fn_in.removeDirectories();
+
+	color(GUI_BACKGROUND_COLOR);
+
+	int width = 485;
+	Fl_Text_Display *mydisp = new Fl_Text_Display(15, 15, width-15, 25,"");
+	Fl_Text_Buffer *textbuff = new Fl_Text_Buffer();
+	textbuff->text(fn_short.c_str());
+	mydisp->buffer(textbuff);
+	int x=170, y=15, ystep = 27, height = 25,  inputwidth = 50;
+	int x2 = width - inputwidth - 50;
+	y += ROUND(1.5*ystep);
+
+	// General box
+	Fl_Box *box1 = new Fl_Box(15, y-ROUND(0.25*ystep), width - 15, ROUND(2.5*ystep), "");
+	box1->color(GUI_BACKGROUND_COLOR);
+	box1->box(FL_DOWN_BOX);
+
+	// Always display these:
+	scale_input = new Fl_Input(x, y, inputwidth, height, "Scale:");
+	scale_input->color(GUI_INPUT_COLOR);
+	scale_input->value("1");
+
+	black_input = new Fl_Input(x2, y, inputwidth, height, "Black value:");
+	black_input->value("0");
+	black_input->color(GUI_INPUT_COLOR);
+	y += ystep;
+
+	sigma_contrast_input = new Fl_Input(x, y, inputwidth, height, "Sigma contrast:");
+	sigma_contrast_input->value("0");
+	sigma_contrast_input->color(GUI_INPUT_COLOR);
+
+	white_input = new Fl_Input(x2, y, inputwidth, height, "White value:");
+	white_input->value("0");
+	white_input->color(GUI_INPUT_COLOR);
+	y += ROUND(1.75*ystep);
+
+	if (is_star)
+	{
+
+		// STAR box
+		Fl_Box *box2 = new Fl_Box(15, y-ROUND(0.25*ystep), width - 15, ROUND(3.5*ystep), "");
+		box2->color(GUI_BACKGROUND_COLOR);
+		box2->box(FL_DOWN_BOX);
+
+		display_choice = new Fl_Choice(x, y, width-x, height, "Display:");
+		for (int i = 0; i < display_labels.size(); i++)
+			display_choice->add(display_labels[i].c_str(), 0, 0,0, FL_MENU_VALUE);
+		display_choice->picked(display_choice->menu());
+		display_choice->color(GUI_INPUT_COLOR);
+		y += ystep;
+
+		sort_button = new Fl_Check_Button(35,y,height,height, "Sort images ");
+		sort_choice = new Fl_Choice(x, y, width-x, height, "on:");
+		for (int i = 0; i < sort_labels.size(); i++)
+			sort_choice->add(sort_labels[i].c_str(), 0, 0,0, FL_MENU_VALUE);
+		sort_choice->picked(sort_choice->menu());
+		sort_choice->color(GUI_INPUT_COLOR);
+		y += ystep;
+
+		reverse_sort_button  = new Fl_Check_Button(35, y, inputwidth, height, "Reverse sort?");
+		reverse_sort_button->color(GUI_INPUT_COLOR);
+		apply_orient_button  = new Fl_Check_Button(x, y, inputwidth, height, "Apply orientations?");
+		apply_orient_button->color(GUI_INPUT_COLOR);
+		read_whole_stack_button = new Fl_Check_Button(x+160, y, inputwidth, height, "Read whole stacks?");
+		read_whole_stack_button->color(GUI_INPUT_COLOR);
+		y += ROUND(1.75*ystep);
+
+	}
+
+	// Optional display options
+	if (is_multi)
+	{
+		// Multiview box
+		Fl_Box *box3;
+		if (is_class || is_data)
+			box3 = new Fl_Box(15, y-ROUND(0.25*ystep), width - 15, ROUND(2.5*ystep), "");
+		else
+			box3 = new Fl_Box(15, y-ROUND(0.25*ystep), width - 15, ROUND(1.5*ystep), "");
+
+		box3->color(GUI_BACKGROUND_COLOR);
+		box3->box(FL_DOWN_BOX);
+
+		col_input = new Fl_Input(x, y, inputwidth, height, "Number of columns:");
+		col_input->value("5");
+		col_input->color(GUI_INPUT_COLOR);
+
+		ori_scale_input = new Fl_Input(x2, y, inputwidth, height, "Scale original images:");
+		ori_scale_input->value("1");
+		ori_scale_input->color(GUI_INPUT_COLOR);
+		y += ROUND(ystep);
+
+		if (is_class || is_data)
+		{
+			regroup_button = new Fl_Check_Button(20, y, inputwidth, height, "Regroup selected particles");
+			regroup_button->color(GUI_INPUT_COLOR);
+			nr_groups_input = new Fl_Input(x2, y, inputwidth, height, "in number of groups:");
+			nr_groups_input->color(GUI_INPUT_COLOR);
+			nr_groups_input->value("-1");
+
+			y+=1.75*ystep;
+		}
+		else
+			y += ROUND(0.75*ystep);
+	}
+	else // is_single
+	{
+		// singleview box
+		Fl_Box *box3 = new Fl_Box(15, y-ROUND(0.25*ystep), width - 15, ROUND(3.5*ystep), "");
+		box3->color(GUI_BACKGROUND_COLOR);
+		box3->box(FL_DOWN_BOX);
+
+		pick_button = new Fl_Check_Button(150, y, inputwidth, height, "Pick particles");
+		pick_button->color(GUI_INPUT_COLOR);
+
+		particle_radius_input = new Fl_Input(x2, y, inputwidth, height, "with radius (pix):");
+		particle_radius_input->color(GUI_INPUT_COLOR);
+		particle_radius_input->value("100");
+		y += ystep;
+
+		pick_rootname_input = new Fl_Input(x2-inputwidth, y, 2*inputwidth, height, "picking rootname:");
+		pick_rootname_input->color(GUI_INPUT_COLOR);
+		pick_rootname_input->value("autopick");
+		y += ystep;
+
+		lowpass_input = new Fl_Input(x, y, inputwidth, height, "Lowpass filter (A):");
+		lowpass_input->color(GUI_INPUT_COLOR);
+		lowpass_input->value("0");
+
+		angpix_input = new Fl_Input(x2, y, inputwidth, height, "Pixel size (A):");
+		angpix_input->color(GUI_INPUT_COLOR);
+		angpix_input->value("1");
+
+		y += ROUND(1.75*ystep);
+	}
+
+	// Display button
+	Fl_Button *display_button = new Fl_Button(width-100, y, 100, 30, "Display!");
+	display_button->color(GUI_RUNBUTTON_COLOR);
+	display_button->callback( cb_display, this);
+
+	// Read last settings file if it is present
+	readLastSettings();
+
+	show();
+	return Fl::run();
+}
+
+void displayerGuiWindow::readLastSettings()
+{
+	FileName fn = ".relion_display_gui_settings";
+	if (!exists(fn))
+		return;
+
+	std::ifstream in(fn.c_str(), std::ios_base::in);
+    if (in.fail())
+    {
+    	std::cerr << "Error reading last settings from file: "<< fn<<std::endl;
+    	return;
+    }
+
+	in.seekg(0, std::ios::beg);
+	std::string line;
+	while (getline(in, line, '\n'))
+	{
+		int ispos = line.rfind("=");
+		std::string label = line.substr(0, ispos - 1);
+		std::string value = line.substr(ispos+2,line.length());
+		if (label == scale_input->label())
+			scale_input->value(value.c_str());
+		else if (label == black_input->label())
+			black_input->value(value.c_str());
+		else if (label == white_input->label())
+			white_input->value(value.c_str());
+		else if (label == sigma_contrast_input->label())
+			sigma_contrast_input->value(value.c_str());
+		else if (is_multi && label == col_input->label())
+			col_input->value(value.c_str());
+		else if (!is_multi && label == particle_radius_input->label())
+			particle_radius_input->value(value.c_str());
+		else if (!is_multi && label == pick_rootname_input->label())
+			pick_rootname_input->value(value.c_str());
+		else if (!is_multi && label == lowpass_input->label())
+			lowpass_input->value(value.c_str());
+		else if (!is_multi && label == angpix_input->label())
+			angpix_input->value(value.c_str());
+		else if (is_class && label == nr_groups_input->label())
+			nr_groups_input->value(value.c_str());
+	}
+
+	in.close();
+
+
+}
+void displayerGuiWindow::writeLastSettings()
+{
+    std::ofstream  fh;
+    FileName fn = ".relion_display_gui_settings";
+    fh.open(fn.c_str(), std::ios::out);
+    if (!fh)
+    {
+    	std::cerr << "Cannot write last settings to file: "<<fn<<std::endl;
+    	return;
+    }
+
+    fh << scale_input->label() << " = " << scale_input->value() << std::endl;
+    fh << black_input->label() << " = " << black_input->value() << std::endl;
+    fh << white_input->label() << " = " << white_input->value() << std::endl;
+    fh << sigma_contrast_input->label() << " = " << sigma_contrast_input->value() << std::endl;
+    if (is_multi)
+    {
+    	fh << col_input->label() << " = " << col_input->value() << std::endl;
+    }
+    else
+    {
+    	fh << particle_radius_input->label() << " = " << particle_radius_input->value() << std::endl;
+    	fh << pick_rootname_input->label() << " = " << pick_rootname_input->value() << std::endl;
+    	fh << lowpass_input->label() << " = " << lowpass_input->value() << std::endl;
+    	fh << angpix_input->label() << " = " << angpix_input->value() << std::endl;
+
+    }
+    if (is_class || is_data)
+    	fh << nr_groups_input->label() << " = " << nr_groups_input->value() << std::endl;
+
+    fh.close();
+
+}
+// Display button call-back functions
+void displayerGuiWindow::cb_display(Fl_Widget* o, void* v) {
+
+	displayerGuiWindow* T=(displayerGuiWindow*)v;
+    T->cb_display_i();
+}
+
+void displayerGuiWindow::cb_display_i()
+{
+
+	// Save last settings, so we don't need to change settings every time...
+	writeLastSettings();
+
+	// This is a rather ugly system call to the relion_display program again,
+	// but I do not know how to get back to the original Displayer class from here...
+	std::string cl = "relion_display ";
+	cl += " --i " + fn_in;
+
+	// Always
+	cl += " --scale " + (std::string)scale_input->value();
+	cl += " --black " + (std::string)black_input->value();
+	cl += " --white " + (std::string)white_input->value();
+	cl += " --sigma_contrast " + (std::string)sigma_contrast_input->value();
+
+	if (is_star)
+	{
+
+		const Fl_Menu_Item* m = display_choice->mvalue();
+		cl += " --display " + (std::string)m->label();
+
+		if (sort_button->value())
+		{
+			const Fl_Menu_Item* m2 = sort_choice->mvalue();
+			cl += " --sort " + (std::string)m2->label();
+			if (reverse_sort_button->value())
+				cl += " --reverse ";
+		}
+
+		if (read_whole_stack_button->value())
+			cl += " --read_whole_stack ";
+
+		if (apply_orient_button->value())
+			cl += " --apply_orient ";
+	}
+
+	if (is_multi)
+	{
+		cl += " --col " + (std::string)col_input->value();
+		cl += " --ori_scale " + (std::string)ori_scale_input->value();
+	}
+	else
+	{
+		//check for pick
+		if (pick_button->value())
+		{
+			cl += " --pick  --particle_radius " + (std::string)particle_radius_input->value();
+			// get the coordinate files
+			FileName fn_coord = fn_in.withoutExtension() + "_" + (std::string)pick_rootname_input->value() + ".star";
+			cl += " --coords " + fn_coord;
+			cl += " --lowpass " + (std::string)lowpass_input->value();
+			cl += " --angpix " + (std::string)angpix_input->value();
+		}
+
+	}
+	if ( (is_class || is_data) && regroup_button->value())
+	{
+		cl += " --regroup " + (std::string)nr_groups_input->value();
+	}
+	if (is_class)
+	{
+		cl += " --class ";
+	}
+
+
+	// send job in the background
+	cl += " &";
+	std::cerr << "Executing: " << cl << std::endl;
+	system(cl.c_str());
+
+}
+
+
+void Displayer::read(int argc, char **argv)
+{
+
+	parser.setCommandLine(argc, argv);
+
+	int gen_section = parser.addSection("General options");
+	fn_in = parser.getOption("--i", "Input STAR file, image or stack","");
+	do_gui = parser.checkOption("--gui", "Use this to provide all other parameters through a GUI");
+	display_label = EMDL::str2Label(parser.getOption("--display", "Metadata label to display", "rlnImageName"));
+	table_name = parser.getOption("--table", "Name of the table to read from in the input STAR file", "");
+	scale = textToFloat(parser.getOption("--scale", "Relative scale", "1"));
+	minval = textToFloat(parser.getOption("--black", "Pixel value for black (default is auto-contrast)", "0"));
+	maxval = textToFloat(parser.getOption("--white", "Pixel value for white (default is auto-contrast)", "0"));
+	sigma_contrast  = textToFloat(parser.getOption("--sigma_contrast", "Set white and black pixel values this many times the image stddev from the mean", "0"));
+	do_read_whole_stacks = parser.checkOption("--read_whole_stack", "Read entire stacks at once (to speed up when many images of each stack are displayed)");
+
+	int disp_section  = parser.addSection("Multiviewer options");
+	ncol = textToInteger(parser.getOption("--col", "Number of columns", "5"));
+	do_apply_orient = parser.checkOption("--apply_orient","Apply the orientation as stored in the input STAR file angles and offsets");
+	ori_scale = textToFloat(parser.getOption("--ori_scale", "Relative scale for viewing individual images in multiviewer", "1"));
+	sort_label = EMDL::str2Label(parser.getOption("--sort", "Metadata label to sort images on", "EMDL_UNDEFINED"));
+	reverse_sort = parser.checkOption("--reverse", "Use reverse order (from high to low) in the sorting");
+	do_class = parser.checkOption("--class", "Use this to analyse classes in input model.star file");
+	nr_regroups = textToInteger(parser.getOption("--regroup", "Number of groups to regroup saved particles from selected classes in (default is no regrouping)", "-1"));
+
+	int pick_section  = parser.addSection("Picking options");
+	do_pick = parser.checkOption("--pick", "Pick coordinates in input image");
+	fn_coords = parser.getOption("--coords", "STAR file with picked particle coordinates", "");
+	particle_radius = textToFloat(parser.getOption("--particle_radius", "Particle radius in pixels", "100"));
+	lowpass = textToFloat(parser.getOption("--lowpass", "Lowpass filter (in A) to filter micrograph before displaying", "0"));
+	angpix = textToFloat(parser.getOption("--angpix", "Pixel size (in A) to calculate lowpass filter", "1"));
+	fn_color = parser.getOption("--color_star", "STAR file with a column for red-blue coloring (a subset of) the particles", "");
+	color_label = parser.getOption("--color_label", "MetaDataLabel to color particles on (e.g. rlnParticleSelectZScore)", "");
+	color_blue_value = textToFloat(parser.getOption("--blue", "Value of the blue color", "1."));
+	color_red_value = textToFloat(parser.getOption("--red", "Value of the red color", "0."));
+
+	verb = textToInteger(parser.getOption("--verb", "Verbosity", "1"));
+
+	// Check for errors in the command-line option
+	if (parser.checkForErrors())
+		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+}
+
+void Displayer::usage()
+{
+	parser.writeUsage(std::cerr);
+}
+
+void Displayer::initialise()
+{
+
+	if (!do_gui && fn_in=="")
+		REPORT_ERROR("Displayer::initialise ERROR: either provide --i or --gui");
+    Fl::visual(FL_RGB);
+    // initialise some static variables
+    has_dragged = false;
+    has_shift = false;
+
+    if (do_class)
+    {
+    	display_label = EMDL_MLMODEL_REF_IMAGE;
+    	table_name = "model_classes";
+    	FileName fn_data;
+    	if (fn_in.contains("_half1_model.star"))
+    		fn_data = fn_in.without("_half1_model.star") + "_data.star";
+    	else if (fn_in.contains("_half2_model.star"))
+    		fn_data = fn_in.without("_half2_model.star") + "_data.star";
+    	else
+    		fn_data = fn_in.without("_model.star") + "_data.star";
+    	MDdata.read(fn_data);
+
+    	// If regouping, also read the model_groups table into memory
+    	if (nr_regroups > 0)
+    		MDgroups.read(fn_in, "model_groups");
+    }
+
+    // Also allow regrouping on data.star
+    if (fn_in.contains("_data.star") && nr_regroups > 0)
+    {
+    	FileName fn_model;
+    	fn_model = fn_in.without("_data.star") + "_model.star";
+    	bool has_model = false;
+    	if (exists(fn_model))
+    	{
+    		MDgroups.read(fn_model, "model_groups");
+    		has_model = true;
+    	}
+    	else
+    	{
+    		fn_model = fn_in.without("_data.star") + "_half1_model.star";
+    		if (exists(fn_model))
+    		{
+    			MDgroups.read(fn_model, "model_groups");
+    			has_model = true;
+    		}
+    	}
+    	if (!has_model)
+    		std::cout <<" Warning: cannot find model.star file for " << fn_in << " needed for regrouping..." << std::endl;
+
+    }
+}
+
+int Displayer::runGui()
+{
+	Fl::scheme("gtk+");
+    // Shall I make a browser window in this GUI or in the general relion GUI?
+    // Perhaps here is better..., then there will be no fn_in yet....
+    // Update entire window each time the entry of the browser changes...
+    Fl_File_Chooser chooser(".",                        // directory
+                            "All recognised formats (*.{star,mrc,mrcs})\tSTAR Files (*.star)\tMRC stack (*.mrcs)\tMRC image (*.mrc)\tAll Files (*)*", // filter
+                            Fl_File_Chooser::SINGLE,     // chooser type
+                            "Choose file to display");        // title
+    chooser.show();
+    // Block until user picks something.
+    while(chooser.shown())
+        { Fl::wait(); }
+
+    // User hit cancel?
+    if ( chooser.value() == NULL )
+    	exit(0);
+    FileName _fn_in(chooser.value());
+
+	// make a bigger window for STAR files...
+	int windowheight = _fn_in.isStarFile() ? 350 : 300;
+
+	displayerGuiWindow win(500, windowheight, "Relion display GUI");
+	win.is_class = false;
+	win.is_data = false;
+	win.is_star = false;
+	win.is_multi = false;
+
+	// If this is a STAR file, decide what to do
+	if (_fn_in.isStarFile())
+	{
+		MetaDataTable MD;
+		win.is_star = true;
+		win.is_multi = true;
+		win.is_data = _fn_in.contains("_data.star");
+		if (_fn_in.contains("_model.star"))
+		{
+			win.fn_data = fn_in.without("_model.star") + "_data.star";
+			win.is_class = true;
+			MD.read(_fn_in, "model_classes");
+		}
+		else
+		{
+			MD.read(_fn_in);
+		}
+
+		// Get which labels are stored in this metadatatable and generate choice menus for display and sorting
+
+		for (int ilab = 0; ilab < MD.activeLabels.size(); ilab++)
+		{
+			if (EMDL::isNumber(MD.activeLabels[ilab]))
+				win.sort_labels.push_back(EMDL::label2Str(MD.activeLabels[ilab]));
+		}
+
+		// Preferred order of defaults!
+		// If EMDL_IMAGE_NAME is among the labels: make that the default choice!)
+		if (MD.containsLabel(EMDL_IMAGE_NAME))
+			win.display_labels.push_back(EMDL::label2Str(EMDL_IMAGE_NAME));
+		if (MD.containsLabel(EMDL_MLMODEL_REF_IMAGE))
+			win.display_labels.push_back(EMDL::label2Str(EMDL_MLMODEL_REF_IMAGE));
+		if (MD.containsLabel(EMDL_CTF_IMAGE))
+			win.display_labels.push_back(EMDL::label2Str(EMDL_CTF_IMAGE));
+		if (MD.containsLabel(EMDL_MICROGRAPH_NAME))
+			win.display_labels.push_back(EMDL::label2Str(EMDL_MICROGRAPH_NAME));
+
+
+	}
+	else
+	{
+		// Try reading as an image/stack header
+		Image<double> img;
+		img.read(_fn_in, false);
+		win.is_multi = (ZSIZE(img()) * NSIZE(img()) > 1);
+	}
+
+	win.fill(_fn_in);
+}
+
+
+int Displayer::run()
+{
+    if (do_gui)
+    {
+    }
+    else if (do_pick)
+    {
+
+        Image<double> img;
+        img.read(fn_in); // dont read data yet: only header to get size
+
+        if (lowpass > 0.)
+        	lowPassFilterMap(img(), lowpass, angpix);
+        basisViewerWindow win(CEIL(scale*XSIZE(img())), CEIL(scale*YSIZE(img())), fn_in.c_str());
+        if (fn_coords=="")
+            fn_coords = fn_in.withoutExtension()+"_coords.star";
+        win.fillPickerViewerCanvas(img(), minval, maxval, sigma_contrast, scale, ROUND(scale*particle_radius), fn_coords,
+        		fn_color, fn_in, color_label, color_blue_value, color_red_value);
+    }
+
+    else if (fn_in.isStarFile())
+    {
+        MDin.read(fn_in, table_name);
+        // Check that label to display is present in the table
+        if (!MDin.containsLabel(display_label))
+        	REPORT_ERROR("Cannot find metadata label in input STAR file");
+
+        // Store class number in metadata table
+        if (do_class)
+        {
+			int iclass = 0;
+			FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDin)
+			{
+        		iclass++; // start counting at 1
+        		MDin.setValue(EMDL_PARTICLE_CLASS, iclass);
+        	}
+        }
+
+        if (sort_label != EMDL_UNDEFINED)
+        {
+        	MDin.sort(sort_label, reverse_sort, true); // true means only store sorted_idx!
+        	// When sorting: never read in the whole stacks!
+        	do_read_whole_stacks = false;
+        }
+
+        basisViewerWindow win(MULTIVIEW_WINDOW_WIDTH, MULTIVIEW_WINDOW_HEIGHT, fn_in.c_str());
+        win.fillCanvas(MULTIVIEWER, MDin, display_label, do_read_whole_stacks, do_apply_orient, minval, maxval, sigma_contrast, scale, ori_scale, ncol,
+        		do_class, &MDdata, nr_regroups, fn_in.contains("_data.star"), &MDgroups);
+
+    }
+    else
+    {
+        // Attempt to read a single-file image
+        Image<double> img;
+        img.read(fn_in, false); // dont read data yet: only header to get size
+
+        MDin.clear();
+        // display stacks
+        if (NSIZE(img()) > 1)
+        {
+        	for (int n = 0; n < NSIZE(img()); n++)
+        	{
+        		FileName fn_tmp;
+        		fn_tmp.compose(n+1,fn_in);
+        		MDin.addObject();
+        		MDin.setValue(EMDL_IMAGE_NAME, fn_tmp);
+        	}
+            basisViewerWindow win(MULTIVIEW_WINDOW_WIDTH, MULTIVIEW_WINDOW_HEIGHT, fn_in.c_str());
+            win.fillCanvas(MULTIVIEWER, MDin, EMDL_IMAGE_NAME, true, false, minval, maxval, sigma_contrast, scale, ori_scale, ncol);
+        }
+        else if (ZSIZE(img()) > 1)
+        {
+
+        	// Read volume slices from .mrc as if it were a .mrcs stack and then use normal slice viewer
+        	// This will not work for Spider volumes...
+        	if (fn_in.getFileFormat() != "mrc")
+        		REPORT_ERROR("Displayer::run() ERROR: only MRC maps are allowed...");
+
+        	// Use a single minval and maxval for all slice
+        	if (minval == maxval)
+        	{
+        		Image<double> It;
+        		It.read(fn_in);
+        		It().computeDoubleMinMax(minval, maxval);
+        	}
+
+        	// Trick MD with :mrcs extension....
+        	for (int n = 0; n < ZSIZE(img()); n++)
+        	{
+        		FileName fn_tmp;
+        		fn_tmp.compose(n+1,fn_in);
+        		fn_tmp += ":mrcs";
+        		MDin.addObject();
+        		MDin.setValue(EMDL_IMAGE_NAME, fn_tmp);
+        	}
+
+            basisViewerWindow win(MULTIVIEW_WINDOW_WIDTH, MULTIVIEW_WINDOW_HEIGHT, fn_in.c_str());
+            win.fillCanvas(MULTIVIEWER, MDin, EMDL_IMAGE_NAME, true, false, minval, maxval, sigma_contrast, scale, ori_scale, ncol);
+        }
+        else
+        {
+        	img.read(fn_in); // now read image data as well (not only header)
+
+        	MDin.addObject();
+            MDin.setValue(EMDL_IMAGE_NAME, fn_in);
+            basisViewerWindow win(CEIL(scale*XSIZE(img())), CEIL(scale*YSIZE(img())), fn_in.c_str());
+            win.fillSingleViewerCanvas(img(), minval, maxval, sigma_contrast, scale);
+        }
+
+    }
+
+
+
+}
+
diff --git a/src/displayer.h b/src/displayer.h
new file mode 100644
index 0000000..bdaa4ff
--- /dev/null
+++ b/src/displayer.h
@@ -0,0 +1,490 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef DISPLAYER_H_
+#define DISPLAYER_H_
+
+#include "src/image.h"
+#include "src/metadata_label.h"
+#include "src/metadata_table.h"
+#include <src/matrix2d.h>
+#include <src/fftw.h>
+#include <src/time.h>
+#include <src/args.h>
+
+#include <external/fltk-1.3.0/FL/Fl.H>
+#include <external/fltk-1.3.0/FL/Fl_Shared_Image.H>
+#include <external/fltk-1.3.0/FL/Fl_Double_Window.H>
+#include <external/fltk-1.3.0/FL/Fl_Scroll.H>
+#include <external/fltk-1.3.0/FL/Fl_Image.H>
+#include <external/fltk-1.3.0/FL/Fl_JPEG_Image.H>
+#include <external/fltk-1.3.0/FL/Fl_Box.H>
+#include <external/fltk-1.3.0/FL/fl_draw.H>
+#include <external/fltk-1.3.0/FL/Fl_Menu_Bar.H>
+#include <external/fltk-1.3.0/FL/Fl_File_Chooser.H>
+#include <external/fltk-1.3.0/FL/Fl_Float_Input.H>
+#include <external/fltk-1.3.0/FL/Fl_Text_Display.H>
+
+#define GUI_BACKGROUND_COLOR (fl_rgb_color(240,240,240))
+#define GUI_INPUT_COLOR (fl_rgb_color(255,255,230))
+#define GUI_RUNBUTTON_COLOR (fl_rgb_color(255,80,80))
+
+#define SELECTED true
+#define NOTSELECTED false
+#define MULTIVIEW_WINDOW_WIDTH  720
+#define MULTIVIEW_WINDOW_HEIGHT 486
+
+#define BOX_OFFSET 4
+
+#define MULTIVIEWER 0
+#define SINGLEVIEWER 1
+#define BLACK 0
+#define WHITE 1
+
+static bool has_dragged;
+static int predrag_xc;
+static int predrag_yc;
+static bool has_shift;
+static int preshift_ipos;
+
+class DisplayBox : public Fl_Box
+{
+protected:
+
+	// Draw the actual box on the screen (this function is used by redraw())
+	void draw();
+
+public:
+
+	int xsize_data;
+	int ysize_data;
+	int xoff;
+	int yoff;
+
+	// The box's selection status
+	bool selected;
+
+	// The box's original position in the input MetaDataTable
+	int ipos;
+
+	// The metadata fir this image
+	MetaDataTable MDimg;
+
+	// The actual image data array
+	char * img_data;
+
+	// For getting back close the original image values from the uchar ones...
+	double minval;
+	double maxval;
+	double scale;
+
+	// Constructor with an image and its metadata
+	DisplayBox(int X, int Y, int W, int H, const char *L=0) : Fl_Box(X,Y,W,H,L) { img_data = NULL; MDimg.clear(); }
+
+	void setData(MultidimArray<double> &img, MetaDataContainer *MDCin, int ipos, double minval, double maxval,
+			double _scale, bool do_relion_scale = false);
+
+	// Destructor
+	~DisplayBox()
+	{
+		MDimg.clear();
+		if (img_data)
+			delete [] img_data;
+	};
+
+	// Change selected status, redraw and return new status
+	bool toggleSelect();
+	// Select, redraw and return new selected status
+	bool select();
+	// unSelect, redraw and return new selected status
+	bool unSelect();
+
+};
+
+
+// This class only puts scrollbars around the resizable canvas
+class basisViewerWindow : public Fl_Window
+{
+
+public:
+
+	// Constructor with w x h size of the window and a title
+	basisViewerWindow(int W, int H, const char* title=0): Fl_Window(W, H, title){}
+
+	int fillCanvas(int viewer_type, MetaDataTable &MDin, EMDLabel display_label, bool _do_read_whole_stacks, bool _do_apply_orient,
+			double _minval, double _maxval, double _sigma_contrast,
+			double _scale, double _ori_scale, int _ncol, bool do_class = false, MetaDataTable *MDdata = NULL,
+			int _nr_regroup = -1, bool _is_data = false, MetaDataTable *MDgroups = NULL);
+	int fillSingleViewerCanvas(MultidimArray<double> image, double _minval, double _maxval, double _sigma_contrast, double _scale);
+	int fillPickerViewerCanvas(MultidimArray<double> image, double _minval, double _maxval, double _sigma_contrast, double _scale,
+			int _particle_radius, FileName _fn_coords = "",
+			FileName _fn_color = "", FileName _fn_mic= "", FileName _color_label = "", double _color_blue_value = 0., double _color_red_value = 1.);
+
+
+};
+
+class basisViewerCanvas : public Fl_Widget
+{
+protected:
+
+	void draw();
+
+public:
+
+	int ncol;
+	int nrow;
+	int xsize_box;
+	int ysize_box;
+	int xoff;
+	int yoff;
+
+	// To get positions in scrolled canvas...
+	Fl_Scroll *scroll;
+
+	// All the individual image display boxes
+	std::vector<DisplayBox*> boxes;
+
+	// Read stacks at once to speed up?
+	bool do_read_whole_stacks;
+
+	// Constructor with w x h size of the window and a title
+	basisViewerCanvas(int X,int Y, int W, int H, const char* title=0) : Fl_Widget(X,Y,W, H, title) { }
+
+	void SetScroll(Fl_Scroll *val) { scroll = val; }
+
+	int fill(MetaDataTable &MDin, EMDLabel display_label, bool _do_apply_orient, double _minval, double _maxval,
+			double _sigma_contrast, double _scale, int _ncol);
+	int fill(MultidimArray<double> &image, double _minval, double _maxval, double _sigma_contrast, double _scale = 1.);
+
+private:
+	void getImageContrast(MultidimArray<double> &image, double &minval, double &maxval, double &sigma_contrast);
+
+};
+
+class multiViewerCanvas : public basisViewerCanvas
+{
+protected:
+
+	int handle(int ev);
+
+public:
+
+	// Flag to indicate whether this is a viewer for class averages from 2D/3D relion_refine classification runs
+	bool do_class;
+
+	// Flag to indicate whether this is a viewer for a data.star (to also allow regrouping)
+	bool is_data;
+
+	// Number of groups for regrouping the selected particles (for model.star)
+	int nr_regroups;
+
+	// pointer to the MetaDataTable for the individually aligned particles when do_class (the data.star file)
+	MetaDataTable *MDdata;
+
+	// pointer to the MetaDataTable for the groups when do_class and do_regroup (the data.star file)
+	MetaDataTable *MDgroups;
+
+	// Scale for showing the original image
+	double ori_scale;
+
+	// To know which original image to display
+	EMDLabel display_label;
+
+	// To know which contrast to apply to original image display
+	double sigma_contrast;
+
+	// Constructor with w x h size of the window and a title
+	multiViewerCanvas(int X,int Y, int W, int H, const char* title=0): basisViewerCanvas(X,Y,W, H, title) { }
+
+private:
+
+	// Functionalities for  popup menu
+	void clearSelection();
+	void invertSelection();
+	void selectFromHereBelow(int ipos);
+	void selectFromHereAbove(int ipos);
+	void printMetaData(int ipos);
+	void showAverage(bool selected, bool show_stddev=false);
+	void showOriginalImage(int ipos);
+	void makeStarFileSelectedParticles(bool save_selected, MetaDataTable &MDpart);
+	void saveSelectedParticles(bool save_selected);
+	void showSelectedParticles(bool save_selected);
+	void saveSelected(bool save_selected);
+	void saveBackupSelection();
+	void loadBackupSelection();
+
+};
+
+// Generally accessible function
+void regroupSelectedParticles(MetaDataTable &MDdata, MetaDataTable &MDgroups, int nr_regroups);
+
+class singleViewerCanvas : public basisViewerCanvas
+{
+
+protected:
+	int handle(int ev);
+
+public:
+
+	// Constructor with w x h size of the window and a title
+	singleViewerCanvas(int X, int Y, int W, int H, const char* title=0): basisViewerCanvas(X,Y,W, H, title) { }
+private:
+
+	// Functionalities for  popup menu
+	void printMetaData();
+
+	// explain functionality of clicks
+	void printHelp();
+
+
+};
+
+class pickerViewerCanvas : public basisViewerCanvas
+{
+
+protected:
+	int handle(int ev);
+	void draw();
+
+public:
+	// MetaDataTable with all picked coordinates
+	MetaDataTable MDcoords;
+
+	int particle_radius;
+
+	// Filename of the picked coordinate files
+	FileName fn_coords;
+
+	// FileName of the STAR file that contains the color-based column
+	FileName fn_color;
+
+	// Label to base coloring on
+	EMDLabel color_label;
+
+	// Blue value for coloring
+	double smallest_color_value;
+
+	// Red value for coloring
+	double biggest_color_value;
+
+	// Red->Blue is true; blue->red is false
+	bool do_blue_to_red;
+
+	// Micrograph name (useful to search relevant particles in fn_color)
+	FileName fn_mic;
+
+	// Constructor with w x h size of the window and a title
+	pickerViewerCanvas(int X, int Y, int W, int H, const char* title=0): basisViewerCanvas(X,Y,W, H, title) { }
+
+	void loadCoordinates(bool ask_filename = false);
+
+	// if a fn_zscore is given, then match the coordinates to the Zscores in the corresponding MDtable
+	void findColorColumnForCoordinates();
+
+private:
+
+	// Functionalities for  popup menu
+	void saveCoordinates(bool ask_filename = false);
+	void clearCoordinates();
+	void printHelp();
+	void viewExtractedParticles();
+};
+
+class popupInputWindow : Fl_Window
+{
+	Fl_Input * input;
+	double result;
+public:
+
+	// Constructor with w x h size of the window and a title
+	popupInputWindow(int W, int H, const char* title=0): Fl_Window(W, H, title){}
+
+	int fill(std::string label, double &_result)
+	{
+		input = new Fl_Input(x() + 200, 0, 100, 30, "black value: ") ;
+		Fl_Button * done = new Fl_Button(x()+350, 0, 30, 30, "go!");
+		//*result = atof(input->value());
+		done->callback( cb_done, this);
+		result = _result;
+		show();
+	}
+
+	static void cb_done(Fl_Widget* o, void* v)
+	{
+		popupInputWindow* T=(popupInputWindow*)v;
+	    T->cb_done_i();
+	}
+	inline void cb_done_i()
+	{
+		std::cerr << " input->value()= " << input->value() << std::endl;
+		result =  atof(input->value());
+	}
+
+};
+// This class only puts scrollbars around the resizable canvas
+class displayerGuiWindow : public Fl_Window
+{
+public:
+
+	FileName fn_in, fn_data;
+
+	// Some general settings for different types
+	bool is_class;
+
+	bool is_multi;
+
+	bool is_star;
+
+	// Allow regrouping from _data.star
+	bool is_data;
+
+	// Label option to display or to sort on
+	std::vector<std::string> display_labels;
+	std::vector<std::string> sort_labels;
+
+	// Input for the display parameters
+	Fl_Input *black_input, *white_input, *sigma_contrast_input, *scale_input, *lowpass_input, *angpix_input;
+	Fl_Input *col_input, *ori_scale_input, *particle_radius_input, *pick_rootname_input, *nr_groups_input;
+	Fl_Check_Button *sort_button, *reverse_sort_button, *pick_button, *apply_orient_button, *read_whole_stack_button, *regroup_button;
+	Fl_Choice *display_choice, *sort_choice;
+
+	// Constructor with w x h size of the window and a title
+	displayerGuiWindow(int W, int H, const char* title=0): Fl_Window(W, H, title){}
+
+	// Fill all except for the browser
+	int fill(FileName &fn_in);
+
+private:
+
+	static void cb_display(Fl_Widget*, void*);
+    inline void cb_display_i();
+    void readLastSettings();
+    void writeLastSettings();
+
+};
+
+class Displayer
+{
+public:
+
+	// I/O Parser
+	IOParser parser;
+
+	// Launch the GUI for parameter input
+	bool do_gui;
+
+	// Verbosity
+	int verb;
+
+	// Which metadatalabel to display
+	EMDLabel display_label, sort_label;
+
+	// use reverse order for sorting?
+	bool reverse_sort;
+
+	// Scale factor for displaying
+	double scale;
+
+	// Number of rows for tiled view
+	int nrow, ncol;
+
+	// Apply orientations stored in metadatatable
+	bool do_apply_orient;
+
+	// Scale for showing the original image
+	double ori_scale;
+
+	// Black and white values
+	double minval, maxval;
+
+	// For setting black and white contrast to a specified times the image standard deviation from the mean
+	double sigma_contrast;
+
+	// Particle diameter
+	int particle_radius;
+
+	// Input & Output rootname
+	FileName fn_in;
+
+	// Filename for coordinates star file
+	FileName fn_coords;
+
+	// FileName of the STAR file that contains the color label
+	FileName fn_color;
+
+	// Which column to color on?
+	FileName color_label;
+
+	// Values for blue and red coloring
+	double color_blue_value, color_red_value;
+
+	// Tablename to read from in the input STAR file
+	FileName table_name;
+
+	// Flag to pick
+	bool do_pick;
+
+	// Flag for looking at classes
+	bool do_class;
+
+	// Number of groups for regrouping (negative number is no regrouping)
+	int nr_regroups;
+
+	// Flag for reading whole stacks instead of individual images
+	bool do_read_whole_stacks;
+
+	// data.star metadata (for do_class)
+	MetaDataTable MDdata;
+
+	// model_groups  metadata (for do_class and regrouping)
+	MetaDataTable MDgroups;
+
+	// Input metadata
+	MetaDataTable MDin;
+
+	// For the multiviewer
+	std::vector<DisplayBox*> boxes;
+
+	// Lowpass filter for picker images
+	double lowpass;
+
+	// Pixel size to calculate lowpass filter in Angstroms
+	double angpix;
+
+public:
+	// Read command line arguments
+	void read(int argc, char **argv);
+
+	// Print usage instructions
+	void usage();
+
+	// Initialise some general stuff after reading
+	void initialise();
+
+	// Decide what to do
+	int run();
+
+	// run the GUI
+	int runGui();
+
+};
+
+
+#endif /* DISPLAYER_H_ */
diff --git a/src/error.cpp b/src/error.cpp
new file mode 100644
index 0000000..0712853
--- /dev/null
+++ b/src/error.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+
+
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+#include "src/error.h"
+
+// Object Constructor
+RelionError::RelionError(const std::string &what, const std::string &fileArg, const long lineArg)
+{
+    msg = what;
+    file= fileArg;
+    line=lineArg;
+}
+
+// Show message
+std::ostream& operator << (std::ostream& o, RelionError& XE)
+{
+    o << XE.msg << std::endl
+      << "File: " << XE.file << " line: " << XE.line << std::endl;
+    return o;
+}
diff --git a/src/error.h b/src/error.h
new file mode 100644
index 0000000..de6d8f4
--- /dev/null
+++ b/src/error.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+*
+* Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+*
+* Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+*
+* 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
+*
+*  All comments concerning this program package may be sent to the
+*  e-mail address 'xmipp at cnb.csic.es'
+***************************************************************************/
+
+#ifndef ERROR_H
+#define ERROR_H
+//ROB
+#include <cstdlib>
+
+#include <string>
+#include <iostream>
+
+/** Show message and throw exception
+ * @ingroup ErrorHandling
+ *
+ * This macro shows the given message and exits with the error code.
+ *
+ * @code
+ * if (...)
+ *     REPORT_ERROR("Error 1");
+ * @endcode
+ */
+#define REPORT_ERROR(ErrormMsg) throw RelionError(ErrormMsg, __FILE__, __LINE__)
+
+/** Exception class
+ * @ingroup ErrorHandling
+ *
+ * This is the class type for the errors thrown by the exceptions
+ */
+
+class RelionError
+{
+public:
+    /** Error code */
+    int __errno;
+
+    /** Message shown */
+    std::string msg;
+
+    /** File produstd::cing the error */
+    std::string file;
+
+    /** Line number */
+    long line;
+
+    RelionError(const std::string& what, const std::string &fileArg, const long lineArg);
+    friend std::ostream& operator<<(std::ostream& o, RelionError& XE);
+};
+
+#endif
diff --git a/src/euler.cpp b/src/euler.cpp
new file mode 100644
index 0000000..a39e738
--- /dev/null
+++ b/src/euler.cpp
@@ -0,0 +1,392 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include <iostream>
+#include <math.h>
+
+#include "src/euler.h"
+#include "src/funcs.h"
+
+/* Euler angles --> matrix ------------------------------------------------- */
+void Euler_angles2matrix(double alpha, double beta, double gamma,
+                         Matrix2D<double> &A, bool homogeneous)
+{
+    double ca, sa, cb, sb, cg, sg;
+    double cc, cs, sc, ss;
+
+    if (homogeneous)
+    {
+        A.initZeros(4,4);
+        MAT_ELEM(A,3,3)=1;
+    }
+    else
+        if (MAT_XSIZE(A) != 3 || MAT_YSIZE(A) != 3)
+            A.resize(3, 3);
+
+    alpha = DEG2RAD(alpha);
+    beta  = DEG2RAD(beta);
+    gamma = DEG2RAD(gamma);
+
+    ca = cos(alpha);
+    cb = cos(beta);
+    cg = cos(gamma);
+    sa = sin(alpha);
+    sb = sin(beta);
+    sg = sin(gamma);
+    cc = cb * ca;
+    cs = cb * sa;
+    sc = sb * ca;
+    ss = sb * sa;
+
+    A(0, 0) =  cg * cc - sg * sa;
+    A(0, 1) =  cg * cs + sg * ca;
+    A(0, 2) = -cg * sb;
+    A(1, 0) = -sg * cc - cg * sa;
+    A(1, 1) = -sg * cs + cg * ca;
+    A(1, 2) = sg * sb;
+    A(2, 0) =  sc;
+    A(2, 1) =  ss;
+    A(2, 2) = cb;
+}
+
+/* Euler direction --------------------------------------------------------- */
+void Euler_angles2direction(double alpha, double beta,
+						    Matrix1D<double> &v)
+{
+    double ca, sa, cb, sb;
+    double sc, ss;
+
+    v.resize(3);
+    alpha = DEG2RAD(alpha);
+    beta  = DEG2RAD(beta);
+
+    ca = cos(alpha);
+    cb = cos(beta);
+    sa = sin(alpha);
+    sb = sin(beta);
+    sc = sb * ca;
+    ss = sb * sa;
+
+    v(0) = sc;
+    v(1) = ss;
+    v(2) = cb;
+}
+
+/* Euler direction2angles ------------------------------- */
+//gamma is useless but I keep it for simmetry
+//with Euler_direction
+void Euler_direction2angles(Matrix1D<double> &v0,
+                            double &alpha, double &beta)
+{
+    double abs_ca, sb, cb;
+    double aux_alpha;
+    double aux_beta;
+    double error, newerror;
+    Matrix1D<double> v_aux;
+    Matrix1D<double> v;
+
+    //if not normalized do it so
+    v.resize(3);
+    v = v0;
+    v.selfNormalize();
+
+    v_aux.resize(3);
+    cb = v(2);
+
+    if (fabs((cb)) > 0.999847695)/*one degree */
+    {
+        std::cerr << "\nWARNING: Routine Euler_direction2angles is not reliable\n"
+        "for small tilt angles. Up to 0.001 deg it should be OK\n"
+        "for most applications but you never know";
+    }
+
+    if (fabs((cb - 1.)) < FLT_EPSILON)
+    {
+        alpha = 0.;
+        beta = 0.;
+    }
+    else
+    {/*1*/
+
+        aux_beta = acos(cb); /* beta between 0 and PI */
+
+
+        sb = sin(aux_beta);
+
+        abs_ca = fabs(v(0)) / sb;
+        if (fabs((abs_ca - 1.)) < FLT_EPSILON)
+            aux_alpha = 0.;
+        else
+            aux_alpha = acos(abs_ca);
+
+        v_aux(0) = sin(aux_beta) * cos(aux_alpha);
+        v_aux(1) = sin(aux_beta) * sin(aux_alpha);
+        v_aux(2) = cos(aux_beta);
+
+        error = fabs(dotProduct(v, v_aux) - 1.);
+        alpha = aux_alpha;
+        beta = aux_beta;
+
+        v_aux(0) = sin(aux_beta) * cos(-1. * aux_alpha);
+        v_aux(1) = sin(aux_beta) * sin(-1. * aux_alpha);
+        v_aux(2) = cos(aux_beta);
+        newerror = fabs(dotProduct(v, v_aux) - 1.);
+        if (error > newerror)
+        {
+            alpha = -1. * aux_alpha;
+            beta  = aux_beta;
+            error = newerror;
+        }
+
+        v_aux(0) = sin(-aux_beta) * cos(-1. * aux_alpha);
+        v_aux(1) = sin(-aux_beta) * sin(-1. * aux_alpha);
+        v_aux(2) = cos(-aux_beta);
+        newerror = fabs(dotProduct(v, v_aux) - 1.);
+        if (error > newerror)
+        {
+            alpha = -1. * aux_alpha;
+            beta  = -1. * aux_beta;
+            error = newerror;
+        }
+
+        v_aux(0) = sin(-aux_beta) * cos(aux_alpha);
+        v_aux(1) = sin(-aux_beta) * sin(aux_alpha);
+        v_aux(2) = cos(-aux_beta);
+        newerror = fabs(dotProduct(v, v_aux) - 1.);
+
+        if (error > newerror)
+        {
+            alpha = aux_alpha;
+            beta  = -1. * aux_beta;
+            error = newerror;
+        }
+    }/*else 1 end*/
+    beta  = RAD2DEG(beta);
+    alpha = RAD2DEG(alpha);
+}/*Eulerdirection2angles end*/
+
+/* Matrix --> Euler angles ------------------------------------------------- */
+#define CHECK
+//#define DEBUG_EULER
+void Euler_matrix2angles(const Matrix2D<double> &A, double &alpha,
+                         double &beta, double &gamma)
+{
+    double abs_sb, sign_sb;
+
+    if (MAT_XSIZE(A) != 3 || MAT_YSIZE(A) != 3)
+        REPORT_ERROR( "Euler_matrix2angles: The Euler matrix is not 3x3");
+
+    abs_sb = sqrt(A(0, 2) * A(0, 2) + A(1, 2) * A(1, 2));
+    if (abs_sb > 16*FLT_EPSILON)
+    {
+        gamma = atan2(A(1, 2), -A(0, 2));
+        alpha = atan2(A(2, 1), A(2, 0));
+        if (ABS(sin(gamma)) < FLT_EPSILON)
+            sign_sb = SGN(-A(0, 2) / cos(gamma));
+        // if (sin(alpha)<FLT_EPSILON) sign_sb=SGN(-A(0,2)/cos(gamma));
+        // else sign_sb=(sin(alpha)>0) ? SGN(A(2,1)):-SGN(A(2,1));
+        else
+            sign_sb = (sin(gamma) > 0) ? SGN(A(1, 2)) : -SGN(A(1, 2));
+        beta  = atan2(sign_sb * abs_sb, A(2, 2));
+    }
+    else
+    {
+        if (SGN(A(2, 2)) > 0)
+        {
+            // Let's consider the matrix as a rotation around Z
+            alpha = 0;
+            beta  = 0;
+            gamma = atan2(-A(1, 0), A(0, 0));
+        }
+        else
+        {
+            alpha = 0;
+            beta  = PI;
+            gamma = atan2(A(1, 0), -A(0, 0));
+        }
+    }
+
+    gamma = RAD2DEG(gamma);
+    beta  = RAD2DEG(beta);
+    alpha = RAD2DEG(alpha);
+
+#ifdef double
+
+    Matrix2D<double> Ap;
+    Euler_angles2matrix(alpha, beta, gamma, Ap);
+    if (A != Ap)
+    {
+        std::cout << "---\n";
+        std::cout << "Euler_matrix2angles: I have computed angles "
+        " which doesn't match with the original matrix\n";
+        std::cout << "Original matrix\n" << A;
+        std::cout << "Computed angles alpha=" << alpha << " beta=" << beta
+        << " gamma=" << gamma << std::endl;
+        std::cout << "New matrix\n" << Ap;
+        std::cout << "---\n";
+    }
+#endif
+
+#ifdef DEBUG_EULER
+    std::cout << "abs_sb " << abs_sb << std::endl;
+    std::cout << "A(1,2) " << A(1, 2) << " A(0,2) " << A(0, 2) << " gamma "
+    << gamma << std::endl;
+    std::cout << "A(2,1) " << A(2, 1) << " A(2,0) " << A(2, 0) << " alpha "
+    << alpha << std::endl;
+    std::cout << "sign sb " << sign_sb << " A(2,2) " << A(2, 2)
+    << " beta " << beta << std::endl;
+#endif
+}
+#undef CHECK
+#undef DEBUG
+
+#ifdef NEVERDEFINED
+// Michael's method
+void Euler_matrix2angles(Matrix2D<double> A, double *alpha, double *beta,
+                         double *gamma)
+{
+    double abs_sb;
+
+    if (ABS(A(1, 1)) > FLT_EPSILON)
+    {
+        abs_sb = sqrt((-A(2, 2) * A(1, 2) * A(2, 1) - A(0, 2) * A(2, 0)) / A(1, 1));
+    }
+    else if (ABS(A(0, 1)) > FLT_EPSILON)
+    {
+        abs_sb = sqrt((-A(2, 1) * A(2, 2) * A(0, 2) + A(2, 0) * A(1, 2)) / A(0, 1));
+    }
+    else if (ABS(A(0, 0)) > FLT_EPSILON)
+    {
+        abs_sb = sqrt((-A(2, 0) * A(2, 2) * A(0, 2) - A(2, 1) * A(1, 2)) / A(0, 0));
+    }
+    else
+        EXIT_ERROR(1, "Don't know how to extract angles");
+
+    if (abs_sb > FLT_EPSILON)
+    {
+        *beta  = atan2(abs_sb, A(2, 2));
+        *alpha = atan2(A(2, 1) / abs_sb, A(2, 0) / abs_sb);
+        *gamma = atan2(A(1, 2) / abs_sb, -A(0, 2) / abs_sb);
+    }
+    else
+    {
+        *alpha = 0;
+        *beta  = 0;
+        *gamma = atan2(A(1, 0), A(0, 0));
+    }
+
+    *gamma = rad2deg(*gamma);
+    *beta  = rad2deg(*beta);
+    *alpha = rad2deg(*alpha);
+}
+#endif
+/* Euler up-down correction ------------------------------------------------ */
+void Euler_up_down(double rot, double tilt, double psi,
+                   double &newrot, double &newtilt, double &newpsi)
+{
+    newrot  = rot;
+    newtilt = tilt + 180;
+    newpsi  = -(180 + psi);
+}
+
+/* Same view, differently expressed ---------------------------------------- */
+void Euler_another_set(double rot, double tilt, double psi,
+                       double &newrot, double &newtilt, double &newpsi)
+{
+    newrot  = rot + 180;
+    newtilt = -tilt;
+    newpsi  = -180 + psi;
+}
+
+/* Euler mirror Y ---------------------------------------------------------- */
+void Euler_mirrorY(double rot, double tilt, double psi,
+                   double &newrot, double &newtilt, double &newpsi)
+{
+    newrot  = rot;
+    newtilt = tilt + 180;
+    newpsi  = -psi;
+}
+
+/* Euler mirror X ---------------------------------------------------------- */
+void Euler_mirrorX(double rot, double tilt, double psi,
+                   double &newrot, double &newtilt, double &newpsi)
+{
+    newrot  = rot;
+    newtilt = tilt + 180;
+    newpsi  = 180 - psi;
+}
+
+/* Euler mirror XY --------------------------------------------------------- */
+void Euler_mirrorXY(double rot, double tilt, double psi,
+                    double &newrot, double &newtilt, double &newpsi)
+{
+    newrot  = rot;
+    newtilt = tilt;
+    newpsi  = 180 + psi;
+}
+
+/* Apply a transformation matrix to Euler angles --------------------------- */
+void Euler_apply_transf(const Matrix2D<double> &L,
+                        const Matrix2D<double> &R,
+                        double rot,
+                        double tilt,
+                        double psi,
+                        double &newrot,
+                        double &newtilt,
+                        double &newpsi)
+{
+
+    Matrix2D<double> euler(3, 3), temp;
+    Euler_angles2matrix(rot, tilt, psi, euler);
+    temp = L * euler * R;
+    Euler_matrix2angles(temp, newrot, newtilt, newpsi);
+}
+
+/* Rotate (3D) MultidimArray with 3 Euler angles ------------------------------------- */
+void Euler_rotation3DMatrix(double rot, double tilt, double psi, Matrix2D<double> &result)
+{
+    Euler_angles2matrix(rot, tilt, psi, result, true);
+}
+
+
diff --git a/src/euler.h b/src/euler.h
new file mode 100644
index 0000000..81b08bd
--- /dev/null
+++ b/src/euler.h
@@ -0,0 +1,311 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+*
+* Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+*
+* Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+*
+* 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
+*
+*  All comments concerning this program package may be sent to the
+*  e-mail address 'xmipp at cnb.csic.es'
+***************************************************************************/
+
+#ifndef GEOMETRY_H
+#define GEOMETRY_H
+
+#include "src/multidim_array.h"
+#include "src/transformations.h"
+
+#ifndef FLT_EPSILON
+#define FLT_EPSILON 1.19209e-07
+#endif
+
+/// @name Euler operations
+/// @{
+
+/** Euler angles --> "Euler" matrix
+ *
+ * This function returns the transformation matrix associated to the 3 given
+ * Euler angles (in degrees).
+ *
+ * As an implementation note you might like to know that this function calls
+ * always to Matrix2D::resize
+ *
+ * See http://xmipp.cnb.csic.es/twiki/bin/view/Xmipp/EulerAngles for a
+ * description of the Euler angles.
+ */
+void Euler_angles2matrix(double a, double b, double g, Matrix2D< double >& A,
+                         bool homogeneous=false);
+
+/** Euler angles2direction
+ *
+ * This function returns  a vector parallel to the  projection direction.
+ * Resizes v if needed
+ */
+void Euler_angles2direction(double alpha,
+						 double beta,
+						 Matrix1D< double >& v);
+
+/** Euler direction2angles
+ *
+ * This function returns the 2 Euler angles (rot&tilt) associated to the direction given by
+ * the vector v.
+ */
+void Euler_direction2angles(Matrix1D< double >& v,
+                            double& alpha,
+                            double& beta);
+
+/** "Euler" matrix --> angles
+ *
+ * This function compute a set of Euler angles which result in an "Euler" matrix
+ * as the one given. See \ref Euler_angles2matrix to know more about how this
+ * matrix is computed and what each row means. The result angles are in degrees.
+ * Alpha, beta and gamma are respectively the first, second and third rotation
+ * angles. If the input matrix is not 3x3 then an exception is thrown, the
+ * function doesn't check that the Euler matrix is truly representing a
+ * coordinate system.
+ *
+ * @code
+ * Euler_matrix2angles(Euler, alpha, beta, gamma);
+ * @endcode
+ */
+void Euler_matrix2angles(const Matrix2D< double >& A,
+                         double& alpha,
+                         double& beta,
+                         double& gamma);
+
+/** Up-Down projection equivalence
+ *
+ * As you know a projection view from a point has got its homologous from its
+ * diametrized point in the projection sphere. This function takes a projection
+ * defined by its 3 Euler angles and computes an equivalent set of Euler angles
+ * from which the view is exactly the same but in the other part of the sphere
+ * (if the projection is taken from the bottom then the new projection from the
+ * top, and viceversa). The defined projections are exactly the same except for
+ * a flip over X axis, ie, an up-down inversion. Exactly the correction
+ * performed is:
+ *
+ * @code
+ * newrot = rot;
+ * newtilt = tilt + 180;
+ * newpsi = -(180 + psi);
+ * @endcode
+ *
+ * @code
+ * Euler_up_down(rot, tilt, psi, newrot, newtilt, newpsi);
+ * @endcode
+ */
+void Euler_up_down(double rot,
+                   double tilt,
+                   double psi,
+                   double& newrot,
+                   double& newtilt,
+                   double& newpsi);
+
+/** The same view but differently expressed
+ *
+ * As you know a projection view from a point can be expressed with different
+ * sets of Euler angles. This function gives you another expression of the Euler
+ * angles for this point of view. Exactly the operation performed is:
+ *
+ * @code
+ * newrot = rot + 180;
+ * newtilt = -tilt;
+ * newpsi = -180 + psi;
+ * @endcode
+ *
+ * @code
+ * Euler_another_set(rot, tilt, psi, newrot, newtilt, newpsi);
+ * @endcode
+ */
+void Euler_another_set(double rot,
+                       double tilt,
+                       double psi,
+                       double& newrot,
+                       double& newtilt,
+                       double& newpsi);
+
+/** Mirror over Y axis
+ *
+ * Given a set of Euler angles this function returns a new set which define a
+ * mirrored (over Y axis) version of the former projection.
+ *
+ * @code
+ *  -----> X               X<------
+ *  |                              |
+ *  |                              |
+ *  |               ======>        |
+ *  v                              v
+ *  Y                             Y
+ * @endcode
+ *
+ * The operation performed is
+ *
+ * @code
+ * newrot = rot;
+ * newtilt = tilt + 180;
+ * newpsi = -psi;
+ * @endcode
+ *
+ * @code
+ * Euler_mirrorY(rot, tilt, psi, newrot, newtilt, newpsi);
+ * @endcode
+ */
+void Euler_mirrorY(double rot,
+                   double tilt,
+                   double psi,
+                   double& newrot,
+                   double& newtilt,
+                   double& newpsi);
+
+/** Mirror over X axis
+ *
+ * Given a set of Euler angles this function returns a new set which define a
+ * mirrored (over X axis) version of the former projection.
+ *
+ * @code
+ *  -----> X               Y
+ *  |                       ^
+ *  |                       |
+ *  |               ======> |
+ *  v                       |
+ *  Y                        -----> X
+ * @endcode
+ *
+ * The operation performed is
+ *
+ * @code
+ * newrot = rot;
+ * newtilt = tilt + 180;
+ * newpsi = 180 - psi;
+ * @endcode
+ *
+ * @code
+ * Euler_mirrorX(rot, tilt, psi, newrot, newtilt, newpsi);
+ * @endcode
+ */
+void Euler_mirrorX(double rot,
+                   double tilt,
+                   double psi,
+                   double& newrot,
+                   double& newtilt,
+                   double& newpsi);
+
+/** Mirror over X and Y axes
+ *
+ * Given a set of Euler angles this function returns a new set which define a
+ * mirrored (over X and Y axes at the same time) version of the former
+ * projection.
+ *
+ * @code
+ *  -----> X                       Y
+ *  |                               ^
+ *  |                               |
+ *  |               ======>         |
+ *  v                               |
+ *  Y                        X<-----
+ * @endcode
+ *
+ * The operation performed is
+ *
+ * @code
+ * newrot = rot;
+ * newtilt = tilt;
+ * newpsi = 180 + psi;
+ * @endcode
+ *
+ * @code
+ * Euler_mirrorX(rot, tilt, psi, newrot, newtilt, newpsi);
+ * @endcode
+ */
+void Euler_mirrorXY(double rot,
+                    double tilt,
+                    double psi,
+                    double& newrot,
+                    double& newtilt,
+                    double& newpsi);
+
+/** Apply a geometrical transformation
+ *
+ * The idea behind this function is the following. 3 Euler angles define a point
+ * of view for a projection, but also a coordinate system. You might apply a
+ * geometrical transformation to this system, and then compute back what the
+ * Euler angles for the new system are. This could be used to "mirror" points of
+ * view, rotate them and all the stuff. The transformation matrix must be 3x3
+ * but it must transform R3 vectors into R3 vectors (that is a normal 3D
+ * transformation matrix when vector coordinates are not homogeneous) and it
+ * will be applied in the sense:
+ *
+ * @code
+ * New Euler matrix = L * Old Euler matrix * R
+ * @endcode
+ *
+ * where you know that the Euler matrix rows represent the different system
+ * axes. See Euler_angles2matrix for more information about the Euler coordinate
+ * system.
+ *
+ * @code
+ * Matrix2D< double > R60 = rotation3DMatrix(60, 'Z');
+ * R60.resize(3, 3); // Get rid of homogeneous part
+ * Matrix2D< double > I(3, 3);
+ * I.initIdentity();
+ * Euler_apply_transf(I, R60, rot, tilt, psi, newrot, newtilt, newpsi);
+ * @endcode
+ */
+void Euler_apply_transf(const Matrix2D< double >& L,
+                        const Matrix2D< double >& R,
+                        double rot,
+                        double tilt,
+                        double psi,
+                        double& newrot,
+                        double& newtilt,
+                        double& newpsi);
+
+/** 3D Rotation matrix after 3 Euler angles
+ *
+ * Creates a rotational matrix (4x4) for volumes around the combination of the 3
+ * rotations around ZYZ. All angles are in degrees. You must use it with
+ * IS_NOT_INV in applyGeometry.
+ *
+ * @code
+ * Matrix2D< float > euler = Euler_rotation3DMatrix(60, 30, 60);
+ * @endcode
+ */
+void Euler_rotation3DMatrix(double rot, double tilt, double psi,
+                            Matrix2D<double> &result);
+
+//@}
+
+#endif
diff --git a/src/exp_model.cpp b/src/exp_model.cpp
new file mode 100644
index 0000000..dd61407
--- /dev/null
+++ b/src/exp_model.cpp
@@ -0,0 +1,1122 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/exp_model.h"
+
+void ExpOriginalParticle::addParticle(long int _particle_id, int _random_subset, int _order)
+{
+	// Keep random_subsets equal in each original particle
+	if (random_subset != _random_subset)
+		REPORT_ERROR("ExpOriginalParticle:addParticle: incompatible random subsets between particle and its original particle");
+	particles_id.push_back(_particle_id);
+	particles_order.push_back(_order);
+}
+
+	long int Experiment::numberOfImages(int random_subset)
+{
+	long int result = 0;
+	for (long int i = 0; i < particles.size(); i++)
+		if (random_subset == 0 || particles[i].random_subset == random_subset)
+			result += particles[i].images.size();
+
+	return result;
+}
+
+long int Experiment::numberOfParticles(int random_subset)
+{
+	if (random_subset == 0)
+		return particles.size();
+	else
+	{
+		long int result = 0;
+		for (long int i = 0; i < ori_particles.size(); i++)
+		{
+			if (ori_particles[i].random_subset == random_subset)
+			{
+				result += ori_particles[i].particles_id.size();
+			}
+		}
+		return result;
+	}
+}
+
+long int Experiment::numberOfOriginalParticles(int random_subset)
+{
+	if (random_subset == 0)
+		return ori_particles.size();
+	else if (random_subset == 1)
+		return nr_ori_particles_subset1;
+	else if (random_subset == 2)
+		return nr_ori_particles_subset2;
+	else
+		REPORT_ERROR("ERROR: Experiment::numberOfOriginalParticles invalid random_subset: " + integerToString(random_subset));
+}
+
+
+long int Experiment::numberOfMicrographs()
+{
+	return micrographs.size();
+}
+
+long int Experiment::numberOfGroups()
+{
+	return groups.size();
+}
+
+int Experiment::getNrImagesInSeries(long int part_id)
+{
+//#define DEBUG_CHECKSIZES
+#ifdef DEBUG_CHECKSIZES
+	if (part_id >= particles.size())
+	{
+		std::cerr<< "part_id= "<<part_id<<" particles.size()= "<< particles.size() <<std::endl;
+		REPORT_ERROR("part_id >= particles.size()");
+	}
+#endif
+	return (particles[part_id].images).size();
+}
+
+long int Experiment::getMicrographId(long int part_id, int inseries_no)
+{
+#ifdef DEBUG_CHECKSIZES
+	if (part_id >= particles.size())
+	{
+		std::cerr<< "part_id= "<<part_id<<" particles.size()= "<< particles.size() <<std::endl;
+		REPORT_ERROR("part_id >= particles.size()");
+	}
+	if (inseries_no >= particles[part_id].images.size())
+	{
+		std::cerr<< "inseries_no= "<<inseries_no<<" particles[part_id].images.size()= "<< particles[part_id].images.size() <<std::endl;
+		REPORT_ERROR("inseries_no >= particles[part_id].images.size()]");
+	}
+#endif
+	return (particles[part_id].images[inseries_no]).micrograph_id;
+}
+
+long int Experiment::getGroupId(long int part_id, int inseries_no)
+{
+#ifdef DEBUG_CHECKSIZES
+	if (part_id >= particles.size())
+	{
+		std::cerr<< "part_id= "<<part_id<<" particles.size()= "<< particles.size() <<std::endl;
+		REPORT_ERROR("part_id >= particles.size()");
+	}
+	if (inseries_no >= particles[part_id].images.size())
+	{
+		std::cerr<< "inseries_no= "<<inseries_no<<" particles[part_id].images.size()= "<< particles[part_id].images.size() <<std::endl;
+		REPORT_ERROR("inseries_no >= particles[part_id].images.size()]");
+	}
+#endif
+	return (particles[part_id].images[inseries_no]).group_id;
+}
+
+int Experiment::getRandomSubset(long int part_id)
+{
+	return particles[part_id].random_subset;
+}
+
+long int Experiment::getImageId(long int part_id, int inseries_no)
+{
+	return (particles[part_id].images[inseries_no]).id;
+}
+
+MetaDataTable Experiment::getMetaDataImage(long int part_id, int inseries_no)
+{
+	MetaDataTable result;
+	long int img_id = getImageId(part_id, inseries_no);
+	result.addObject(MDimg.getObject(img_id));
+	return result;
+}
+
+MetaDataTable Experiment::getMetaDataMicrograph(long int part_id, int inseries_no)
+{
+	MetaDataTable result;
+	long int mic_id = getMicrographId(part_id, inseries_no);
+	result.addObject(MDmic.getObject(mic_id));
+	return result;
+}
+
+Matrix2D<double> Experiment::getMicrographTransformationMatrix(long int micrograph_id)
+{
+
+	Matrix2D<double> R(3,3);
+
+	if (MDmic.containsLabel(EMDL_MATRIX_1_1))
+	{
+
+#ifdef DEBUG_CHECKSIZES
+	if (micrograph_id >= MDmic.numberOfObjects())
+	{
+		std::cerr<< "micrograph_id= "<<micrograph_id<<" MDmic.lastObject()= "<< MDmic.lastObject() <<std::endl;
+		REPORT_ERROR("micrograph_id > MDmic.lastObject()");
+	}
+#endif
+		//TODO: default values for getValue
+		MDmic.getValue(EMDL_MATRIX_1_1, R(0,0), micrograph_id);
+		MDmic.getValue(EMDL_MATRIX_1_2, R(0,1), micrograph_id);
+		MDmic.getValue(EMDL_MATRIX_1_3, R(0,2), micrograph_id);
+		MDmic.getValue(EMDL_MATRIX_2_1, R(1,0), micrograph_id);
+		MDmic.getValue(EMDL_MATRIX_2_2, R(1,1), micrograph_id);
+		MDmic.getValue(EMDL_MATRIX_2_3, R(1,2), micrograph_id);
+		MDmic.getValue(EMDL_MATRIX_3_1, R(2,0), micrograph_id);
+		MDmic.getValue(EMDL_MATRIX_3_2, R(2,1), micrograph_id);
+		MDmic.getValue(EMDL_MATRIX_3_3, R(2,2), micrograph_id);
+	}
+	else if (MDmic.containsLabel(EMDL_MICROGRAPH_TILT_ANGLE))
+	{
+#ifdef DEBUG_CHECKSIZES
+	if (micrograph_id >= MDmic.numberOfObjects())
+	{
+		std::cerr<< "micrograph_id= "<<micrograph_id<<" MDmic.lastObject()= "<< MDmic.lastObject() <<std::endl;
+		REPORT_ERROR("micrograph_id > MDmic.lastObject()");
+	}
+#endif
+
+	double tiltdir, tiltangle, outofplane;
+		MDmic.getValue(EMDL_MICROGRAPH_TILT_ANGLE, tiltangle, micrograph_id);
+		// By default tiltdir = 0
+		if (!MDmic.getValue(EMDL_MICROGRAPH_TILT_AXIS_DIRECTION, tiltdir, micrograph_id))
+			tiltdir = 0.;
+		// By default in-plane tilt axis....
+		if (!MDmic.getValue(EMDL_MICROGRAPH_TILT_AXIS_OUTOFPLANE, outofplane, micrograph_id))
+			outofplane= 90.;
+
+		// Transformation matrix
+		// Get the direction of the tilt axis as a Matrix1D
+		Matrix1D<double> dir_axis(3);
+		Euler_angles2direction(tiltdir, outofplane, dir_axis);
+		// Calculate the corresponding 3D rotation matrix
+		rotation3DMatrix(tiltangle, dir_axis, R, false);
+		// Somehow have to take the inverse of that...
+		R = R.inv();
+	}
+	else
+	{
+		R.initIdentity();
+	}
+
+	return R;
+}
+
+Matrix2D<double> Experiment::getMicrographTransformationMatrix(long int part_id, int inseries_no)
+{
+	long int mic_id = getMicrographId(part_id, inseries_no);
+	return getMicrographTransformationMatrix(mic_id);
+}
+
+
+long int Experiment::addImage(long int group_id, long int micrograph_id, long int particle_id)
+{
+
+	if (group_id >= groups.size())
+		REPORT_ERROR("Experiment::addImage: group_id out of range");
+
+	if (micrograph_id >= micrographs.size())
+		REPORT_ERROR("Experiment::addImage: micrograph_id out of range");
+
+	if (particle_id >= particles.size())
+	{
+		std::cerr << " particle_id= " << particle_id << " particles.size()= " << particles.size() << std::endl;
+		REPORT_ERROR("Experiment::addImage: particle_id out of range");
+	}
+
+	ExpImage image;
+	image.group_id = group_id;
+	image.micrograph_id = micrograph_id;
+	image.particle_id = particle_id;
+	// Add new entry in the MDimg MetaDataTable of this Experiment, and get image.id
+	image.id = MDimg.addObject();
+
+	// add this ExpImage to the ExpParticle and the ExpMicrograph
+	(micrographs[micrograph_id].images).push_back(image);
+	(particles[particle_id].images).push_back(image);
+
+	return image.id;
+
+}
+
+long int Experiment::addParticle(std::string part_name, int random_subset)
+{
+
+	ExpParticle particle;
+	particle.id = particles.size();
+	particle.random_subset = random_subset;
+	particle.name = part_name;
+	// Push back this particle in the particles vector
+	particles.push_back(particle);
+
+	// Return the id in the particles vector
+	return particle.id;
+
+}
+
+long int Experiment::addOriginalParticle(std::string part_name, int _random_subset)
+{
+
+	ExpOriginalParticle ori_particle;
+	ori_particle.random_subset = _random_subset;
+	ori_particle.name = part_name;
+	long int id = ori_particles.size();
+	ori_particles.push_back(ori_particle);
+
+	// Return the id in the ori_particles vector
+	return id;
+
+}
+
+long int Experiment::addGroup(std::string group_name)
+{
+	// Add new entry in the MDmic MetaDataTable of this Experiment
+	ExpGroup group;
+	group.id = groups.size(); // start counting groups at 0!
+	group.name = group_name;
+
+	// Push back this micrograph
+	groups.push_back(group);
+
+	// Return the id in the micrographs vector
+	return group.id;
+
+}
+
+long int Experiment::addAverageMicrograph(std::string avg_mic_name)
+{
+	// Add new entry in the MDmic MetaDataTable of this Experiment
+	AverageMicrograph micrograph;
+	micrograph.id = average_micrographs.size();
+	micrograph.name = avg_mic_name;
+
+	// Push back this micrograph
+	average_micrographs.push_back(micrograph);
+
+	// Return the id in the micrographs vector
+	return micrograph.id;
+
+}
+
+long int Experiment::addMicrograph(std::string mic_name)
+{
+	// Add new entry in the MDmic MetaDataTable of this Experiment
+	ExpMicrograph micrograph;
+	micrograph.id = MDmic.addObject();
+	micrograph.name = mic_name;
+
+	// Push back this micrograph
+	micrographs.push_back(micrograph);
+
+	// Return the id in the micrographs vector
+	return micrograph.id;
+
+}
+
+void Experiment::divideOriginalParticlesInRandomHalves(int seed)
+{
+
+	// Only do this if the random_subset of all original_particles is zero
+	bool all_are_zero = true;
+	bool some_are_zero = false;
+	nr_ori_particles_subset1 = 0;
+	nr_ori_particles_subset2 = 0;
+	for (long int i = 0; i < ori_particles.size(); i++)
+	{
+		int random_subset = ori_particles[i].random_subset;
+		if (random_subset != 0)
+		{
+			all_are_zero = false;
+			// Keep track of how many particles there are in each subset
+			if (random_subset == 1)
+				nr_ori_particles_subset1++;
+			else if (random_subset == 2)
+				nr_ori_particles_subset2++;
+			else
+				REPORT_ERROR("ERROR Experiment::divideParticlesInRandomHalves: invalid number for random subset (i.e. not 1 or 2): " + integerToString(random_subset));
+		}
+		else
+			some_are_zero = true;
+
+		if (!all_are_zero && some_are_zero)
+			REPORT_ERROR("ERROR Experiment::divideParticlesInRandomHalves: some random subset values are zero and others are not. They should all be zero, or all bigger than zero!");
+	}
+
+	//std::cerr << " all_are_zero= " << all_are_zero << " some_are_zero= " << some_are_zero << std::endl;
+
+	if (all_are_zero)
+	{
+		// Only randomise them if the random_subset values were not read in from the STAR file
+		srand(seed);
+		for (long int i = 0; i < ori_particles.size(); i++)
+		{
+			int random_subset = rand() % 2 + 1;
+			ori_particles[i].random_subset = random_subset; // randomly 1 or 2
+			if (random_subset == 1)
+				nr_ori_particles_subset1++;
+			else if (random_subset == 2)
+				nr_ori_particles_subset2++;
+			else
+				REPORT_ERROR("ERROR Experiment::divideParticlesInRandomHalves: invalid number for random subset (i.e. not 1 or 2): " + integerToString(random_subset));
+
+			// Loop over all particles in each ori_particle and set their random_subset
+			// Also set the EMDL_PARTICLE_RANDOM_SUBSET in the MDimg of all images for this particle
+			for (long int j = 0; j < ori_particles[i].particles_id.size(); j++)
+			{
+				long int part_id = (ori_particles[i]).particles_id[j];
+				{
+					particles[part_id].random_subset = random_subset;
+					for (long int n = 0; n < (particles[part_id]).images.size(); n++)
+					{
+						long int img_id = ((particles[part_id]).images[n]).id;
+						MDimg.setValue(EMDL_PARTICLE_RANDOM_SUBSET, random_subset, img_id);
+					}
+				}
+			}
+		}
+	}
+}
+
+void Experiment::randomiseOriginalParticlesOrder(int seed, bool do_split_random_halves)
+{
+	//This static flag is for only randomize once
+	static bool randomised = false;
+	if (!randomised)
+	{
+
+		srand(seed);
+		std::vector<ExpOriginalParticle> new_ori_particles;
+
+		if (do_split_random_halves)
+		{
+			std::vector<long int> ori_particle_list1, ori_particle_list2;
+			ori_particle_list1.clear();
+			ori_particle_list2.clear();
+			// Fill the two particle lists
+			for (long int i = 0; i < ori_particles.size(); i++)
+			{
+				int random_subset = ori_particles[i].random_subset;
+				if (random_subset == 1)
+					ori_particle_list1.push_back(i);
+				else if (random_subset == 2)
+					ori_particle_list2.push_back(i);
+				else
+					REPORT_ERROR("ERROR Experiment::randomiseParticlesOrder: invalid number for random subset (i.e. not 1 or 2): " + integerToString(random_subset));
+			}
+
+			// Just a silly check for the sizes of the ori_particle_lists (to be sure)
+			if (ori_particle_list1.size() != nr_ori_particles_subset1)
+				REPORT_ERROR("ERROR Experiment::randomiseParticlesOrder: invalid ori_particle_list1 size:" + integerToString(ori_particle_list1.size()) + " != " + integerToString(nr_ori_particles_subset1));
+			if (ori_particle_list2.size() != nr_ori_particles_subset2)
+				REPORT_ERROR("ERROR Experiment::randomiseParticlesOrder: invalid ori_particle_list2 size:" + integerToString(ori_particle_list2.size()) + " != " + integerToString(nr_ori_particles_subset2));
+
+			// Randomise the two particle lists
+			std::random_shuffle(ori_particle_list1.begin(), ori_particle_list1.end());
+			std::random_shuffle(ori_particle_list2.begin(), ori_particle_list2.end());
+
+			// First fill new_ori_particles with the first subset, then with the second
+			for (long int i = 0; i < ori_particle_list1.size(); i++)
+				new_ori_particles.push_back(ori_particles[ori_particle_list1[i]]);
+			for (long int i = 0; i < ori_particle_list2.size(); i++)
+				new_ori_particles.push_back(ori_particles[ori_particle_list2[i]]);
+
+		}
+		else
+		{
+
+			// First fill in order
+			std::vector<long int> ori_particle_list;
+			ori_particle_list.resize(ori_particles.size());
+			for (long int i = 0; i < ori_particle_list.size(); i++)
+				ori_particle_list[i] = i;
+
+			// Randomise
+			std::random_shuffle(ori_particle_list.begin(), ori_particle_list.end());
+
+			// Refill new_ori_particles
+			for (long int i = 0; i < ori_particle_list.size(); i++)
+				new_ori_particles.push_back(ori_particles[ori_particle_list[i]]);
+		}
+
+		ori_particles=new_ori_particles;
+		randomised = true;
+
+	}
+}
+
+int Experiment::maxNumberOfImagesPerOriginalParticle(long int first_ori_particle_id, long int last_ori_particle_id)
+{
+
+	// By default search all particles
+	if (first_ori_particle_id < 0)
+		first_ori_particle_id = 0;
+	if (last_ori_particle_id < 0)
+		last_ori_particle_id = ori_particles.size() - 1;
+
+	int result = 0;
+	for (long int i = first_ori_particle_id; i <= last_ori_particle_id; i++)
+	{
+		// Loop over all particles in this ori_particle
+		for (int j = 0; j < ori_particles[i].particles_id.size(); j++)
+		{
+			long int part_id = ori_particles[i].particles_id[j];
+			int val = getNrImagesInSeries(part_id);
+			if (val > result)
+				result = val;
+
+		}
+	}
+	return result;
+
+}
+void Experiment::expandToMovieFrames(FileName fn_data_movie)
+{
+
+	MetaDataTable MDmovie;
+	MDmovie.read(fn_data_movie);
+	if (!MDmovie.containsLabel(EMDL_MICROGRAPH_NAME) || !MDmovie.containsLabel(EMDL_PARTICLE_NAME))
+		REPORT_ERROR("Experiment::expandToMovieFrames Error: movie metadata file does not contain rlnMicrographName as well as rlnParticleName");
+
+	// Re-build new Experiment Exp_movie from scratch
+	Experiment Exp_movie;
+
+	// Make a temporary vector of all image names in the current Experiment to gain speed
+	std::vector<FileName> fn_curr_imgs, fn_curr_groups;
+	std::vector<int> count_frames;
+	std::vector<long int> pointer_current_idx;
+	FileName fn_curr_img;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDimg)
+	{
+		MDimg.getValue(EMDL_IMAGE_NAME, fn_curr_img);
+		long int group_id;
+		MDimg.getValue(EMDL_MLMODEL_GROUP_NO, group_id);
+		fn_curr_imgs.push_back(fn_curr_img);
+		fn_curr_groups.push_back(groups[group_id-1].name);
+		count_frames.push_back(0);
+	}
+
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDmovie)
+	{
+		long int group_id, mic_id, part_id, image_id;
+		int my_random_subset, my_class;
+		double rot, tilt, psi, xoff, yoff;
+		FileName fn_movie_part, fn_curr_img, group_name;
+		MDmovie.getValue(EMDL_PARTICLE_NAME, fn_movie_part);
+
+		bool have_found = false;
+		for (long int idx = 0; idx < fn_curr_imgs.size(); idx++)
+		{
+			// Found a match
+			if (fn_curr_imgs[idx] == fn_movie_part)
+			{
+				// Now get the angles from the current Experiment
+				MDimg.getValue(EMDL_ORIENT_ROT, rot, idx);
+				MDimg.getValue(EMDL_ORIENT_TILT, tilt, idx);
+				MDimg.getValue(EMDL_ORIENT_PSI, psi, idx);
+				MDimg.getValue(EMDL_ORIENT_ORIGIN_X, xoff, idx);
+				MDimg.getValue(EMDL_ORIENT_ORIGIN_Y, yoff, idx);
+				MDimg.getValue(EMDL_PARTICLE_CLASS, my_class, idx);
+				// Also get the random subset (if present)
+				if (!MDimg.getValue(EMDL_PARTICLE_RANDOM_SUBSET, my_random_subset, idx))
+					my_random_subset = 0;
+
+				// count how many frames are measured for each particle
+				count_frames[idx]++;
+				// Also keep track to which particle each image in MDmovie belongs
+				pointer_current_idx.push_back(idx);
+				group_name = fn_curr_groups[idx];
+				have_found = true;
+				break;
+			}
+
+		}
+
+		// Only include particles that were already in the current Experiment
+		if (have_found)
+		{
+			// Add new micrographs or get mic_id for existing micrograph
+			FileName mic_name;
+			MDmovie.getValue(EMDL_MICROGRAPH_NAME, mic_name);
+
+			// If this micrograph did not exist in the Exp_movie yet, add it to the Exp_movie experiment
+			mic_id = -1;
+			for (long int i = 0; i < Exp_movie.micrographs.size(); i++)
+			{
+				if (Exp_movie.micrographs[i].name == mic_name)
+				{
+					mic_id = Exp_movie.micrographs[i].id;
+					break;
+				}
+			}
+			if (mic_id < 0)
+				mic_id = Exp_movie.addMicrograph(mic_name);
+
+
+			// Add frameno@ to existing group names, so that separate weighting may be applied to different dose images
+			// NO THIS HAS NO SENSE IF WE'RE ONLY DOING ONE ITERATION ANYWAY!!! THEN IT'S JUST A WASTE OF MEMORY....
+			//std::string dum;
+			//long int frameno;
+			//mic_name.decompose(frameno, dum);
+			//group_name.compose(frameno, group_name, 4);
+
+			// If this group did not exist yet, add it to the experiment
+			group_id = -1;
+			for (long int i = 0; i < Exp_movie.groups.size(); i++)
+			{
+				if (Exp_movie.groups[i].name == group_name)
+				{
+					group_id = Exp_movie.groups[i].id;
+					break;
+				}
+			}
+			if (group_id < 0)
+				group_id = Exp_movie.addGroup(group_name);
+
+			// Create a new particle
+			std::string part_name;
+			part_name= integerToString( Exp_movie.particles.size() + 1); // start counting at 1
+			part_id = Exp_movie.addParticle(part_name, my_random_subset);
+
+			image_id = Exp_movie.addImage(group_id, mic_id, part_id);
+			// Copy the current row of MDimgin into the current row of MDimg
+			Exp_movie.MDimg.setObject(MDmovie.getObject(), image_id);
+
+			// Set the orientations
+			Exp_movie.MDimg.setValue(EMDL_ORIENT_ROT, rot, image_id);
+			Exp_movie.MDimg.setValue(EMDL_ORIENT_TILT, tilt, image_id);
+			Exp_movie.MDimg.setValue(EMDL_ORIENT_PSI, psi, image_id);
+			Exp_movie.MDimg.setValue(EMDL_ORIENT_ORIGIN_X, xoff, image_id);
+			Exp_movie.MDimg.setValue(EMDL_ORIENT_ORIGIN_Y, yoff, image_id);
+			// Now also set the priors on the orientations equal to the orientations from the averages
+			Exp_movie.MDimg.setValue(EMDL_ORIENT_ROT_PRIOR, rot, image_id);
+			Exp_movie.MDimg.setValue(EMDL_ORIENT_TILT_PRIOR, tilt, image_id);
+			Exp_movie.MDimg.setValue(EMDL_ORIENT_PSI_PRIOR, psi, image_id);
+			Exp_movie.MDimg.setValue(EMDL_ORIENT_ORIGIN_X_PRIOR, xoff, image_id);
+			Exp_movie.MDimg.setValue(EMDL_ORIENT_ORIGIN_Y_PRIOR, yoff, image_id);
+			Exp_movie.MDimg.setValue(EMDL_PARTICLE_CLASS, my_class, image_id);
+			Exp_movie.MDimg.setValue(EMDL_PARTICLE_RANDOM_SUBSET, my_random_subset, image_id);
+			// Set normcorrection to 1
+			double norm = 1.;
+			Exp_movie.MDimg.setValue(EMDL_IMAGE_NORM_CORRECTION, norm);
+
+			// Get the rlnParticleName and set this into rlnOriginalParticleName to prevent re-reading of this file to be handled differently..
+			FileName fn_ori_part;
+			Exp_movie.MDimg.getValue(EMDL_PARTICLE_NAME, fn_ori_part, image_id);
+			Exp_movie.MDimg.setValue(EMDL_PARTICLE_ORI_NAME, fn_ori_part, image_id);
+			// Set the particle number in its new rlnParticleName
+			Exp_movie.MDimg.setValue(EMDL_PARTICLE_NAME, part_name, image_id);
+			// Set the new group name
+			Exp_movie.MDimg.setValue(EMDL_MLMODEL_GROUP_NAME, group_name);
+
+
+			// Add ExpOriParticles
+			// If this ori_particle did not exist in the Exp_movie yet, add it to the Exp_movie experiment
+			long int ori_part_id = -1;
+			for (long int i = 0; i < Exp_movie.ori_particles.size(); i++)
+			{
+				if (Exp_movie.ori_particles[i].name == fn_ori_part)
+				{
+					ori_part_id = i;
+					break;
+				}
+			}
+			// If no ExpOriParticles with this name was found, then add new one
+			if (ori_part_id < 0)
+				ori_part_id = Exp_movie.addOriginalParticle(fn_ori_part, my_random_subset);
+			// Add this particle to the OriginalParticle
+			// get Number from mic_name (-1 if empty mic_name, or no @ in mic_name)
+			std::string fnt;
+			long int my_order;
+			mic_name.decompose(my_order, fnt);
+			(Exp_movie.ori_particles[ori_part_id]).addParticle(part_id, my_random_subset, my_order);
+
+		}
+	}
+
+	if (Exp_movie.MDimg.numberOfObjects() == 0)
+		REPORT_ERROR("Experiment::expandToMovieFrames: ERROR: no movie frames selected. Check filenames of micrographs, movies and particle stacks!");
+
+	// Now that all particles from MDmovie have been parsed, set nr_frames per particle in the metadatatable
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(Exp_movie.MDimg)
+	{
+		Exp_movie.MDimg.setValue(EMDL_PARTICLE_NR_FRAMES, count_frames[(pointer_current_idx[current_object])]);
+	}
+
+	// Now replace the current Experiment with Exp_movie
+	(*this) = Exp_movie;
+
+	// Order the particles in each ori_particle
+	orderParticlesInOriginalParticles();
+
+
+}
+void Experiment::orderParticlesInOriginalParticles()
+{
+	// If the orders are negative (-1) then dont sort anything
+	if (ori_particles[0].particles_order[0] < 0)
+		return;
+
+	for (long int i = 0; i < ori_particles.size(); i++)
+	{
+		int nframe = ori_particles[i].particles_order.size();
+
+		std::vector<std::pair<long int, long int> > vp;
+        vp.reserve(nframe);
+        for (long int j = 0; j < nframe; j++)
+        	vp.push_back(std::make_pair(ori_particles[i].particles_order[j], j));
+        // Sort on the first elements of the pairs
+        std::sort(vp.begin(), vp.end());
+
+        // tmp copy of particles_id
+        std::vector<long int> _particles_id = ori_particles[i].particles_id;
+        for (int j = 0; j < nframe; j++)
+			ori_particles[i].particles_id[j] = _particles_id[vp[j].second];
+
+		// We now no longer need the particles_order vector, clear it to save memory
+		ori_particles[i].particles_order.clear();
+	}
+
+}
+
+void Experiment::getAverageMicrographs()
+{
+
+	// Loop over all ori_particles and group in identical AverageMicrographs
+	// Recognize identical AverageMicrographs, by common MicrographNames AFTER the "@" sign
+	// This will only work for movie-processing, where the rlnMicrographName indeed contains an "@"
+
+	average_micrographs.clear();
+	for (long int i = 0; i < ori_particles.size(); i++)
+	{
+		// Get the first particle (i.e. movie-frame) from this original_particle (i.e. movie)
+		long int part_id = ori_particles[i].particles_id[0];
+		// The micrograph_id from the first image of the first particle (movie-particles only have 1 image/particle!!!!)
+		// This whole series-stuff is not turning out to be extremely useful yet....
+		long int mic_id = getMicrographId(part_id, 0);
+		FileName mic_name = micrographs[mic_id].name;
+		std::string avg_mic_name;
+		long int frame_nr;
+		// Get the part AFTER the "@" sign
+		mic_name.decompose(frame_nr, avg_mic_name);
+		// If this micrograph did not exist yet, add it to the experiment
+		long int avg_mic_id = -1;
+		for (long int ii = average_micrographs.size() - 1; ii >= 0; ii--) // search backwards to find match faster
+		{
+			if (average_micrographs[ii].name == avg_mic_name)
+			{
+				avg_mic_id = micrographs[ii].id;
+				break;
+			}
+		}
+		if (avg_mic_id < 0)
+		{
+			avg_mic_id = addAverageMicrograph(avg_mic_name);
+		}
+
+		// Add this OriginalParticle to the AverageMicrograph
+		average_micrographs[avg_mic_id].ori_particles_id.push_back(i);
+	}
+
+}
+
+void Experiment::usage()
+{
+	std::cout
+	<< "  -i                     : Starfile with input images\n"
+	;
+}
+
+// Read from file
+void Experiment::read(FileName fn_exp, bool do_ignore_particle_name)
+{
+
+//#define DEBUG_READ
+#ifdef DEBUG_READ
+	std::cerr << "Entering Experiment::read" << std::endl;
+	char c;
+#endif
+
+	// Initialize by emptying everything
+	clear();
+	MetaDataTable MDmicin, MDimgin;
+	long int group_id, mic_id, part_id, image_id;
+
+	if (!fn_exp.isStarFile())
+	{
+		// Read images from stack. Ignore all metadata, just use filenames
+		// Add a single Micrograph
+		group_id = addGroup("group");
+		mic_id = addMicrograph("micrograph");
+
+		// Check that a MRC stack ends in .mrcs, not .mrc (which will be read as a MRC 3D map!)
+		if (fn_exp.contains(".mrc") && !fn_exp.contains(".mrcs"))
+			REPORT_ERROR("Experiment::read: ERROR: MRC stacks of 2D images should be have extension .mrcs, not .mrc!");
+
+		// Read in header-only information to get the NSIZE of the stack
+		Image<double> img;
+		img.read(fn_exp, false); // false means skip data, only read header
+
+		for (long int n = 0; n <  NSIZE(img()); n++)
+		{
+			FileName fn_img;
+			fn_img.compose(n+1, fn_exp); // fn_img = integerToString(n) + "@" + fn_exp;
+			// Add the particle to my_area = 0
+			part_id = addParticle("particle");
+			// Add this image to the area
+			image_id = addImage(group_id, mic_id, part_id);
+			// Also add OriginalParticle
+			(ori_particles[addOriginalParticle("particle")]).addParticle(part_id, 0, -1);
+
+			// Set the filename and other metadata parameters
+			MDimg.setValue(EMDL_IMAGE_NAME, fn_img, image_id);
+		}
+
+	}
+	else
+	{
+		// Read all metadata from a STAR file
+		bool contains_images_block;
+
+		// First try reading a data_images block into MDimgin (as written by Experiment::write() )
+		MDimgin.read(fn_exp, "images");
+		// If that did not work, try reading the first data-block in the file
+		if (MDimgin.isEmpty())
+		{
+			MDimgin.read(fn_exp);
+			contains_images_block = false;
+		}
+		else
+		{
+			contains_images_block = true;
+		}
+
+#ifdef DEBUG_READ
+	std::cerr << "Done reading MDimgin" << std::endl;
+	std::cerr << "Press any key to continue..." << std::endl;
+	std::cin >> c;
+#endif
+
+		// If there is no EMDL_MICROGRAPH_NAME, then just use a single group and micrograph
+		if (!MDimgin.containsLabel(EMDL_MICROGRAPH_NAME))
+		{
+			group_id = addGroup("group");
+			mic_id = addMicrograph("micrograph");
+		}
+
+		// Now Loop over all objects in the metadata file and fill the logical tree of the experiment
+#ifdef DEBUG_READ
+		std::cerr << " sizeof(int)= " << sizeof(int) << std::endl;
+		std::cerr << " sizeof(long int)= " << sizeof(long int) << std::endl;
+		std::cerr << " sizeof(double)= " << sizeof(double) << std::endl;
+		std::cerr << " sizeof(ExpImage)= " << sizeof(ExpImage) << std::endl;
+		std::cerr << " sizeof(ExpParticle)= " << sizeof(ExpParticle) << std::endl;
+		std::cerr << " sizeof(ExpMicrograph)= " << sizeof(ExpMicrograph) << std::endl;
+		std::cerr << " sizeof(std::vector<long int>)= " << sizeof(std::vector<long int>) << std::endl;
+		long int nr_read = 0;
+
+#endif
+		// Reserve the same number of particles as there are images in MDimgin
+		particles.reserve(MDimgin.size() * (sizeof(ExpParticle) + sizeof(ExpImage)));
+		// TODO precalculate this somehow?! ARE THESE RESERVES NECESSARY ANYWAY???!!!
+		micrographs.reserve(4000);
+
+#ifdef DEBUG_READ
+		std::cerr << "Done reserving" << std::endl;
+		std::cerr << "Press any key to continue..." << std::endl;
+		std::cin >> c;
+#endif
+
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDimgin)
+		{
+
+			// Add new micrographs or get mic_id for existing micrograph
+			FileName mic_name="", group_name="";
+			if (MDimgin.containsLabel(EMDL_MICROGRAPH_NAME))
+			{
+				MDimgin.getValue(EMDL_MICROGRAPH_NAME, mic_name);
+
+				// If this micrograph did not exist yet, add it to the experiment
+				mic_id = -1;
+				for (long int i = micrographs.size() - 1; i >= 0; i--) // search backwards to find match faster
+				{
+					if (micrographs[i].name == mic_name)
+					{
+						mic_id = micrographs[i].id;
+						break;
+					}
+				}
+				if (mic_id < 0)
+					mic_id = addMicrograph(mic_name);
+
+				// Check whether there is a group label, if not use a group for each micrograph
+				if (MDimgin.containsLabel(EMDL_MLMODEL_GROUP_NAME))
+				{
+					MDimgin.getValue(EMDL_MLMODEL_GROUP_NAME, group_name);
+				}
+				else
+				{
+					group_name = mic_name;
+				}
+				// If this group did not exist yet, add it to the experiment
+				group_id = -1;
+				for (long int i = groups.size() - 1; i >= 0; i--) // search backwards to find match faster
+				{
+					if (groups[i].name == group_name)
+					{
+						group_id = groups[i].id;
+						break;
+					}
+				}
+				if (group_id < 0)
+					group_id = addGroup(group_name);
+			}
+			else
+			{
+				// All images belong to the same micrograph
+				mic_id = 0;
+				group_id = 0;
+			}
+
+			// If there is an EMDL_PARTICLE_RANDOM_SUBSET entry in the input STAR-file, then set the random_subset, otherwise use defualt (0)
+			int my_random_subset;
+			if (!MDimgin.getValue(EMDL_PARTICLE_RANDOM_SUBSET, my_random_subset))
+				my_random_subset = 0;
+
+			// Add this image to an existing particle, or create a new particle
+			std::string part_name;
+			if (MDimgin.containsLabel(EMDL_PARTICLE_NAME) && !do_ignore_particle_name)
+			{
+				MDimgin.getValue(EMDL_PARTICLE_NAME, part_name);
+				// Check whether this particle already exists
+				part_id = -1;
+				for (long int i = particles.size() - 1; i >= 0; i--) // search backwards to find match faster
+				{
+					if (particles[i].name == part_name)
+					{
+						part_id = particles[i].id;
+						break;
+					}
+				}
+				// If no particle with this name was found, then add new one
+				if (part_id < 0)
+				{
+					part_id = addParticle(part_name, my_random_subset);
+				}
+			}
+			else
+			{
+				// If particleName is not in the input metadata file, call this particle by the image number
+				part_name= integerToString(particles.size());
+				part_id = addParticle(part_name, my_random_subset);
+			}
+
+			// Add this particle to an existing OriginalParticle, or create a new OriginalParticle
+			long int ori_part_id = -1;
+			if (MDimgin.containsLabel(EMDL_PARTICLE_ORI_NAME))
+			{
+				MDimgin.getValue(EMDL_PARTICLE_ORI_NAME, part_name);
+				for (long int i = ori_particles.size() - 1; i >= 0; i--)  // search backwards to find match faster
+				{
+					if (ori_particles[i].name == part_name)
+					{
+						ori_part_id = i;
+						break;
+					}
+				}
+
+				// If no OriginalParticles with this name was found, then add new one
+				if (ori_part_id < 0)
+					ori_part_id = addOriginalParticle(part_name, my_random_subset);
+
+			}
+			else
+			{
+				// If there are no EMDL_PARTICLE_ORI_NAME in the input file: just one particle per OriginalParticle
+				ori_part_id = addOriginalParticle(part_name, my_random_subset);
+			}
+
+			// Add this particle to the OriginalParticle
+			std::string fnt;
+			long int my_order;
+			mic_name.decompose(my_order, fnt);
+			(ori_particles[ori_part_id]).addParticle(part_id, my_random_subset, my_order);
+
+			long int img_id = addImage(group_id, mic_id, part_id);
+			// Copy the current row of MDimgin into the current row of MDimg
+			MDimg.setObject(MDimgin.getObject(), img_id);
+
+			// The group number is only set upon reading: it is not read from the STAR file itself,
+			// there the only thing that matters is the order of the micrograph_names
+			// Write igroup+1, to start numbering at one instead of at zero
+			MDimg.setValue(EMDL_MLMODEL_GROUP_NO, group_id + 1, img_id);
+
+#ifdef DEBUG_READ
+			nr_read++;
+#endif
+		} // end loop over all objects in MDimgin
+
+#ifdef DEBUG_READ
+		std::cerr << " MDimg.lastObject()= " << MDimg.lastObject() << std::endl;
+		std::cerr << " nr_read= " << nr_read << " particles.size()= " << particles.size() << " micrographs.size()= " << micrographs.size();
+#endif
+
+		// Now, if this file was created by this class then also fill MDmic:
+		if (contains_images_block)
+		{
+			MDmicin.read(fn_exp, "micrographs");
+			if (!MDmicin.isEmpty())
+			{
+				std::vector<std::string> found_mic_names;
+				FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDmicin)
+				{
+					std::string mic_name;
+					if (!MDmicin.getValue(EMDL_MICROGRAPH_NAME, mic_name))
+						REPORT_ERROR("Experiment::read ERROR: data_micrographs block should contain micrographName labels!");
+					found_mic_names.push_back(mic_name);
+					bool found = false;
+					for (long int i = 0; i < micrographs.size(); i++)
+					{
+						if (micrographs[i].name == mic_name)
+						{
+							// Copy entire row from MDmicin to MDmic (at line micrographs[i].id)
+							MDmic.setObject(MDmicin.getObject(), micrographs[i].id);
+							break;
+						}
+					}
+				}
+
+				// Also check whether all micrographs have been found....
+				for (int i = 0; i < micrographs.size(); i++)
+				{
+					bool found = false;
+					for (int j = 0; j < found_mic_names.size(); j++)
+					{
+						if (found_mic_names[j] == micrographs[i].name)
+						{
+							found = true;
+							break;
+						}
+					}
+					if (!found)
+						REPORT_ERROR("Did not find the following micrograph in the data_micrographs table: " + micrographs[i].name);
+				}
+
+			}
+		}
+	}
+
+#ifdef DEBUG_READ
+	std::cerr << "Done filling MDimg" << std::endl;
+	std::cerr << "Press any key to continue..." << std::endl;
+	std::cin >> c;
+#endif
+
+	// Make sure some things are always set in the MDimg
+	bool have_rot  = MDimgin.containsLabel(EMDL_ORIENT_ROT);
+	bool have_tilt = MDimgin.containsLabel(EMDL_ORIENT_TILT);
+	bool have_psi  = MDimgin.containsLabel(EMDL_ORIENT_PSI);
+	bool have_xoff = MDimgin.containsLabel(EMDL_ORIENT_ORIGIN_X);
+	bool have_yoff = MDimgin.containsLabel(EMDL_ORIENT_ORIGIN_Y);
+	bool have_clas = MDimgin.containsLabel(EMDL_PARTICLE_CLASS);
+	bool have_norm = MDimgin.containsLabel(EMDL_IMAGE_NORM_CORRECTION);
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDimg)
+	{
+		double dzero=0., done=1.;
+		int izero = 0;
+		if (!have_rot)
+			MDimg.setValue(EMDL_ORIENT_ROT, dzero);
+		if (!have_tilt)
+			MDimg.setValue(EMDL_ORIENT_TILT, dzero);
+		if (!have_psi)
+			MDimg.setValue(EMDL_ORIENT_PSI, dzero);
+		if (!have_xoff)
+			MDimg.setValue(EMDL_ORIENT_ORIGIN_X, dzero);
+		if (!have_yoff)
+			MDimg.setValue(EMDL_ORIENT_ORIGIN_Y, dzero);
+		if (!have_clas)
+			MDimg.setValue(EMDL_PARTICLE_CLASS, izero);
+		if (!have_norm)
+			MDimg.setValue(EMDL_IMAGE_NORM_CORRECTION, done);
+	}
+
+#ifdef DEBUG_READ
+	std::cerr << "Done setting defaults MDimg" << std::endl;
+	std::cerr << "Press any key to continue..." << std::endl;
+	std::cin >> c;
+#endif
+
+	// Also set the image_size (use the last image for that, still in fn_img)
+	FileName fn_img;
+	Image<double> img;
+	MDimg.getValue(EMDL_IMAGE_NAME, fn_img, MDimg.firstObject());
+	if (fn_img != "")
+	{
+		img.read(fn_img, false); //false means read only header, skip real data
+		int image_size = XSIZE(img());
+		if (image_size != YSIZE(img()))
+			REPORT_ERROR("Experiment::read: xsize != ysize: only squared images allowed");
+			// Add a single object to MDexp
+			MDexp.addObject();
+		MDexp.setValue(EMDL_IMAGE_SIZE, image_size);
+		if (ZSIZE(img()) > 1)
+		{
+			if (image_size != ZSIZE(img()))
+				REPORT_ERROR("Experiment::read: xsize != zsize: only cubed images allowed");
+			MDexp.setValue(EMDL_IMAGE_DIMENSIONALITY, 3);
+		}
+		else
+		{
+			MDexp.setValue(EMDL_IMAGE_DIMENSIONALITY, 2);
+		}
+	}
+	else
+	{
+		REPORT_ERROR("There are no images read in: please check your input file...");
+	}
+
+	// Order the particles in each ori_particle (only useful for realignment of movie frames)
+	orderParticlesInOriginalParticles();
+
+#ifdef DEBUG_READ
+	std::cerr << "Writing out debug_data.star" << std::endl;
+	write("debug");
+	exit(0);
+#endif
+}
+
+// Write to file
+void Experiment::write(FileName fn_root)
+{
+
+	std::ofstream  fh;
+	FileName fn_tmp = fn_root+"_data.star";
+    fh.open((fn_tmp).c_str(), std::ios::out);
+    if (!fh)
+        REPORT_ERROR( (std::string)"Experiment::write: Cannot write file: " + fn_tmp);
+
+    // Always write MDimg
+    MDimg.write(fh);
+
+    // Only write MDmic if more than one micrograph is stored there...
+    //if (MDmic.lastObject() > 1)
+    //	MDmic.write(fh);
+
+    // Only write MDexp if something is stored there...
+    //if (!MDexp.isEmpty())
+    //	MDexp.write(fh);
+
+	fh.close();
+
+}
diff --git a/src/exp_model.h b/src/exp_model.h
new file mode 100644
index 0000000..482b616
--- /dev/null
+++ b/src/exp_model.h
@@ -0,0 +1,438 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#ifndef EXP_MODEL_H_
+#define EXP_MODEL_H_
+#include <fstream>
+#include "src/matrix2d.h"
+#include "src/image.h"
+#include "src/multidim_array.h"
+#include "src/metadata_table.h"
+
+////////////// Hierarchical metadata model for tilt series
+
+// ExpImage, ExpParticle, and ExpMicrograph dont store any metadata other than logical relationships
+// All image and micrograph -related metadata is stored in MDimg and MDmic inside Experiment...
+class ExpImage
+{
+public:
+	// ID of this image, i.e. which number in the MDimg am I?
+	long int id;
+
+	// ID of the micrograph that this image comes from
+	long int micrograph_id;
+
+	// ID of the group that this image comes from
+	long int group_id;
+
+	// ID of the particle that this image comes from
+	long int particle_id;
+
+	// Empty constructor
+	ExpImage() {};
+
+	// Destructor needed for work with vectors
+	~ExpImage() {};
+
+	void clear()
+	{
+		id = micrograph_id = group_id = particle_id = -1;
+	}
+};
+
+class ExpParticle
+{
+public:
+	// Particle id
+	long int id;
+
+	// Name of this particle (by this name it will be recognised upon reading)
+	std::string name;
+
+	// Random subset this particle belongs to
+	int random_subset;
+
+	// All the images that were recorded for this particle
+	std::vector<ExpImage> images;
+
+	// Empty Constructor
+	ExpParticle(int max_nr_images_pers_particle = 1)
+	{
+		clear();
+	}
+
+	// Destructor needed for work with vectors
+	~ExpParticle()
+	{
+		clear();
+	}
+
+	// Initialise
+	void clear()
+	{
+		id = -1;
+		random_subset = 0;
+		name="undefined";
+		images.clear();
+	}
+
+};
+
+class ExpOriginalParticle
+{
+public:
+	// Name of this particle (by this name it will be recognised upon reading)
+	std::string name;
+
+	// Random subset this original_particle belongs to
+	int random_subset;
+
+	// All the id's of the particles that were derived from this original particle
+	std::vector<long int> particles_id;
+
+	// Order of those particles in the original particle (extracted from mic_name)
+	std::vector<int> particles_order;
+
+	// Empty Constructor
+	ExpOriginalParticle()
+	{
+		clear();
+	}
+
+	// Destructor needed for work with vectors
+	~ExpOriginalParticle()
+	{
+		clear();
+	}
+
+	// Initialise
+	void clear()
+	{
+		name="undefined";
+		particles_id.clear();
+		particles_order.clear();
+	}
+
+	void addParticle(long int _particle_id, int _random_subset, int _order);
+
+};
+
+// This class describes which OriginalParticles in the data set belong to the same frame-average micrograph
+class AverageMicrograph
+{
+public:
+	// ID of this average micrograph, i.e. which number in the MDmic am I?
+	long int id;
+
+	// Name of this average micrograph
+	std::string name;
+
+	// All the original particles that were recorded on this average micrograph
+	std::vector<long int> ori_particles_id;
+
+	// Empty Constructor
+	AverageMicrograph()
+	{
+		clear();
+	}
+
+	// Destructor needed for work with vectors
+	~AverageMicrograph()
+	{
+		clear();
+	}
+
+	// Copy constructor needed for work with vectors
+	AverageMicrograph(AverageMicrograph const& copy)
+	{
+		id = copy.id;
+		name = copy.name;
+		ori_particles_id = copy.ori_particles_id;
+	}
+
+	// Define assignment operator in terms of the copy constructor
+	AverageMicrograph& operator=(AverageMicrograph const& copy)
+	{
+		id = copy.id;
+		name = copy.name;
+		ori_particles_id = copy.ori_particles_id;
+		return *this;
+	}
+
+	// Initialise
+	void clear()
+	{
+		id = -1;
+		name="";
+		ori_particles_id.clear();
+	}
+};
+
+
+class ExpMicrograph
+{
+public:
+	// ID of this micrograph, i.e. which number in the MDmic am I?
+	long int id;
+
+	// Name of this micrograph (by this name it will be recognised upon reading)
+	std::string name;
+
+	// All the images that were recorded on this micrograph
+	std::vector<ExpImage> images;
+
+	// Empty Constructor
+	ExpMicrograph()
+	{
+		clear();
+	}
+
+	// Destructor needed for work with vectors
+	~ExpMicrograph()
+	{
+		clear();
+	}
+
+	// Copy constructor needed for work with vectors
+	ExpMicrograph(ExpMicrograph const& copy)
+	{
+		id = copy.id;
+		name = copy.name;
+		images = copy.images;
+
+	}
+
+	// Define assignment operator in terms of the copy constructor
+	ExpMicrograph& operator=(ExpMicrograph const& copy)
+	{
+		id = copy.id;
+		name = copy.name;
+		images = copy.images;
+		return *this;
+	}
+
+	// Initialise
+	void clear()
+	{
+		id = -1;
+		name="";
+		images.clear();
+	}
+
+};
+
+class ExpGroup
+{
+public:
+	// ID of this group
+	long int id;
+
+	// Name of this group (by this name it will be recognised upon reading)
+	std::string name;
+
+	// Empty Constructor
+	ExpGroup()
+	{
+		clear();
+	}
+
+	// Destructor needed for work with vectors
+	~ExpGroup()
+	{
+		clear();
+	}
+
+	// Copy constructor needed for work with vectors
+	ExpGroup(ExpGroup const& copy)
+	{
+		id = copy.id;
+		name = copy.name;
+	}
+
+	// Define assignment operator in terms of the copy constructor
+	ExpGroup& operator=(ExpGroup const& copy)
+	{
+		id = copy.id;
+		name = copy.name;
+		return *this;
+	}
+
+	// Initialise
+	void clear()
+	{
+		id = -1;
+		name="";
+	}
+
+};
+
+
+class Experiment
+{
+public:
+	// All groups in the experiment
+	std::vector<ExpGroup> groups;
+
+	// All micrographs in the experiment
+	std::vector<ExpMicrograph> micrographs;
+
+	// All average micrographs in this experiment (only used for movie-processing, i.e. by the particle_polisher
+	std::vector<AverageMicrograph> average_micrographs;
+
+	// All particles in the experiment
+	std::vector<ExpParticle> particles;
+
+	// All original particles in the experiment
+	std::vector<ExpOriginalParticle> ori_particles;
+
+	// Number of particles in random subsets 1 and 2;
+	long int nr_ori_particles_subset1, nr_ori_particles_subset2;
+
+	// Experiment-related metadata
+    MetaDataTable MDexp;
+
+    // One large MetaDataTable for all images
+    MetaDataTable MDimg;
+
+    // One large MetaDataTable for all micrographs
+    MetaDataTable MDmic;
+
+	// Empty Constructor
+	Experiment()
+	{
+		clear();
+	}
+
+	~Experiment()
+	{
+		clear();
+	}
+
+	void clear()
+	{
+		groups.clear();
+		micrographs.clear();
+		particles.clear();
+		ori_particles.clear();
+		MDexp.clear();
+		MDexp.setIsList(true);
+		MDimg.clear();
+		MDimg.setIsList(false);
+		MDmic.clear();
+		MDmic.setIsList(false);
+		MDimg.setName("images");
+		MDmic.setName("micrographs");
+		MDexp.setName("experiment");
+	}
+
+	// Calculate the total number of images in this experiment
+	long int numberOfImages(int random_subset = 0);
+
+	// Calculate the total number of particles in this experiment
+	long int numberOfParticles(int random_subset = 0);
+
+	// Calculate the total number of particles in this experiment
+	long int numberOfOriginalParticles(int random_subset = 0);
+
+	// Calculate the total number of micrographs in this experiment
+	long int numberOfMicrographs();
+
+	// Calculate the total number of groups in this experiment
+	long int numberOfGroups();
+
+	// Get the number of images for this particle
+	int getNrImagesInSeries(long int part_id);
+
+	// Get the random_subset for this particle
+	int getRandomSubset(long int part_id);
+
+	// Get the micrograph_id for the N'th image for this particle
+	long int getMicrographId(long int part_id, int inseries_no);
+
+	// Get the group_id for the N'th image for this particle
+	long int getGroupId(long int part_id, int inseries_no);
+
+	// Get the image_id for the N'th image for this particle
+	long int getImageId(long int part_id, int inseries_no);
+
+	// Get the metadata-row for this image in a separate MetaDataTable
+	MetaDataTable getMetaDataImage(long int part_id, int inseries_no);
+
+	// Get the metadata-row for this micrograph in a separate MetaDataTable
+	MetaDataTable getMetaDataMicrograph(long int part_id, int inseries_no);
+
+	// Get the micrograph transformation matrix for this particle
+	Matrix2D<double> getMicrographTransformationMatrix(long int mic_id);
+
+	// Get the micrograph transformation matrix for this particle & iseries_no
+	Matrix2D<double> getMicrographTransformationMatrix(long int part_id, int inseries_no);
+
+	// Add an image
+	long int addImage(long int group_id, long int micrograph_id, long int particle_id);
+
+	// Add a particle
+	long int addParticle(std::string part_name, int random_subset = 0);
+
+	// Add an original particle
+	long int addOriginalParticle(std::string part_name, int random_subset = 0);
+
+	// Add a group
+	long int addGroup(std::string mic_name);
+
+	// Add a micrograph
+	long int addMicrograph(std::string mic_name);
+
+	// Add an AverageMicrograph
+	long int addAverageMicrograph(std::string avg_mic_name);
+
+	// for separate refinement of random halves of the data
+	void divideOriginalParticlesInRandomHalves(int seed);
+
+	// Randomise the order of the original_particles
+	void randomiseOriginalParticlesOrder(int seed, bool do_split_random_halves = false);
+
+	// calculate maximum number of images for a particle (possibly within a range of particles)
+	int maxNumberOfImagesPerOriginalParticle(long int first_particle_id = -1, long int last_particle_id = -1);
+
+	// Given the STAR file of a set of movieframes, expand the current Experiment to contain all movie frames
+	// rlnParticleName entries in the movie-frame Experiment should coincide with rlnImageName entries in the current Experiment
+	// the entries rlnAngleRot, rlnAngleTilt, rlnAnglePsi, rlnOriginX and rlnOriginY will be taken from the current Experiment and
+	// copied into the new moevieframe Experiment. In addition, these values will be used to center the corresponding Priors
+	void expandToMovieFrames(FileName fn_data_movie);
+
+	// Make sure the particles inside each orriginal_particle are in the right order
+	// After they have been ordered, get rid of the particles_order vector inside the ori_particles
+	void orderParticlesInOriginalParticles();
+
+	// For all OriginalParticles, determine from which AverageMicrograph they originate
+	// This is only used for movie-processing, e.g. in the particle_polisher
+	void getAverageMicrographs();
+
+	// Print help message for possible command-line options
+	void usage();
+
+	// Read from file
+	void read(FileName fn_in, bool do_ignore_particle_name = false);
+
+	// Write
+	void write(FileName fn_root);
+
+};
+
+#endif /* METADATA_MODEL_H_ */
diff --git a/src/fftw.cpp b/src/fftw.cpp
new file mode 100644
index 0000000..61f3e20
--- /dev/null
+++ b/src/fftw.cpp
@@ -0,0 +1,1149 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:    Roberto Marabini                 (roberto at cnb.csic.es)
+ *             Carlos Oscar S. Sorzano          (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include "src/fftw.h"
+#include "src/args.h"
+#include <string.h>
+#include <pthread.h>
+
+static pthread_mutex_t fftw_plan_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+//#define DEBUG_PLANS
+
+// Constructors and destructors --------------------------------------------
+FourierTransformer::FourierTransformer()
+{
+    init();
+
+#ifdef DEBUG_PLANS
+    std::cerr << "INIT this= "<<this<< std::endl;
+#endif
+}
+
+FourierTransformer::~FourierTransformer()
+{
+    clear();
+#ifdef DEBUG_PLANS
+    std::cerr << "CLEARED this= "<<this<< std::endl;
+#endif
+}
+
+FourierTransformer::FourierTransformer(const FourierTransformer& op)
+{
+	// Clear current object
+	clear();
+	// New object is an extact copy of op
+    *this = op;
+}
+
+void FourierTransformer::init()
+{
+    fReal            = NULL;
+    fComplex         = NULL;
+    fPlanForward     = NULL;
+    fPlanBackward    = NULL;
+    dataPtr          = NULL;
+    complexDataPtr   = NULL;
+    threadsSetOn=false;
+    nthreads = 1;
+}
+
+void FourierTransformer::clear()
+{
+    fFourier.clear();
+    // Clean-up all other FFTW-allocated memory
+    destroyPlans();
+    // Initialise all pointers to NULL, set nthreads to 1 and threadsSetOn to false
+    init();
+
+}
+
+void FourierTransformer::cleanup()
+{
+	// First clear object and destroy plans
+    clear();
+    // Then clean up all the junk fftw keeps lying around
+    // SOMEHOW THE FOLLOWING IS NOT ALLOWED WHEN USING MULTPLE TRANSFORMER OBJECTS....
+	if (threadsSetOn)
+    	fftw_cleanup_threads();
+    else
+    	fftw_cleanup();
+#ifdef DEBUG_PLANS
+    std::cerr << "CLEANED-UP this= "<<this<< std::endl;
+#endif
+
+}
+
+void FourierTransformer::destroyPlans()
+{
+
+    // Anything to do with plans has to be protected for threads!
+    pthread_mutex_lock(&fftw_plan_mutex);
+    if (fPlanForward !=NULL)
+    {
+#ifdef DEBUG_PLANS
+    	std::cerr << " DESTROY fPlanForward= " << fPlanForward  <<" this= "<<this<<std::endl;
+#endif
+    	fftw_destroy_plan(fPlanForward);
+    }
+    if (fPlanBackward!=NULL)
+    {
+#ifdef DEBUG_PLANS
+    	std::cerr << " DESTROY fPlanBackward= " << fPlanBackward  <<" this= "<<this<< std::endl;
+#endif
+   	fftw_destroy_plan(fPlanBackward);
+    }
+    pthread_mutex_unlock(&fftw_plan_mutex);
+
+}
+
+void FourierTransformer::setThreadsNumber(int tNumber)
+{
+    if (tNumber!=1)
+    {
+        threadsSetOn=true;
+        nthreads = tNumber;
+        pthread_mutex_lock(&fftw_plan_mutex);
+        if(fftw_init_threads()==0)
+            REPORT_ERROR("FFTW cannot init threads (setThreadsNumber)");
+        fftw_plan_with_nthreads(nthreads);
+        pthread_mutex_unlock(&fftw_plan_mutex);
+    }
+}
+
+// Initialization ----------------------------------------------------------
+const MultidimArray<double> &FourierTransformer::getReal() const
+{
+    return (*fReal);
+}
+
+const MultidimArray<Complex > &FourierTransformer::getComplex() const
+{
+    return (*fComplex);
+}
+
+
+void FourierTransformer::setReal(MultidimArray<double> &input)
+{
+    bool recomputePlan=false;
+    if (fReal==NULL)
+        recomputePlan=true;
+    else if (dataPtr!=MULTIDIM_ARRAY(input))
+        recomputePlan=true;
+    else
+        recomputePlan=!(fReal->sameShape(input));
+    fFourier.resize(ZSIZE(input),YSIZE(input),XSIZE(input)/2+1);
+    fReal=&input;
+
+    if (recomputePlan)
+    {
+        int ndim=3;
+        if (ZSIZE(input)==1)
+        {
+            ndim=2;
+            if (YSIZE(input)==1)
+                ndim=1;
+        }
+        int *N = new int[ndim];
+        switch (ndim)
+        {
+        case 1:
+            N[0]=XSIZE(input);
+            break;
+        case 2:
+            N[0]=YSIZE(input);
+            N[1]=XSIZE(input);
+            break;
+        case 3:
+            N[0]=ZSIZE(input);
+            N[1]=YSIZE(input);
+            N[2]=XSIZE(input);
+            break;
+        }
+
+        // Destroy both forward and backward plans if they already exist
+        destroyPlans();
+        // Make new plans
+        pthread_mutex_lock(&fftw_plan_mutex);
+        fPlanForward = fftw_plan_dft_r2c(ndim, N, MULTIDIM_ARRAY(*fReal),
+                                         (fftw_complex*) MULTIDIM_ARRAY(fFourier), FFTW_ESTIMATE);
+        fPlanBackward = fftw_plan_dft_c2r(ndim, N,
+                                          (fftw_complex*) MULTIDIM_ARRAY(fFourier), MULTIDIM_ARRAY(*fReal),
+                                          FFTW_ESTIMATE);
+        pthread_mutex_unlock(&fftw_plan_mutex);
+
+        if (fPlanForward == NULL || fPlanBackward == NULL)
+            REPORT_ERROR("FFTW plans cannot be created");
+
+#ifdef DEBUG_PLANS
+        std::cerr << " SETREAL fPlanForward= " << fPlanForward << " fPlanBackward= " << fPlanBackward  <<" this= "<<this<< std::endl;
+#endif
+
+        delete [] N;
+        dataPtr=MULTIDIM_ARRAY(*fReal);
+    }
+}
+
+void FourierTransformer::setReal(MultidimArray<Complex > &input)
+{
+    bool recomputePlan=false;
+    if (fComplex==NULL)
+        recomputePlan=true;
+    else if (complexDataPtr!=MULTIDIM_ARRAY(input))
+        recomputePlan=true;
+    else
+        recomputePlan=!(fComplex->sameShape(input));
+    fFourier.resize(input);
+    fComplex=&input;
+
+    if (recomputePlan)
+    {
+        int ndim=3;
+        if (ZSIZE(input)==1)
+        {
+            ndim=2;
+            if (YSIZE(input)==1)
+                ndim=1;
+        }
+        int *N = new int[ndim];
+        switch (ndim)
+        {
+        case 1:
+            N[0]=XSIZE(input);
+            break;
+        case 2:
+            N[0]=YSIZE(input);
+            N[1]=XSIZE(input);
+            break;
+        case 3:
+            N[0]=ZSIZE(input);
+            N[1]=YSIZE(input);
+            N[2]=XSIZE(input);
+            break;
+        }
+
+        pthread_mutex_lock(&fftw_plan_mutex);
+        if (fPlanForward!=NULL)
+            fftw_destroy_plan(fPlanForward);
+        fPlanForward=NULL;
+        fPlanForward = fftw_plan_dft(ndim, N, (fftw_complex*) MULTIDIM_ARRAY(*fComplex),
+                                     (fftw_complex*) MULTIDIM_ARRAY(fFourier), FFTW_FORWARD, FFTW_ESTIMATE);
+        if (fPlanBackward!=NULL)
+            fftw_destroy_plan(fPlanBackward);
+        fPlanBackward=NULL;
+        fPlanBackward = fftw_plan_dft(ndim, N, (fftw_complex*) MULTIDIM_ARRAY(fFourier),
+                                      (fftw_complex*) MULTIDIM_ARRAY(*fComplex), FFTW_BACKWARD, FFTW_ESTIMATE);
+        if (fPlanForward == NULL || fPlanBackward == NULL)
+            REPORT_ERROR("FFTW plans cannot be created");
+        delete [] N;
+        complexDataPtr=MULTIDIM_ARRAY(*fComplex);
+        pthread_mutex_unlock(&fftw_plan_mutex);
+    }
+}
+
+void FourierTransformer::setFourier(MultidimArray<Complex > &inputFourier)
+{
+    memcpy(MULTIDIM_ARRAY(fFourier),MULTIDIM_ARRAY(inputFourier),
+           MULTIDIM_SIZE(inputFourier)*2*sizeof(double));
+}
+
+// Transform ---------------------------------------------------------------
+void FourierTransformer::Transform(int sign)
+{
+    if (sign == FFTW_FORWARD)
+    {
+        fftw_execute(fPlanForward);
+
+        // Normalisation of the transform
+        unsigned long int size=0;
+        if(fReal!=NULL)
+            size = MULTIDIM_SIZE(*fReal);
+        else if (fComplex!= NULL)
+            size = MULTIDIM_SIZE(*fComplex);
+        else
+            REPORT_ERROR("No complex nor real data defined");
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(fFourier)
+            DIRECT_MULTIDIM_ELEM(fFourier,n) /= size;
+    }
+    else if (sign == FFTW_BACKWARD)
+        fftw_execute(fPlanBackward);
+
+}
+
+void FourierTransformer::FourierTransform()
+{
+    Transform(FFTW_FORWARD);
+}
+
+void FourierTransformer::inverseFourierTransform()
+{
+    Transform(FFTW_BACKWARD);
+}
+
+// Inforce Hermitian symmetry ---------------------------------------------
+void FourierTransformer::enforceHermitianSymmetry()
+{
+    int ndim=3;
+    if (ZSIZE(*fReal)==1)
+    {
+        ndim=2;
+        if (YSIZE(*fReal)==1)
+            ndim=1;
+    }
+    long int yHalf=YSIZE(*fReal)/2;
+    if (YSIZE(*fReal)%2==0)
+        yHalf--;
+    long int zHalf=ZSIZE(*fReal)/2;
+    if (ZSIZE(*fReal)%2==0)
+        zHalf--;
+    switch (ndim)
+    {
+    case 2:
+        for (long int i=1; i<=yHalf; i++)
+        {
+        	long int isym=intWRAP(-i,0,YSIZE(*fReal)-1);
+            Complex mean=0.5*(
+                                          DIRECT_A2D_ELEM(fFourier,i,0)+
+                                          conj(DIRECT_A2D_ELEM(fFourier,isym,0)));
+            DIRECT_A2D_ELEM(fFourier,i,0)=mean;
+            DIRECT_A2D_ELEM(fFourier,isym,0)=conj(mean);
+        }
+        break;
+    case 3:
+        for (long int k=0; k<ZSIZE(*fReal); k++)
+        {
+        	long int ksym=intWRAP(-k,0,ZSIZE(*fReal)-1);
+            for (long int i=1; i<=yHalf; i++)
+            {
+            	long int isym=intWRAP(-i,0,YSIZE(*fReal)-1);
+                Complex mean=0.5*(
+                                              DIRECT_A3D_ELEM(fFourier,k,i,0)+
+                                              conj(DIRECT_A3D_ELEM(fFourier,ksym,isym,0)));
+                DIRECT_A3D_ELEM(fFourier,k,i,0)=mean;
+                DIRECT_A3D_ELEM(fFourier,ksym,isym,0)=conj(mean);
+            }
+        }
+        for (long int k=1; k<=zHalf; k++)
+        {
+        	long int ksym=intWRAP(-k,0,ZSIZE(*fReal)-1);
+            Complex mean=0.5*(
+                                          DIRECT_A3D_ELEM(fFourier,k,0,0)+
+                                          conj(DIRECT_A3D_ELEM(fFourier,ksym,0,0)));
+            DIRECT_A3D_ELEM(fFourier,k,0,0)=mean;
+            DIRECT_A3D_ELEM(fFourier,ksym,0,0)=conj(mean);
+        }
+        break;
+    }
+}
+
+
+void randomizePhasesBeyond(MultidimArray<double> &v, int index)
+{
+    MultidimArray< Complex > FT;
+    FourierTransformer transformer;
+
+    transformer.FourierTransform(v, FT, false);
+
+    int index2 = index*index;
+    FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(FT)
+    {
+    	if (kp*kp + ip*ip + jp*jp >= index2)
+    	{
+    		double mag = abs(DIRECT_A3D_ELEM(FT, k, i, j));
+    		double phas = rnd_unif(0., 2.*PI);
+    		double realval = mag * cos(phas);
+    		double imagval = mag * sin(phas);
+    		DIRECT_A3D_ELEM(FT, k, i, j) = Complex(realval, imagval);
+    	}
+    }
+
+    // Inverse transform
+    transformer.inverseFourierTransform();
+
+}
+
+
+// Fourier ring correlation -----------------------------------------------
+// from precalculated Fourier Transforms, and without sampling rate etc.
+void getFSC(MultidimArray< Complex > &FT1,
+			MultidimArray< Complex > &FT2,
+			MultidimArray< double > &fsc)
+{
+	if (!FT1.sameShape(FT2))
+        REPORT_ERROR("fourierShellCorrelation ERROR: MultidimArrays have different shapes!");
+
+    MultidimArray< int > radial_count(XSIZE(FT1));
+    MultidimArray<double> num, den1, den2;
+    Matrix1D<double> f(3);
+    num.initZeros(radial_count);
+    den1.initZeros(radial_count);
+    den2.initZeros(radial_count);
+    fsc.initZeros(radial_count);
+    FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(FT1)
+    {
+    	int idx = ROUND(sqrt(kp*kp + ip*ip + jp*jp));
+        if (idx >= XSIZE(FT1))
+        	continue;
+        Complex z1=DIRECT_A3D_ELEM(FT1, k, i, j);
+        Complex z2=DIRECT_A3D_ELEM(FT2, k, i, j);
+        double absz1=abs(z1);
+        double absz2=abs(z2);
+        num(idx)+= (conj(z1) * z2).real;
+        den1(idx)+= absz1*absz1;
+        den2(idx)+= absz2*absz2;
+        radial_count(idx)++;
+    }
+
+    FOR_ALL_ELEMENTS_IN_ARRAY1D(fsc)
+    {
+        fsc(i) = num(i)/sqrt(den1(i)*den2(i));
+    }
+
+}
+
+
+void getFSC(MultidimArray< double > &m1,
+		    MultidimArray< double > &m2,
+		    MultidimArray< double > &fsc)
+{
+	MultidimArray< Complex > FT1, FT2;
+	FourierTransformer transformer;
+	transformer.FourierTransform(m1, FT1);
+	transformer.FourierTransform(m2, FT2);
+	getFSC(FT1, FT2, fsc);
+}
+
+/*
+void selfScaleToSizeFourier(long int Ydim, long int Xdim, MultidimArray<double>& Mpmem, int nThreads)
+{
+
+    //Mmem = *this
+    //memory for fourier transform output
+    MultidimArray<Complex > MmemFourier;
+    // Perform the Fourier transform
+    FourierTransformer transformerM;
+    transformerM.setThreadsNumber(nThreads);
+    transformerM.FourierTransform(Mpmem, MmemFourier, true);
+
+    // Create space for the downsampled image and its Fourier transform
+    Mpmem.resize(Ydim, Xdim);
+    MultidimArray<Complex > MpmemFourier;
+    FourierTransformer transformerMp;
+    transformerMp.setReal(Mpmem);
+    transformerMp.getFourierAlias(MpmemFourier);
+    long int ihalf = XMIPP_MIN((YSIZE(MpmemFourier)/2+1),(YSIZE(MmemFourier)/2+1));
+    long int xsize = XMIPP_MIN((XSIZE(MmemFourier)),(XSIZE(MpmemFourier)));
+    //Init with zero
+    MpmemFourier.initZeros();
+    for (long int i=0; i<ihalf; i++)
+        for (long int j=0; j<xsize; j++)
+            MpmemFourier(i,j)=MmemFourier(i,j);
+    for (long int i=YSIZE(MpmemFourier)-1, n=1; n < ihalf-1; i--, n++)
+    {
+    	long int ip = YSIZE(MmemFourier) - n;
+    	for (long int j=0; j<xsize; j++)
+            MpmemFourier(i,j)=MmemFourier(ip,j);
+    }
+
+    // Transform data
+    transformerMp.inverseFourierTransform();
+}
+*/
+
+// Shift an image through phase-shifts in its Fourier Transform
+void shiftImageInFourierTransform(MultidimArray<Complex > &in,
+		                          MultidimArray<Complex > &out,
+								  TabSine &tab_sin, TabCosine &tab_cos,
+								  double oridim, Matrix1D<double> shift)
+{
+	out.resize(in);
+	shift /= -oridim;
+	double dotp, a, b, c, d, ac, bd, ab_cd, x, y, z, xshift, yshift, zshift;
+	switch (in.getDim())
+	{
+	case 1:
+		xshift = XX(shift);
+		if (ABS(xshift) < XMIPP_EQUAL_ACCURACY)
+		{
+			out = in;
+			return;
+		}
+		for (long int j = 0; j < XSIZE(in); j++)
+		{
+			x = j;
+			dotp = 2 * PI * (x * xshift);
+			a = tab_cos(dotp);
+			b = tab_sin(dotp);
+			c = DIRECT_A1D_ELEM(in, j).real;
+			d = DIRECT_A1D_ELEM(in, j).imag;
+			ac = a * c;
+			bd = b * d;
+			ab_cd = (a + b) * (c + d); // (ab_cd-ac-bd = ad+bc : but needs 4 multiplications)
+			DIRECT_A1D_ELEM(out, j) = Complex(ac - bd, ab_cd - ac - bd);
+		}
+		break;
+	case 2:
+		xshift = XX(shift);
+		yshift = YY(shift);
+		if (ABS(xshift) < XMIPP_EQUAL_ACCURACY && ABS(yshift) < XMIPP_EQUAL_ACCURACY)
+		{
+			out = in;
+			return;
+		}
+		for (long int i=0; i<XSIZE(in); i++)
+			for (long int j=0; j<XSIZE(in); j++)
+			{
+				x = j;
+				y = i;
+				dotp = 2 * PI * (x * xshift + y * yshift);
+				a = tab_cos(dotp);
+				b = tab_sin(dotp);
+				c = DIRECT_A2D_ELEM(in, i, j).real;
+				d = DIRECT_A2D_ELEM(in, i, j).imag;
+				ac = a * c;
+				bd = b * d;
+				ab_cd = (a + b) * (c + d);
+				DIRECT_A2D_ELEM(out, i, j) = Complex(ac - bd, ab_cd - ac - bd);
+			}
+		for (long int i=YSIZE(in)-1; i>=XSIZE(in); i--)
+		{
+			y = i - YSIZE(in);
+			for (long int j=0; j<XSIZE(in); j++)
+			{
+				x = j;
+				dotp = 2 * PI * (x * xshift + y * yshift);
+				a = tab_cos(dotp);
+				b = tab_sin(dotp);
+				c = DIRECT_A2D_ELEM(in, i, j).real;
+				d = DIRECT_A2D_ELEM(in, i, j).imag;
+				ac = a * c;
+				bd = b * d;
+				ab_cd = (a + b) * (c + d);
+				DIRECT_A2D_ELEM(out, i, j) = Complex(ac - bd, ab_cd - ac - bd);
+			}
+		}
+		break;
+	case 3:
+		xshift = XX(shift);
+		yshift = YY(shift);
+		zshift = ZZ(shift);
+		if (ABS(xshift) < XMIPP_EQUAL_ACCURACY && ABS(yshift) < XMIPP_EQUAL_ACCURACY && ABS(zshift) < XMIPP_EQUAL_ACCURACY)
+		{
+			out = in;
+			return;
+		}
+		for (long int k=0; k<ZSIZE(in); k++)
+		{
+			z = (k < XSIZE(in)) ? k : k - ZSIZE(in);
+			for (long int i=0; i<YSIZE(in); i++)
+			{
+				y = (i < XSIZE(in)) ? i : i - YSIZE(in);
+				for (long int j=0; j<XSIZE(in); j++)
+				{
+					x = j;
+					dotp = 2 * PI * (x * xshift + y * yshift + z * zshift);
+					a = cos(dotp);
+					b = sin(dotp);
+					c = DIRECT_A3D_ELEM(in, k, i, j).real;
+					d = DIRECT_A3D_ELEM(in, k, i, j).imag;
+					ac = a * c;
+					bd = b * d;
+					ab_cd = (a + b) * (c + d);
+					DIRECT_A3D_ELEM(out, k, i, j) = Complex(ac - bd, ab_cd - ac - bd);
+				}
+			}
+		}
+		break;
+	default:
+		REPORT_ERROR("shiftImageInFourierTransform ERROR: dimension should be 1, 2 or 3!");
+	}
+}
+// Shift an image through phase-shifts in its Fourier Transform (without pretabulated sine and cosine)
+void shiftImageInFourierTransform(MultidimArray<Complex > &in,
+		                          MultidimArray<Complex > &out,
+		                          double oridim, Matrix1D<double> shift)
+{
+	out.resize(in);
+	shift /= -oridim;
+	double dotp, a, b, c, d, ac, bd, ab_cd, x, y, z, xshift, yshift, zshift;
+	switch (in.getDim())
+	{
+	case 1:
+		xshift = XX(shift);
+		if (ABS(xshift) < XMIPP_EQUAL_ACCURACY)
+		{
+			out = in;
+			return;
+		}
+		for (long int j = 0; j < XSIZE(in); j++)
+		{
+			x = j;
+			dotp = 2 * PI * (x * xshift);
+			a = cos(dotp);
+			b = sin(dotp);
+			c = DIRECT_A1D_ELEM(in, j).real;
+			d = DIRECT_A1D_ELEM(in, j).imag;
+			ac = a * c;
+			bd = b * d;
+			ab_cd = (a + b) * (c + d); // (ab_cd-ac-bd = ad+bc : but needs 4 multiplications)
+			DIRECT_A1D_ELEM(out, j) = Complex(ac - bd, ab_cd - ac - bd);
+		}
+		break;
+	case 2:
+		xshift = XX(shift);
+		yshift = YY(shift);
+		if (ABS(xshift) < XMIPP_EQUAL_ACCURACY && ABS(yshift) < XMIPP_EQUAL_ACCURACY)
+		{
+			out = in;
+			return;
+		}
+		for (long int i=0; i<XSIZE(in); i++)
+			for (long int j=0; j<XSIZE(in); j++)
+			{
+				x = j;
+				y = i;
+				dotp = 2 * PI * (x * xshift + y * yshift);
+				a = cos(dotp);
+				b = sin(dotp);
+				c = DIRECT_A2D_ELEM(in, i, j).real;
+				d = DIRECT_A2D_ELEM(in, i, j).imag;
+				ac = a * c;
+				bd = b * d;
+				ab_cd = (a + b) * (c + d);
+				DIRECT_A2D_ELEM(out, i, j) = Complex(ac - bd, ab_cd - ac - bd);
+			}
+		for (long int i=YSIZE(in)-1; i>=XSIZE(in); i--)
+		{
+			y = i - YSIZE(in);
+			for (long int j=0; j<XSIZE(in); j++)
+			{
+				x = j;
+				dotp = 2 * PI * (x * xshift + y * yshift);
+				a = cos(dotp);
+				b = sin(dotp);
+				c = DIRECT_A2D_ELEM(in, i, j).real;
+				d = DIRECT_A2D_ELEM(in, i, j).imag;
+				ac = a * c;
+				bd = b * d;
+				ab_cd = (a + b) * (c + d);
+				DIRECT_A2D_ELEM(out, i, j) = Complex(ac - bd, ab_cd - ac - bd);
+			}
+		}
+		break;
+	case 3:
+		xshift = XX(shift);
+		yshift = YY(shift);
+		zshift = ZZ(shift);
+		if (ABS(xshift) < XMIPP_EQUAL_ACCURACY && ABS(yshift) < XMIPP_EQUAL_ACCURACY && ABS(zshift) < XMIPP_EQUAL_ACCURACY)
+		{
+			out = in;
+			return;
+		}
+		for (long int k=0; k<ZSIZE(in); k++)
+		{
+			z = (k < XSIZE(in)) ? k : k - ZSIZE(in);
+			for (long int i=0; i<YSIZE(in); i++)
+			{
+				y = (i < XSIZE(in)) ? i : i - YSIZE(in);
+				for (long int j=0; j<XSIZE(in); j++)
+				{
+					x = j;
+					dotp = 2 * PI * (x * xshift + y * yshift + z * zshift);
+					a = cos(dotp);
+					b = sin(dotp);
+					c = DIRECT_A3D_ELEM(in, k, i, j).real;
+					d = DIRECT_A3D_ELEM(in, k, i, j).imag;
+					ac = a * c;
+					bd = b * d;
+					ab_cd = (a + b) * (c + d);
+					DIRECT_A3D_ELEM(out, k, i, j) = Complex(ac - bd, ab_cd - ac - bd);
+				}
+			}
+		}
+		break;
+	default:
+		REPORT_ERROR("shiftImageInFourierTransform ERROR: dimension should be 1, 2 or 3!");
+	}
+}
+
+void getSpectrum(MultidimArray<double> &Min,
+                 MultidimArray<double> &spectrum,
+                 int spectrum_type)
+{
+
+    MultidimArray<Complex > Faux;
+    int xsize = XSIZE(Min);
+    Matrix1D<double> f(3);
+    MultidimArray<double> count(xsize);
+    FourierTransformer transformer;
+
+    spectrum.initZeros(xsize);
+    count.initZeros();
+    transformer.FourierTransform(Min, Faux, false);
+    FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Faux)
+    {
+    	long int idx = ROUND(sqrt(kp*kp + ip*ip + jp*jp));
+        if (spectrum_type == AMPLITUDE_SPECTRUM)
+            spectrum(idx) += abs(dAkij(Faux, k, i, j));
+        else
+            spectrum(idx) += norm(dAkij(Faux, k, i, j));
+        count(idx) += 1.;
+    }
+
+    for (long int i = 0; i < xsize; i++)
+        if (count(i) > 0.)
+            spectrum(i) /= count(i);
+
+}
+
+void divideBySpectrum(MultidimArray<double> &Min,
+                      MultidimArray<double> &spectrum,
+                      bool leave_origin_intact)
+{
+
+    MultidimArray<double> div_spec(spectrum);
+    FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(spectrum)
+    {
+        if (ABS(dAi(spectrum,i)) > 0.)
+            dAi(div_spec,i) = 1./dAi(spectrum,i);
+        else
+            dAi(div_spec,i) = 1.;
+    }
+    multiplyBySpectrum(Min,div_spec,leave_origin_intact);
+}
+
+void multiplyBySpectrum(MultidimArray<double> &Min,
+                        MultidimArray<double> &spectrum,
+                        bool leave_origin_intact)
+{
+
+    MultidimArray<Complex > Faux;
+    Matrix1D<double> f(3);
+    MultidimArray<double> lspectrum;
+    FourierTransformer transformer;
+    double dim3 = XSIZE(Min)*YSIZE(Min)*ZSIZE(Min);
+
+    transformer.FourierTransform(Min, Faux, false);
+    lspectrum=spectrum;
+    if (leave_origin_intact)
+        lspectrum(0)=1.;
+    FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Faux)
+    {
+    	long int idx = ROUND(sqrt(kp*kp + ip*ip + jp*jp));
+        dAkij(Faux, k, i, j) *=  lspectrum(idx) * dim3;
+    }
+    transformer.inverseFourierTransform();
+
+}
+
+
+void whitenSpectrum(MultidimArray<double> &Min,
+                    MultidimArray<double> &Mout,
+                    int spectrum_type,
+                    bool leave_origin_intact)
+{
+
+    MultidimArray<double> spectrum;
+    getSpectrum(Min,spectrum,spectrum_type);
+    Mout=Min;
+    divideBySpectrum(Mout,spectrum,leave_origin_intact);
+
+}
+
+void adaptSpectrum(MultidimArray<double> &Min,
+                   MultidimArray<double> &Mout,
+                   const MultidimArray<double> &spectrum_ref,
+                   int spectrum_type,
+                   bool leave_origin_intact)
+{
+
+    MultidimArray<double> spectrum;
+    getSpectrum(Min,spectrum,spectrum_type);
+    FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(spectrum)
+    {
+        dAi(spectrum, i) = (dAi(spectrum, i) > 0.) ? dAi(spectrum_ref,i)/ dAi(spectrum, i) : 1.;
+    }
+    Mout=Min;
+    multiplyBySpectrum(Mout,spectrum,leave_origin_intact);
+
+}
+
+/** Kullback-Leibner divergence */
+double getKullbackLeibnerDivergence(MultidimArray<Complex > &Fimg,
+		MultidimArray<Complex > &Fref, MultidimArray<double> &sigma2,
+		MultidimArray<double> &p_i, MultidimArray<double> &q_i, int highshell, int lowshell )
+{
+	// First check dimensions are OK
+	if (!Fimg.sameShape(Fref))
+		REPORT_ERROR("getKullbackLeibnerDivergence ERROR: Fimg and Fref are not of the same shape.");
+
+	if (highshell < 0)
+		highshell = XSIZE(Fimg) - 1;
+	if (lowshell < 0)
+		lowshell = 0;
+
+	if (highshell > XSIZE(sigma2))
+		REPORT_ERROR("getKullbackLeibnerDivergence ERROR: highshell is larger than size of sigma2 array.");
+
+	if (highshell < lowshell)
+		REPORT_ERROR("getKullbackLeibnerDivergence ERROR: highshell is smaller than lowshell.");
+
+	// Initialize the histogram
+	MultidimArray<int> histogram;
+	int histogram_size = 101;
+	int histogram_origin = histogram_size / 2;
+	double sigma_max = 10.;
+	double histogram_factor = histogram_origin / sigma_max;
+	histogram.initZeros(histogram_size);
+
+	// This way this will work in both 2D and 3D
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Fimg)
+	{
+		int ires = ROUND(sqrt(kp*kp + ip*ip + jp*jp));
+		if (ires >= lowshell && ires <= highshell)
+		{
+			// Use FT of masked image for noise estimation!
+			double diff_real = (DIRECT_A3D_ELEM(Fref, k, i, j)).real - (DIRECT_A3D_ELEM(Fimg, k, i, j)).real;
+			double diff_imag = (DIRECT_A3D_ELEM(Fref, k, i, j)).imag - (DIRECT_A3D_ELEM(Fimg, k, i, j)).imag;
+			double sigma = sqrt(DIRECT_A1D_ELEM(sigma2, ires));
+
+			// Divide by standard deviation to normalise all the difference
+			diff_real /= sigma;
+			diff_imag /= sigma;
+
+			// Histogram runs from -10 sigma to +10 sigma
+			diff_real += sigma_max;
+			diff_imag += sigma_max;
+
+			// Make histogram on-the-fly;
+			// Real part
+			int ihis = ROUND(diff_real * histogram_factor);
+			if (ihis < 0)
+				ihis = 0;
+			else if (ihis >= histogram_size)
+				ihis = histogram_size - 1;
+			histogram(ihis)++;
+			// Imaginary part
+			ihis = ROUND(diff_imag * histogram_factor);
+			if (ihis < 0)
+				ihis = 0;
+			else if (ihis > histogram_size)
+				ihis = histogram_size;
+			histogram(ihis)++;
+
+		}
+	}
+
+	// Normalise the histogram and the discretised analytical Gaussian
+	double norm = (double)histogram.sum();
+	double gaussnorm = 0.;
+	for (int i = 0; i < histogram_size; i++)
+	{
+		double x = (double)i / histogram_factor;
+		gaussnorm += gaussian1D(x - sigma_max, 1. , 0.);
+	}
+
+	// Now calculate the actual Kullback-Leibner divergence
+	double kl_divergence = 0.;
+	p_i.resize(histogram_size);
+	q_i.resize(histogram_size);
+	for (int i = 0; i < histogram_size; i++)
+	{
+		// Data distribution
+		p_i(i) = (double)histogram(i) / norm;
+		// Theoretical distribution
+		double x = (double)i / histogram_factor;
+		q_i(i) = gaussian1D(x - sigma_max, 1. , 0.) / gaussnorm;
+
+		if (p_i(i) > 0.)
+			kl_divergence += p_i(i) * log (p_i(i) / q_i(i));
+	}
+	kl_divergence /= (double)histogram_size;
+
+	return kl_divergence;
+
+}
+void resizeMap(MultidimArray<double > &img, int newsize)
+{
+
+	FourierTransformer transformer;
+	MultidimArray<Complex > FT, FT2;
+	transformer.FourierTransform(img, FT, false);
+	windowFourierTransform(FT, FT2, newsize);
+    if (img.getDim() == 2)
+    	img.resize(newsize, newsize);
+    else if (img.getDim() == 3)
+    	img.resize(newsize, newsize, newsize);
+	transformer.inverseFourierTransform(FT2, img);
+
+}
+
+void correctMapForMTF(MultidimArray<Complex > &FT, int ori_size, FileName &fn_mtf)
+{
+
+	MetaDataTable MDmtf;
+
+	if (!fn_mtf.isStarFile())
+		REPORT_ERROR("correctMapForMTF ERROR: input MTF file is not a STAR file.");
+
+	MDmtf.read(fn_mtf);
+	MultidimArray<double> mtf_resol, mtf_value;
+	mtf_resol.resize(MDmtf.numberOfObjects());
+	mtf_value.resize(mtf_resol);
+
+	int i =0;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDmtf)
+	{
+		MDmtf.getValue(EMDL_RESOLUTION_INVPIXEL, DIRECT_A1D_ELEM(mtf_resol, i) ); // resolution needs to be given in 1/pix
+		MDmtf.getValue(EMDL_POSTPROCESS_MTF_VALUE, DIRECT_A1D_ELEM(mtf_value, i) );
+		if (DIRECT_A1D_ELEM(mtf_value, i) < 1e-10)
+		{
+			std::cerr << " i= " << i <<  " mtf_value[i]= " << DIRECT_A1D_ELEM(mtf_value, i) << std::endl;
+			REPORT_ERROR("Postprocessing::sharpenMap ERROR: zero or negative values encountered in MTF curve!");
+		}
+		i++;
+	}
+
+    double xsize = (double)ori_size;
+    FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(FT)
+    {
+    	int r2 = kp * kp + ip * ip + jp * jp;
+    	double res = sqrt((double)r2)/xsize; // get resolution in 1/pixel
+		if (res < 0.5 )
+		{
+
+			// Find the suitable MTF value
+			int i_0 = 0;
+			for (int ii = 0; ii < XSIZE(mtf_resol); ii++)
+			{
+				if (DIRECT_A1D_ELEM(mtf_resol, ii) > res)
+					break;
+				i_0 = ii;
+			}
+			// linear interpolation: y = y_0 + (y_1 - y_0)*(x-x_0)/(x1_x0)
+			double mtf;
+			double x_0 = DIRECT_A1D_ELEM(mtf_resol, i_0);
+			if (i_0 == MULTIDIM_SIZE(mtf_resol) - 1 || i_0 == 0) // check boundaries of the array
+				mtf = DIRECT_A1D_ELEM(mtf_value, i_0);
+			else
+			{
+				double x_1 = DIRECT_A1D_ELEM(mtf_resol, i_0 + 1);
+				double y_0 = DIRECT_A1D_ELEM(mtf_value, i_0);
+				double y_1 = DIRECT_A1D_ELEM(mtf_value, i_0 + 1);
+				mtf = y_0 + (y_1 - y_0)*(res - x_0)/(x_1 - x_0);
+			}
+
+			// Divide Fourier component by the MTF
+			DIRECT_A3D_ELEM(FT, k, i, j) /= mtf;
+		}
+    }
+
+
+
+}
+
+void correctMapForMTF(MultidimArray<double > &img, FileName &fn_mtf)
+{
+	FourierTransformer transformer;
+	MultidimArray<Complex > FT;
+	transformer.FourierTransform(img, FT, false);
+	correctMapForMTF(FT, XSIZE(img), fn_mtf);
+	transformer.inverseFourierTransform();
+
+}
+
+void applyBFactorToMap(MultidimArray<Complex > &FT, int ori_size, double bfactor, double angpix)
+{
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(FT)
+	{
+    	int r2 = kp * kp + ip * ip + jp * jp;
+    	double res = sqrt((double)r2)/(ori_size * angpix); // get resolution in 1/Angstrom
+    	if (res <= 1. / (angpix * 2.) ) // Apply B-factor sharpening until Nyquist, then low-pass filter later on (with a soft edge)
+		{
+    		DIRECT_A3D_ELEM(FT, k, i, j) *= exp( -(bfactor / 4.)  * res * res);
+		}
+		else
+		{
+			DIRECT_A3D_ELEM(FT, k, i, j) = 0.;
+		}
+	}
+}
+
+void applyBFactorToMap(MultidimArray<double > &img, double bfactor, double angpix)
+{
+
+	FourierTransformer transformer;
+	MultidimArray<Complex > FT;
+	transformer.FourierTransform(img, FT, false);
+	applyBFactorToMap(FT, XSIZE(img), bfactor, angpix);
+	transformer.inverseFourierTransform();
+}
+
+
+void lowPassFilterMap(MultidimArray<Complex > &FT, int ori_size,
+		double low_pass, double angpix, int filter_edge_width, bool do_highpass_instead)
+{
+
+	// Which resolution shell is the filter?
+	int ires_filter = ROUND((ori_size * angpix)/low_pass);
+	int filter_edge_halfwidth = filter_edge_width / 2;
+
+	// Soft-edge: from 1 shell less to one shell more:
+	double edge_low = XMIPP_MAX(0., (ires_filter - filter_edge_halfwidth) / (double)ori_size); // in 1/pix
+	double edge_high = XMIPP_MIN(XSIZE(FT), (ires_filter + filter_edge_halfwidth) / (double)ori_size); // in 1/pix
+	double edge_width = edge_high - edge_low;
+
+	// Put a raised cosine from edge_low to edge_high
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(FT)
+	{
+    	int r2 = kp * kp + ip * ip + jp * jp;
+    	double res = sqrt((double)r2)/ori_size; // get resolution in 1/pixel
+
+    	if (do_highpass_instead)
+    	{
+			if (res < edge_low)
+				DIRECT_A3D_ELEM(FT, k, i, j) = 0.;
+			else if (res > edge_high)
+				continue;
+			else
+				DIRECT_A3D_ELEM(FT, k, i, j) *= 0.5 - 0.5 * cos( PI * (res-edge_low)/edge_width);
+    	}
+    	else
+    	{
+			if (res < edge_low)
+				continue;
+			else if (res > edge_high)
+				DIRECT_A3D_ELEM(FT, k, i, j) = 0.;
+			else
+				DIRECT_A3D_ELEM(FT, k, i, j) *= 0.5 + 0.5 * cos( PI * (res-edge_low)/edge_width);
+    	}
+	}
+
+
+}
+
+void lowPassFilterMap(MultidimArray<double > &img, double low_pass, double angpix, int filter_edge_width)
+{
+	FourierTransformer transformer;
+	MultidimArray<Complex > FT;
+
+	// Make this work for maps (or more likely 2D images) that have unequal X and Y dimensions
+	img.setXmippOrigin();
+	int my_xsize = XSIZE(img);
+	int my_ysize = YSIZE(img);
+	int my_size = (my_xsize != my_ysize) ? XMIPP_MAX(my_xsize, my_ysize) : my_xsize;
+	if (my_xsize != my_ysize)
+	{
+		if (img.getDim() == 2)
+		{
+			img.window(FIRST_XMIPP_INDEX(my_size), FIRST_XMIPP_INDEX(my_size),
+					   LAST_XMIPP_INDEX(my_size),  LAST_XMIPP_INDEX(my_size));
+		}
+		else
+		{
+			REPORT_ERROR("lowPassFilterMap: filtering of non-cube maps is not implemented...");
+		}
+	}
+	transformer.FourierTransform(img, FT, false);
+	lowPassFilterMap(FT, XSIZE(img), low_pass, angpix, filter_edge_width, false);
+	transformer.inverseFourierTransform();
+	img.setXmippOrigin();
+	if (my_xsize != my_ysize)
+	{
+		if (img.getDim() == 2)
+		{
+			img.window(FIRST_XMIPP_INDEX(my_ysize), FIRST_XMIPP_INDEX(my_xsize),
+					   LAST_XMIPP_INDEX(my_ysize),  LAST_XMIPP_INDEX(my_xsize));
+		}
+		else
+		{
+			REPORT_ERROR("lowPassFilterMap: filtering of non-cube maps is not implemented...");
+		}
+	}
+
+
+}
+
+void highPassFilterMap(MultidimArray<double > &img, double low_pass, double angpix, int filter_edge_width)
+{
+	FourierTransformer transformer;
+	MultidimArray<Complex > FT;
+	transformer.FourierTransform(img, FT, false);
+	lowPassFilterMap(FT, XSIZE(img), low_pass, angpix, filter_edge_width, true);
+	transformer.inverseFourierTransform();
+}
+
+
+
+void applyBeamTilt(const MultidimArray<Complex > &Fin, MultidimArray<Complex > &Fout, double beamtilt_x, double beamtilt_y,
+		double wavelength, double Cs, double angpix, int ori_size)
+{
+
+	Fout = Fin;
+	selfApplyBeamTilt(Fout, beamtilt_x, beamtilt_y, wavelength, Cs, angpix, ori_size);
+}
+
+void selfApplyBeamTilt(MultidimArray<Complex > &Fimg, double beamtilt_x, double beamtilt_y,
+		double wavelength, double Cs, double angpix, int ori_size)
+{
+	if (Fimg.getDim() != 2)
+		REPORT_ERROR("applyBeamTilt can only be done on 2D Fourier Transforms!");
+
+	double boxsize = angpix * ori_size;
+	double factor = 0.360 * Cs * 10000000 * wavelength * wavelength / (boxsize * boxsize * boxsize);
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM2D(Fimg)
+	{
+		double delta_phase = factor * (ip * ip + jp * jp) * (ip * beamtilt_y + jp * beamtilt_x);
+		double realval = DIRECT_A2D_ELEM(Fimg, i, j).real;
+		double imagval = DIRECT_A2D_ELEM(Fimg, i, j).imag;
+		double mag = sqrt(realval * realval + imagval * imagval);
+		double phas = atan2(imagval, realval) + DEG2RAD(delta_phase); // apply phase shift!
+		realval = mag * cos(phas);
+		imagval = mag * sin(phas);
+		DIRECT_A2D_ELEM(Fimg, i, j) = Complex(realval, imagval);
+	}
+
+}
diff --git a/src/fftw.h b/src/fftw.h
new file mode 100644
index 0000000..dba92ee
--- /dev/null
+++ b/src/fftw.h
@@ -0,0 +1,841 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:    Roberto Marabini                 (roberto at cnb.csic.es)
+ *             Carlos Oscar S. Sorzano          (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef __XmippFFTW_H
+#define __XmippFFTW_H
+
+#include <fftw3.h>
+#include "src/multidim_array.h"
+#include "src/funcs.h"
+#include "src/tabfuncs.h"
+#include "src/complex.h"
+#include "src/metadata_table.h"
+
+/** @defgroup FourierW FFTW Fourier transforms
+  * @ingroup DataLibrary
+  */
+
+/** For all direct elements in the complex array in FFTW format.
+ *
+ * This macro is used to generate loops for the volume in an easy way. It
+ * defines internal indexes 'k','i' and 'j' which ranges the volume using its
+ * physical definition. It also defines 'kp', 'ip' and 'jp', which are the logical coordinates
+ * It also works for 1D or 2D FFTW transforms
+ *
+ * @code
+ * FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(V)
+ * {
+ *     int r2 = jp*jp + ip*ip + kp*kp;
+ *
+ *     std::cout << "element at physical coords: "<< i<<" "<<j<<" "<<k<<" has value: "<<DIRECT_A3D_ELEM(m, k, i, j) << std::endl;
+ *     std::cout << "its logical coords are: "<< ip<<" "<<jp<<" "<<kp<<std::endl;
+ *     std::cout << "its distance from the origin = "<<sqrt(r2)<<std::endl;
+ *
+ * }
+ * @endcode
+ */
+#define FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(V) \
+    for (long int k = 0, kp = 0; k<ZSIZE(V); k++, kp = (k < XSIZE(V)) ? k : k - ZSIZE(V)) \
+    	for (long int i = 0, ip = 0 ; i<YSIZE(V); i++, ip = (i < XSIZE(V)) ? i : i - YSIZE(V)) \
+    		for (long int j = 0, jp = 0; j<XSIZE(V); j++, jp = j)
+
+/** For all direct elements in the complex array in FFTW format.
+ *  The same as above, but now only for 2D images (this saves some time as k is not sampled
+ */
+#define FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM2D(V) \
+	for (long int i = 0, ip = 0 ; i<YSIZE(V); i++, ip = (i < XSIZE(V)) ? i : i - YSIZE(V)) \
+		for (long int j = 0, jp = 0; j<XSIZE(V); j++, jp = j)
+
+/** FFTW volume element: Logical access.
+ *
+ * @code
+ *
+ * FFTW_ELEM(V, -1, -2, 1) = 1;
+ * val = FFTW_ELEM(V, -1, -2, 1);
+ * @endcode
+ */
+#define FFTW_ELEM(V, kp, ip, jp) \
+    DIRECT_A3D_ELEM((V),((kp < 0) ? (kp + ZSIZE(V)) : (kp)), ((ip < 0) ? (ip + YSIZE(V)) : (ip)), (jp))
+
+/** FFTW 2D image element: Logical access.
+ *
+ * @code
+ *
+ * FFTW2D_ELEM(V, --2, 1) = 1;
+ * val = FFTW2D_ELEM(V, -2, 1);
+ * @endcode
+ */
+#define FFTW2D_ELEM(V, ip, jp) \
+    DIRECT_A2D_ELEM((V), ((ip < 0) ? (ip + YSIZE(V)) : (ip)), (jp))
+
+/** Fourier Transformer class.
+ * @ingroup FourierW
+ *
+ * The memory for the Fourier transform is handled by this object.
+ * However, the memory for the real space image is handled externally
+ * and this object only has a pointer to it.
+ *
+ * Here you have an example of use
+ * @code
+ * FourierTransformer transformer;
+ * MultidimArray< Complex > Vfft;
+ * transformer.FourierTransform(V(),Vfft,false);
+ * MultidimArray<double> Vmag;
+ * Vmag.resize(Vfft);
+ * FOR_ALL_ELEMENTS_IN_ARRAY3D(Vmag)
+ *     Vmag(k,i,j)=20*log10(abs(Vfft(k,i,j)));
+ * @endcode
+ */
+class FourierTransformer
+{
+public:
+    /** Real array, in fact a pointer to the user array is stored. */
+    MultidimArray<double> *fReal;
+
+     /** Complex array, in fact a pointer to the user array is stored. */
+    MultidimArray<Complex > *fComplex;
+
+    /** Fourier array  */
+    MultidimArray< Complex > fFourier;
+
+    /* fftw Forawrd plan */
+    fftw_plan fPlanForward;
+
+    /* fftw Backward plan */
+    fftw_plan fPlanBackward;
+
+    /* number of threads*/
+    int nthreads;
+
+    /* Threads has been used in this program*/
+    bool threadsSetOn;
+
+// Public methods
+public:
+    /** Default constructor */
+    FourierTransformer();
+
+    /** Destructor */
+    ~FourierTransformer();
+
+    /** Copy constructor
+     *
+     * The created FourierTransformer is a perfect copy of the input array but with a
+     * different memory assignment.
+     *
+     */
+    FourierTransformer(const FourierTransformer& op);
+
+    /** Set Number of threads
+     * This function, which should be called once, performs any
+     * one-time initialization required to use threads on your
+     * system.
+     *
+     *  The nthreads argument indicates the number of threads you
+     *  want FFTW to use (or actually, the maximum number). All
+     *  plans subsequently created with any planner routine will use
+     *  that many threads. You can call fftw_plan_with_nthreads,
+     *  create some plans, call fftw_plan_with_nthreads again with a
+     *  different argument, and create some more plans for a new
+     *  number of threads. Plans already created before a call to
+     *  fftw_plan_with_nthreads are unaffected. If you pass an
+     *  nthreads argument of 1 (the default), threads are
+     *  disabled for subsequent plans. */
+    void setThreadsNumber(int tNumber);
+
+    /** Compute the Fourier transform of a MultidimArray, 2D and 3D.
+        If getCopy is false, an alias to the transformed data is returned.
+        This is a faster option since a copy of all the data is avoided,
+        but you need to be careful that an inverse Fourier transform may
+        change the data.
+        */
+    template <typename T, typename T1>
+        void FourierTransform(T& v, T1& V, bool getCopy=true)
+        {
+            setReal(v);
+            Transform(FFTW_FORWARD);
+            if (getCopy) getFourierCopy(V);
+            else         getFourierAlias(V);
+        }
+
+    /** Compute the Fourier transform.
+        The data is taken from the matrix with which the object was
+        created. */
+    void FourierTransform();
+
+    /** Inforce Hermitian symmetry.
+        If the Fourier transform risks of losing Hermitian symmetry,
+        use this function to renforce it. */
+    void enforceHermitianSymmetry();
+
+    /** Compute the inverse Fourier transform.
+        The result is stored in the same real data that was passed for
+        the forward transform. The Fourier coefficients are taken from
+        the internal Fourier coefficients */
+    void inverseFourierTransform();
+
+    /** Compute the inverse Fourier transform.
+        New data is provided for the Fourier coefficients and the output
+        can be any matrix1D, 2D or 3D. It is important that the output
+        matrix is already resized to the right size before entering
+        in this function. */
+    template <typename T, typename T1>
+        void inverseFourierTransform(T& V, T1& v)
+        {
+            setReal(v);
+            setFourier(V);
+            Transform(FFTW_BACKWARD);
+        }
+
+    /** Get Fourier coefficients. */
+    template <typename T>
+        void getFourierAlias(T& V) {V.alias(fFourier); return;}
+
+    /** Get Fourier coefficients. */
+    template <typename T>
+        void getFourierCopy(T& V) {
+            V.resize(fFourier);
+            memcpy(MULTIDIM_ARRAY(V),MULTIDIM_ARRAY(fFourier),
+                MULTIDIM_SIZE(fFourier)*2*sizeof(double));
+        }
+
+    /** Return a complete Fourier transform (two halves).
+    */
+    template <typename T>
+        void getCompleteFourier(T& V) {
+            V.resize(*fReal);
+            int ndim=3;
+            if (ZSIZE(*fReal)==1)
+            {
+                ndim=2;
+                if (YSIZE(*fReal)==1)
+                    ndim=1;
+            }
+            switch (ndim)
+            {
+                case 1:
+                    FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(V)
+                        if (i<XSIZE(fFourier))
+                            DIRECT_A1D_ELEM(V,i)=DIRECT_A1D_ELEM(fFourier,i);
+                        else
+                            DIRECT_A1D_ELEM(V,i)=
+                                conj(DIRECT_A1D_ELEM(fFourier,
+                                    XSIZE(*fReal)-i));
+                    break;
+                case 2:
+                    FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(V)
+                        if (j<XSIZE(fFourier))
+                            DIRECT_A2D_ELEM(V,i,j)=
+                                DIRECT_A2D_ELEM(fFourier,i,j);
+                        else
+                            DIRECT_A2D_ELEM(V,i,j)=
+                                conj(DIRECT_A2D_ELEM(fFourier,
+                                    (YSIZE(*fReal)-i)%YSIZE(*fReal),
+                                     XSIZE(*fReal)-j));
+                    break;
+                case 3:
+                    FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(V)
+                        if (j<XSIZE(fFourier))
+                            DIRECT_A3D_ELEM(V,k,i,j)=
+                                DIRECT_A3D_ELEM(fFourier,k,i,j);
+                        else
+                            DIRECT_A3D_ELEM(V,k,i,j)=
+                                conj(DIRECT_A3D_ELEM(fFourier,
+                                    (ZSIZE(*fReal)-k)%ZSIZE(*fReal),
+                                    (YSIZE(*fReal)-i)%YSIZE(*fReal),
+                                     XSIZE(*fReal)-j));
+                    break;
+            }
+        }
+
+    /** Set one half of the FT in fFourier from the input complete Fourier transform (two halves).
+        The fReal and fFourier already should have the right sizes
+    */
+    template <typename T>
+        void setFromCompleteFourier(T& V) {
+        int ndim=3;
+        if (ZSIZE(*fReal)==1)
+        {
+            ndim=2;
+            if (YSIZE(*fReal)==1)
+                ndim=1;
+        }
+        switch (ndim)
+        {
+        case 1:
+            FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(fFourier)
+                DIRECT_A1D_ELEM(fFourier,i)=DIRECT_A1D_ELEM(V,i);
+            break;
+        case 2:
+            FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(fFourier)
+                DIRECT_A2D_ELEM(fFourier,i,j) = DIRECT_A2D_ELEM(V,i,j);
+            break;
+        case 3:
+            FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(fFourier)
+                DIRECT_A3D_ELEM(fFourier,k,i,j) = DIRECT_A3D_ELEM(V,k,i,j);
+            break;
+        }
+    }
+
+// Internal methods
+public:
+    /* Pointer to the array of doubles with which the plan was computed */
+    double * dataPtr;
+
+    /* Pointer to the array of complex<double> with which the plan was computed */
+    Complex * complexDataPtr;
+
+    /* Initialise all pointers to NULL */
+    void init();
+
+    /** Clear object */
+    void clear();
+
+    /** This calls fftw_cleanup.
+     * NOTE!! When using multiple threads, only ONE thread can call this function, as it cleans up things that are shared among all threads...
+ 	 *  Therefore, this cleanup is something that needs to be done manually...
+    */
+    void cleanup();
+
+    /** Destroy both forward and backward fftw planes (mutex locked */
+    void destroyPlans();
+
+    /** Computes the transform, specified in Init() function
+        If normalization=true the forward transform is normalized
+        (no normalization is made in the inverse transform)
+        If normalize=false no normalization is performed and therefore
+        the image is scaled by the number of pixels.
+    */
+    void Transform(int sign);
+
+    /** Get the Multidimarray that is being used as input. */
+    const MultidimArray<double> &getReal() const;
+    const MultidimArray<Complex > &getComplex() const;
+
+    /** Set a Multidimarray for input.
+        The data of img will be the one of fReal. In forward
+        transforms it is not modified, but in backward transforms,
+        the result will be stored in img. This means that the size
+        of img cannot change between calls. */
+    void setReal(MultidimArray<double> &img);
+
+    /** Set a Multidimarray for input.
+        The data of img will be the one of fComplex. In forward
+        transforms it is not modified, but in backward transforms,
+        the result will be stored in img. This means that the size
+        of img cannot change between calls. */
+    void setReal(MultidimArray<Complex > &img);
+
+    /** Set a Multidimarray for the Fourier transform.
+        The values of the input array are copied in the internal array.
+        It is assumed that the container for the real image as well as
+        the one for the Fourier array are already resized.
+        No plan is updated. */
+    void setFourier(MultidimArray<Complex > &imgFourier);
+};
+
+// Randomize phases beyond the given shell (index)
+void randomizePhasesBeyond(MultidimArray<double> &I, int index);
+
+/** Center an array, to have its origin at the origin of the FFTW
+ *
+ */
+template <typename T>
+void CenterFFT(MultidimArray< T >& v, bool forward)
+{
+    if ( v.getDim() == 1 )
+    {
+        // 1D
+        MultidimArray< T > aux;
+        int l, shift;
+
+        l = XSIZE(v);
+        aux.resize(l);
+        shift = (int)(l / 2);
+
+        if (!forward)
+            shift = -shift;
+
+        // Shift the input in an auxiliar vector
+        for (int i = 0; i < l; i++)
+        {
+            int ip = i + shift;
+
+            if (ip < 0)
+                ip += l;
+            else if (ip >= l)
+                ip -= l;
+
+            aux(ip) = DIRECT_A1D_ELEM(v, i);
+        }
+
+        // Copy the vector
+        for (int i = 0; i < l; i++)
+            DIRECT_A1D_ELEM(v, i) = DIRECT_A1D_ELEM(aux, i);
+    }
+    else if ( v.getDim() == 2 )
+    {
+        // 2D
+        MultidimArray< T > aux;
+        int l, shift;
+
+        // Shift in the X direction
+        l = XSIZE(v);
+        aux.resize(l);
+        shift = (int)(l / 2);
+
+        if (!forward)
+            shift = -shift;
+
+        for (int i = 0; i < YSIZE(v); i++)
+        {
+            // Shift the input in an auxiliar vector
+            for (int j = 0; j < l; j++)
+            {
+                int jp = j + shift;
+
+                if (jp < 0)
+                    jp += l;
+                else if (jp >= l)
+                    jp -= l;
+
+                aux(jp) = DIRECT_A2D_ELEM(v, i, j);
+            }
+
+            // Copy the vector
+            for (int j = 0; j < l; j++)
+                DIRECT_A2D_ELEM(v, i, j) = DIRECT_A1D_ELEM(aux, j);
+        }
+
+        // Shift in the Y direction
+        l = YSIZE(v);
+        aux.resize(l);
+        shift = (int)(l / 2);
+
+        if (!forward)
+            shift = -shift;
+
+        for (int j = 0; j < XSIZE(v); j++)
+        {
+            // Shift the input in an auxiliar vector
+            for (int i = 0; i < l; i++)
+            {
+                int ip = i + shift;
+
+                if (ip < 0)
+                    ip += l;
+                else if (ip >= l)
+                    ip -= l;
+
+                aux(ip) = DIRECT_A2D_ELEM(v, i, j);
+            }
+
+            // Copy the vector
+            for (int i = 0; i < l; i++)
+                DIRECT_A2D_ELEM(v, i, j) = DIRECT_A1D_ELEM(aux, i);
+        }
+    }
+    else if ( v.getDim() == 3 )
+    {
+        // 3D
+        MultidimArray< T > aux;
+        int l, shift;
+
+        // Shift in the X direction
+        l = XSIZE(v);
+        aux.resize(l);
+        shift = (int)(l / 2);
+
+        if (!forward)
+            shift = -shift;
+
+        for (int k = 0; k < ZSIZE(v); k++)
+            for (int i = 0; i < YSIZE(v); i++)
+            {
+                // Shift the input in an auxiliar vector
+                for (int j = 0; j < l; j++)
+                {
+                    int jp = j + shift;
+
+                    if (jp < 0)
+                        jp += l;
+                    else if (jp >= l)
+                        jp -= l;
+
+                    aux(jp) = DIRECT_A3D_ELEM(v, k, i, j);
+                }
+
+                // Copy the vector
+                for (int j = 0; j < l; j++)
+                    DIRECT_A3D_ELEM(v, k, i, j) = DIRECT_A1D_ELEM(aux, j);
+            }
+
+        // Shift in the Y direction
+        l = YSIZE(v);
+        aux.resize(l);
+        shift = (int)(l / 2);
+
+        if (!forward)
+            shift = -shift;
+
+        for (int k = 0; k < ZSIZE(v); k++)
+            for (int j = 0; j < XSIZE(v); j++)
+            {
+                // Shift the input in an auxiliar vector
+                for (int i = 0; i < l; i++)
+                {
+                    int ip = i + shift;
+
+                    if (ip < 0)
+                        ip += l;
+                    else if (ip >= l)
+                        ip -= l;
+
+                    aux(ip) = DIRECT_A3D_ELEM(v, k, i, j);
+                }
+
+                // Copy the vector
+                for (int i = 0; i < l; i++)
+                    DIRECT_A3D_ELEM(v, k, i, j) = DIRECT_A1D_ELEM(aux, i);
+            }
+
+        // Shift in the Z direction
+        l = ZSIZE(v);
+        aux.resize(l);
+        shift = (int)(l / 2);
+
+        if (!forward)
+            shift = -shift;
+
+        for (int i = 0; i < YSIZE(v); i++)
+            for (int j = 0; j < XSIZE(v); j++)
+            {
+                // Shift the input in an auxiliar vector
+                for (int k = 0; k < l; k++)
+                {
+                    int kp = k + shift;
+                    if (kp < 0)
+                        kp += l;
+                    else if (kp >= l)
+                        kp -= l;
+
+                    aux(kp) = DIRECT_A3D_ELEM(v, k, i, j);
+                }
+
+                // Copy the vector
+                for (int k = 0; k < l; k++)
+                    DIRECT_A3D_ELEM(v, k, i, j) = DIRECT_A1D_ELEM(aux, k);
+            }
+    }
+    else
+    {
+    	v.printShape();
+    	REPORT_ERROR("CenterFFT ERROR: Dimension should be 1, 2 or 3");
+    }
+}
+
+
+
+// Window an FFTW-centered Fourier-transform to a given size
+template<class T>
+void windowFourierTransform(MultidimArray<T > &in,
+			  			    MultidimArray<T > &out,
+			  			    long int newdim)
+{
+	// Check size of the input array
+	if (YSIZE(in) > 1 && YSIZE(in)/2 + 1 != XSIZE(in))
+		REPORT_ERROR("windowFourierTransform ERROR: the Fourier transform should be of an image with equal sizes in all dimensions!");
+	long int newhdim = newdim/2 + 1;
+
+	// If same size, just return input
+	if (newhdim == XSIZE(in))
+	{
+		out = in;
+		return;
+	}
+
+	// Otherwise apply a windowing operation
+	// Initialise output array
+	switch (in.getDim())
+	{
+	case 1:
+		out.initZeros(newhdim);
+		break;
+	case 2:
+		out.initZeros(newdim, newhdim);
+		break;
+	case 3:
+		out.initZeros(newdim, newdim, newhdim);
+		break;
+	default:
+    	REPORT_ERROR("windowFourierTransform ERROR: dimension should be 1, 2 or 3!");
+    }
+	if (newhdim > XSIZE(in))
+	{
+		long int max_r2 = (XSIZE(in) -1) * (XSIZE(in) - 1);
+		FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(in)
+		{
+			// Make sure windowed FT has nothing in the corners, otherwise we end up with an asymmetric FT!
+			if (kp*kp + ip*ip + jp*jp <= max_r2)
+				FFTW_ELEM(out, kp, ip, jp) = FFTW_ELEM(in, kp, ip, jp);
+		}
+	}
+	else
+	{
+		FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(out)
+		{
+			FFTW_ELEM(out, kp, ip, jp) = FFTW_ELEM(in, kp, ip, jp);
+		}
+	}
+}
+
+// A resize operation in Fourier-space (i.e. changing the sampling of the Fourier Transform) by windowing in real-space
+// If recenter=true, the real-space array will be recentered to have its origin at the origin of the FT
+template<class T>
+void resizeFourierTransform(MultidimArray<T > &in,
+			  			    MultidimArray<T > &out,
+			  			    long int newdim, bool do_recenter=true)
+{
+	// Check size of the input array
+	if (YSIZE(in) > 1 && YSIZE(in)/2 + 1 != XSIZE(in))
+		REPORT_ERROR("windowFourierTransform ERROR: the Fourier transform should be of an image with equal sizes in all dimensions!");
+	long int newhdim = newdim/2 + 1;
+	long int olddim = 2* (XSIZE(in) - 1);
+
+	// If same size, just return input
+	if (newhdim == XSIZE(in))
+	{
+		out = in;
+		return;
+	}
+
+	// Otherwise apply a windowing operation
+	MultidimArray<Complex > Fin;
+	MultidimArray<double> Min;
+	FourierTransformer transformer;
+	long int x0, y0, z0, xF, yF, zF;
+	x0 = y0 = z0 = FIRST_XMIPP_INDEX(newdim);
+	xF = yF = zF = LAST_XMIPP_INDEX(newdim);
+
+	// Initialise output array
+	switch (in.getDim())
+	{
+	case 1:
+		Min.resize(olddim);
+		y0=yF=z0=zF=0;
+		break;
+	case 2:
+		Min.resize(olddim, olddim);
+		z0=zF=0;
+		break;
+	case 3:
+		Min.resize(olddim, olddim, olddim);
+		break;
+	default:
+    	REPORT_ERROR("resizeFourierTransform ERROR: dimension should be 1, 2 or 3!");
+    }
+
+	// This is to handle double-valued input arrays
+	Fin.resize(ZSIZE(in), YSIZE(in), XSIZE(in));
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(in)
+	{
+		DIRECT_MULTIDIM_ELEM(Fin, n) = DIRECT_MULTIDIM_ELEM(in, n);
+	}
+	transformer.inverseFourierTransform(Fin, Min);
+	Min.setXmippOrigin();
+	if (do_recenter)
+		CenterFFT(Min, false);
+
+	// Now do the actual windowing in real-space
+	Min.window(z0, y0, x0, zF, yF, xF);
+	Min.setXmippOrigin();
+
+	// If upsizing: mask the corners to prevent aliasing artefacts
+	if (newdim > olddim)
+	{
+		FOR_ALL_ELEMENTS_IN_ARRAY3D(Min)
+		{
+			if (k*k + i*i + j*j > olddim*olddim/4)
+			{
+				A3D_ELEM(Min, k, i, j) = 0.;
+			}
+		}
+	}
+
+	// Recenter FFT back again
+	if (do_recenter)
+		CenterFFT(Min, true);
+
+	// And do the inverse Fourier transform
+	transformer.clear();
+	transformer.FourierTransform(Min, out);
+}
+
+/** Fourier-Ring-Correlation between two multidimArrays using FFT
+ * From precalculated Fourier Transforms
+ * Simpler I/O than above.
+ */
+void getFSC(MultidimArray< Complex > &FT1,
+		    MultidimArray< Complex > &FT2,
+		    MultidimArray< double > &fsc);
+
+/** Fourier-Ring-Correlation between two multidimArrays using FFT
+ * @ingroup FourierOperations
+ * Simpler I/O than above.
+ */
+void getFSC(MultidimArray< double > & m1,
+		    MultidimArray< double > & m2,
+		    MultidimArray< double > &fsc);
+
+/** Scale matrix using Fourier transform
+ * @ingroup FourierOperations
+ * Ydim and Xdim define the output size, Mpmem is the matrix to scale
+ */
+//void selfScaleToSizeFourier(long int Ydim, long int Xdim, MultidimArray<double>& Mpmem, int nthreads=1);
+
+// Shift an image through phase-shifts in its Fourier Transform
+// Note that in and out may be the same array, in that case in is overwritten with the result
+// if oridim is in pixels, xshift, yshift and zshift should be in pixels as well!
+// or both can be in Angstroms
+void shiftImageInFourierTransform(MultidimArray<Complex > &in,
+								  MultidimArray<Complex > &out,
+								  TabSine &tab_sin, TabCosine &tab_cos,
+								  double oridim, Matrix1D<double> shift);
+
+// Shift an image through phase-shifts in its Fourier Transform (without tabulated sine and cosine)
+// Note that in and out may be the same array, in that case in is overwritten with the result
+// if oridim is in pixels, xshift, yshift and zshift should be in pixels as well!
+// or both can be in Angstroms
+void shiftImageInFourierTransform(MultidimArray<Complex > &in,
+						          MultidimArray<Complex > &out,
+								  double oridim, Matrix1D<double> shift);
+
+#define POWER_SPECTRUM 0
+#define AMPLITUDE_SPECTRUM 1
+
+/** Get the amplitude or power_class spectrum of the map in Fourier space.
+ * @ingroup FourierOperations
+    i.e. the radial average of the (squared) amplitudes of all Fourier components
+*/
+void getSpectrum(MultidimArray<double> &Min,
+                 MultidimArray<double> &spectrum,
+                 int spectrum_type=POWER_SPECTRUM);
+
+/** Divide the input map in Fourier-space by the spectrum provided.
+ * @ingroup FourierOperations
+    If leave_origin_intact==true, the origin pixel will remain untouched
+*/
+void divideBySpectrum(MultidimArray<double> &Min,
+                      MultidimArray<double> &spectrum,
+                      bool leave_origin_intact=false);
+
+/** Multiply the input map in Fourier-space by the spectrum provided.
+ * @ingroup FourierOperations
+    If leave_origin_intact==true, the origin pixel will remain untouched
+*/
+void multiplyBySpectrum(MultidimArray<double> &Min,
+                        MultidimArray<double> &spectrum,
+                        bool leave_origin_intact=false);
+
+/** Perform a whitening of the amplitude/power_class spectrum of a 3D map
+ * @ingroup FourierOperations
+    If leave_origin_intact==true, the origin pixel will remain untouched
+*/
+void whitenSpectrum(MultidimArray<double> &Min,
+                    MultidimArray<double> &Mout,
+                    int spectrum_type=AMPLITUDE_SPECTRUM,
+                    bool leave_origin_intact=false);
+
+/** Adapts Min to have the same spectrum as spectrum_ref
+ * @ingroup FourierOperations
+    If only_amplitudes==true, the amplitude rather than the power_class spectrum will be equalized
+*/
+void adaptSpectrum(MultidimArray<double> &Min,
+                   MultidimArray<double> &Mout,
+                   const MultidimArray<double> &spectrum_ref,
+                   int spectrum_type=AMPLITUDE_SPECTRUM,
+                   bool leave_origin_intact=false);
+
+/** Kullback-Leibner divergence */
+double getKullbackLeibnerDivergence(MultidimArray<Complex > &Fimg,
+		MultidimArray<Complex > &Fref, MultidimArray<double> &sigma2,
+		MultidimArray<double> &p_i, MultidimArray<double> &q_i,
+		int highshell = -1, int lowshell = -1);
+
+
+// Resize a map by windowing it's Fourier Transform
+void resizeMap(MultidimArray<double > &img, int newsize);
+
+
+// Correct a map by its MTF-curve
+void correctMapForMTF(MultidimArray<Complex > &FT, int ori_size, FileName &fn_mtf);
+void correctMapForMTF(MultidimArray<double > &img, FileName &fn_mtf);
+
+// Apply a B-factor to a map (given it's Fourier transform)
+void applyBFactorToMap(MultidimArray<Complex > &FT, int ori_size, double bfactor, double angpix);
+
+// Apply a B-factor to a map (given it's real-space array)
+void applyBFactorToMap(MultidimArray<double > &img, double bfactor, double angpix);
+
+// Low-pass filter a map (given it's Fourier transform)
+void lowPassFilterMap(MultidimArray<Complex > &FT, int ori_size,
+		double low_pass, double angpix, int filter_edge_width = 2, bool do_highpass_instead = false);
+
+// Low-pass and high-pass filter a map (given it's real-space array)
+void lowPassFilterMap(MultidimArray<double > &img, double low_pass, double angpix, int filter_edge_width = 2);
+void highPassFilterMap(MultidimArray<double > &img, double low_pass, double angpix, int filter_edge_width = 2);
+
+/*
+ *  Beamtilt x and y are given in mradians
+ *  Wavelength in Angstrom, Cs in mm
+ *  Phase shifts caused by the beamtilt will be calculated and applied to Fimg
+ */
+void selfApplyBeamTilt(MultidimArray<Complex > &Fimg, double beamtilt_x, double beamtilt_y,
+		double wavelength, double Cs, double angpix, int ori_size);
+
+void applyBeamTilt(const MultidimArray<Complex > &Fin, MultidimArray<Complex > &Fout, double beamtilt_x, double beamtilt_y,
+		double wavelength, double Cs, double angpix, int ori_size);
+
+#endif
diff --git a/src/filename.cpp b/src/filename.cpp
new file mode 100644
index 0000000..335e60a
--- /dev/null
+++ b/src/filename.cpp
@@ -0,0 +1,434 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include "src/filename.h"
+#include "src/funcs.h"
+
+// Constructor with root, number and extension .............................
+void FileName::compose(const std::string &str, long int no, const std::string &ext, int numberlength)
+{
+    *this = (FileName) str;
+    if (no != -1)
+    {
+
+        char aux_str[numberlength+1];
+        std::string tmp_fileformat;
+        tmp_fileformat = (std::string) "%0" +
+                         integerToString(numberlength)+
+                         (std::string)"d";
+        sprintf(aux_str, tmp_fileformat.c_str(), no);
+        *this += aux_str;
+    }
+
+    if (ext != "")
+        *this += (std::string)"." + ext;
+}
+
+// Constructor: prefix number and filename, mainly for selfiles..
+void FileName::compose(long int no , const std::string &str, int numberlength)
+{
+    *this = (FileName) str;
+    if (no != -1)
+    {
+
+        char aux_str[numberlength+1];
+        std::string tmp_fileformat;
+        tmp_fileformat = (std::string) "%0" +
+                         integerToString(numberlength)+
+                         (std::string)"d@";
+        sprintf(aux_str, tmp_fileformat.c_str(), no);
+        *this = aux_str + str;
+    }
+    else
+        *this = str;
+
+
+}
+
+// Is in stack ............................................................
+bool FileName::isInStack() const
+{
+    return find("@") != std::string::npos;
+}
+
+// Decompose ..............................................................
+void FileName::decompose(long int &no, std::string &str) const
+{
+    size_t idx = find('@');
+    if(idx != std::string::npos)
+    {
+        no = textToInteger(substr(0,idx));
+        str = substr(idx+1,length()-idx);
+    }
+    else{
+      no=-1;
+      str = *this;
+    }
+}
+
+// Convert to lower case characters .........................................
+FileName FileName::toLowercase() const
+{
+    FileName result = *this;
+    for(unsigned int i=0;i<result.length();i++)
+        result[i] = tolower(result[i]);
+    return result;
+}
+
+// Convert to upper case characters .........................................
+FileName FileName::toUppercase() const
+{
+    FileName result = *this;
+    for(unsigned int i=0;i<result.length();i++)
+        result[i] = toupper(result[i]);
+    return result;
+}
+
+// Is substring present?
+bool FileName::contains(const std::string& str) const
+{
+    int point = rfind(str);
+    if (point > -1)
+        return true;
+    else
+        return false;
+}
+
+// Get substring before first instance of str
+FileName FileName::beforeFirstOf(const std::string& str) const
+{
+    int point = find_first_of(str);
+    if (point > -1)
+        return substr(0, point);
+    else
+        return *this;
+}
+
+// Get substring before last instance of str
+FileName FileName::beforeLastOf(const std::string& str) const
+{
+    int point = find_last_of(str);
+    if (point > -1)
+        return substr(0, point);
+    else
+        return *this;
+}
+
+// Get substring after first instance of str
+FileName FileName::afterFirstOf(const std::string& str) const
+{
+    int point = find_first_of(str);
+    if (point > -1)
+        return substr(point + 1);
+    else
+        return *this;
+}
+
+// Get substring after last instance of str
+FileName FileName::afterLastOf(const std::string& str) const
+{
+    int point = find_last_of(str);
+    if (point > -1)
+        return substr(point + 1);
+    else
+        return *this;
+}
+
+// Get the base name of a filename .........................................
+std::string FileName::getBaseName() const
+{
+    std::string basename = "";
+    std::string myname = *this;
+    int myindex = 0;
+    for (int p = myname.size() - 1; p >= 0; p--)
+    {
+        if (myname[p] == '/')
+        {
+            myindex = p + 1;
+            break;
+        }
+    }
+    for (int p = myindex; p < myname.size(); p++)
+    {
+        if (myname[p] != '.')
+            basename += myname[p];
+        else
+            break;
+    }
+    return basename;
+}
+
+// Get the extension of a filename .........................................
+std::string FileName::getExtension() const
+{
+    int last_point = find_last_of(".");
+    if (last_point == -1)
+        return "";
+    else
+        return substr(last_point + 1);
+}
+
+// Init random .............................................................
+void FileName::initRandom(int length)
+{
+    randomize_random_generator();
+    *this = "";
+    for (int i = 0; i < length; i++)
+        *this += 'a' + FLOOR(rnd_unif(0, 26));
+}
+
+// Add at beginning ........................................................
+FileName FileName::addPrefix(const std::string &prefix) const
+{
+    FileName retval = *this;
+    int skip_directories = find_last_of("/") + 1;
+    return retval.insert(skip_directories, prefix);
+}
+
+// Add at the end ..........................................................
+FileName FileName::addExtension(const std::string &ext) const
+{
+    if (ext == "")
+        return *this;
+    else
+    {
+        FileName retval = *this;
+        retval = retval.append((std::string)"." + ext);
+        return retval;
+    }
+}
+
+// Remove last extension ...................................................
+FileName FileName::withoutExtension() const
+{
+    FileName retval = *this;
+    return retval.substr(0, rfind("."));
+}
+
+// Insert before extension .................................................
+FileName FileName::insertBeforeExtension(const std::string &str) const
+{
+    int point = -1;
+    bool done = false;
+    do
+    {
+        point = find(".", point + 1);
+        if (point == -1)
+        {
+            point = length();
+            done = true;
+        }
+        else if (point == length() - 1)
+            done = true;
+        else if ((*this)[point+1] == '.' || (*this)[point+1] == '/')
+            done = false;
+        else
+            done = true;
+    }
+    while (!done);
+    FileName retval = *this;
+    return retval.insert(point, str);
+}
+
+// Remove an extension wherever it is ......................................
+FileName FileName::removeExtension(const std::string &ext) const
+{
+    int first = find((std::string)"." + ext);
+    if (first == -1)
+        return *this;
+    else
+    {
+        FileName retval = *this;
+        return retval.erase(first, 1 + ext.length());
+    }
+}
+
+// Remove all extensions....................................................
+FileName FileName::removeAllExtensions() const
+{
+    int first = rfind("/");
+    first = find(".", first + 1);
+    if (first == -1)
+        return *this;
+    else
+        return substr(0, first);
+}
+
+FileName FileName::getFileFormat() const
+{
+    int first;
+    FileName result;
+    if (find("#") != std::string::npos)
+        return "raw";
+    else if ( (first = rfind(":"))!=std::string::npos)
+        result = substr(first + 1) ;
+    else if ( (first = rfind("."))!=std::string::npos)
+        result = substr(first + 1);
+    else
+        result="spi";
+    return result.toLowercase();
+
+}
+
+FileName FileName::removeFileFormat() const
+{
+    if ( find("#", 0) > -1 )
+        REPORT_ERROR("Not implemented for raw data");
+    size_t found=rfind(":");
+    if (found!=std::string::npos)
+        return substr(0, found);
+    return *this;
+}
+
+bool FileName::isStarFile() const
+{
+    //file names containing @, : or % are not metadatas
+    size_t found=this->find('@');
+    if (found!=std::string::npos)
+        return false;
+    found=this->find(':');
+    if (found!=std::string::npos)
+        return false;
+    found=this->find('#');
+    if (found!=std::string::npos)
+        return false;
+
+    FileName ext = getFileFormat();
+    if (ext=="star")
+    {
+        return true;
+    }
+    else
+    {
+    	return false;
+    }
+}
+
+// Substitute one extension by other .......................................
+FileName FileName::substituteExtension(const std::string &ext1,
+                                       const std::string &ext2) const
+{
+    int first = find((std::string)"." + ext1);
+    if (first == -1)
+        return *this;
+    else
+    {
+        FileName retval = *this;
+        return retval.replace(first, 1 + ext1.length(), (std::string)"." + ext2);
+    }
+}
+
+// Remove a substring ......................................................
+FileName FileName::without(const std::string &str) const
+{
+    if (str.length() == 0)
+        return *this;
+    int pos = find(str);
+    if (pos == -1)
+        return *this;
+    else
+    {
+        FileName retval = *this;
+        return retval.erase(pos, str.length());
+    }
+}
+
+// Remove until prefix .....................................................
+FileName FileName::removeUntilPrefix(const std::string &str) const
+{
+    if (str.length() == 0)
+        return *this;
+    int pos = find(str);
+    if (pos == -1)
+        return *this;
+    else
+    {
+        FileName retval = *this;
+        return retval.erase(0, pos + str.length());
+    }
+}
+
+// Remove directories ......................................................
+FileName FileName::removeDirectories(int keep) const
+{
+    int last_slash = rfind("/");
+    int tokeep = keep;
+    while (tokeep > 0)
+    {
+        last_slash = rfind("/", last_slash - 1);
+        tokeep--;
+    }
+    if (last_slash == -1)
+        return *this;
+    else
+        return substr(last_slash + 1, length() - last_slash);
+}
+void FileName::copyFile(const FileName & target) const
+{
+    std::ifstream f1 (this->c_str(), std::fstream::binary);
+    std::ofstream f2 (target.c_str(),std::fstream::trunc|std::fstream::binary);
+    f2<<f1.rdbuf();
+}
+
+int FileName::globFiles(std::vector<FileName> &files) const
+{
+	glob_t glob_result;
+	glob((*this).c_str(), GLOB_TILDE, NULL, &glob_result);
+	files.clear();
+	for(unsigned  int  i = 0; i < glob_result.gl_pathc; ++i)
+	{
+		files.push_back(std::string(glob_result.gl_pathv[i]));
+	}
+	globfree(&glob_result);
+	return files.size();
+}
+
+bool exists(const FileName &fn)
+{
+    FILE *aux;
+    if ((aux = fopen(fn.c_str(), "r")) == NULL)
+        return false;
+    fclose(aux);
+    return true;
+}
diff --git a/src/filename.h b/src/filename.h
new file mode 100644
index 0000000..9afcf1d
--- /dev/null
+++ b/src/filename.h
@@ -0,0 +1,520 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef FILENAME_H_
+#define FILENAME_H_
+
+#include <iostream>
+#include <fstream>
+#include <cmath>
+#include <complex>
+#include <cstdlib>
+#include <cstdio>
+#include <string>
+#include <climits>
+#include <algorithm>
+#include <vector>
+#include <typeinfo>
+
+#include <glob.h>
+
+#include "src/numerical_recipes.h"
+#include "src/macros.h"
+#include "src/error.h"
+#include "src/strings.h"
+
+#define FILENAMENUMBERLENGTH 6
+
+//@{
+/** Filenames.
+ *
+ * This class allows you a lot of usual and common manipulations with filenames.
+ * See filename conventions for a detailed explanation of the Filenames dealed
+ * here, although most of the functions work with the more general model
+ * "name.extension"
+ */
+class FileName: public std::string
+{
+public:
+    /// @name Filename constructors
+    /// @{
+
+    /** Empty constructor
+     *
+     * The empty constructor is inherited from the string class, so an empty
+     * FileName is equal to "".
+     *
+     * @code
+     * FileName fn_blobs;
+     * @endcode
+     */
+    FileName(): std::string("") {}
+
+    /* Destructor
+     */
+    ~FileName() {}
+
+    /** Constructor from string
+     *
+     * The constructor from a string allows building complex expressions based
+     * on the string class. Notice that in the following example the type
+     * casting to string is very important, if not, the operation is just a
+     * pointer movement instead of a string concatenation.
+     *
+     * @code
+     * FileName fn_blobs((std::string) "art00001" + ".blobs");
+     * @endcode
+     */
+    FileName(const std::string& str): std::string(str)   {}
+
+    /** Constructor from char*
+     */
+    FileName(const char* str): std::string(str)  {}
+
+    /** Copy constructor
+     */
+    FileName(const FileName& fn): std::string(fn)   {}
+
+    /** Assignment constructor
+     */
+    FileName& operator=(const FileName& op){
+    	return (FileName&) std::string::operator=(op);
+    }
+
+    /** Constructor from root, number and extension
+     *
+     * The number and extension are optional.
+     *
+     * @code
+     * FileName fn_proj("g1ta000001.xmp"); // fn_proj = "g1ta000001.xmp"
+     * FileName fn_proj("g1ta",1,"xmp"); // fn_proj = "g1ta000001.xmp"
+     * FileName fn_proj("g1ta",1); // fn_proj = "g1ta000001"
+     * @endcode
+     */
+    FileName(const char* str, long int no, const std::string& ext = "")
+    {
+        compose(str, no, ext);
+    }
+
+    /** Constructor from root and extension
+     *
+     * None of the parameters is optional
+     *
+     * @code
+     * FileName fn_proj("g1ta00001", "xmp"); // fn_proj = "g1ta00001.xmp"
+     * @endcode
+     */
+    FileName(const char* str, const std::string& ext): std::string(str + ext)
+    {}
+    //@}
+
+    /// @name Composing/Decomposing the filename
+    /// @{
+
+    /** Compose from root, number and extension
+     *
+     * @code
+     * fn_proj.compose("g1ta", 1, "xmp");  // fn_proj = "g1ta000001.xmp"
+     * @endcode
+     */
+    void compose(const std::string& str, long int no, const std::string& ext, int numberlength = FILENAMENUMBERLENGTH);
+
+    /** Prefix with number @. Mainly for selfiles
+     *
+     * @code
+     * fn_proj.compose(1,"g1ta.xmp");  // fn_proj = "000001 at g1ta.xmp"
+     * @endcode
+     */
+    void compose(long int no, const std::string& str, int numberlength = FILENAMENUMBERLENGTH);
+
+    /** True if this filename belongs to a stack
+     */
+    bool isInStack() const;
+
+    /** Decompose filenames with @. Mainly from selfiles
+     *
+     * @code
+     * fn_proj.decompose(no,filename);  // fn_proj = "000001 at g1ta000001.xmp"
+     *                                  // no=1
+     *                                  // filename = "g1ta000001.xmp"
+     * @endcode
+     */
+    void decompose(long int &no, std::string& str) const;
+
+    /** Get the base name from a filename
+     */
+    std::string getBaseName() const;
+
+    /** Get the last extension from filename
+     *
+     * The extension is returned without the dot. If there is no extension "" is
+     * returned.
+     *
+     * @code
+     * std::string ext = fn_proj.get_extension();
+     * @endcode
+     */
+    std::string getExtension() const;
+
+    /** Get image format identifier (as in Bsoft)
+     *
+     * @code
+     * fn_proj = "g1ta00001.xmp";
+     * fn_proj = fn_proj.get_file_format(); // fn_proj == "xmp"
+     * fn_proj = "g1ta00001.nor:spi";
+     * fn_proj = fn_proj.get_file_format(); // fn_proj == "spi"
+     * fn_proj = "input.file#d=f#x=120,120,55#h=1024";
+     * fn_proj = fn_proj.get_file_format(); // fn_proj == "raw"
+     * @endcode
+     */
+    FileName getFileFormat() const;
+
+    /** Random name
+     *
+     * Generate a random name of the desired length.
+     */
+    void initRandom(int length);
+    //@}
+
+    ///@name Filename utilities
+    //@{
+    /** Change all characters for lowercases
+     *
+     * @code
+     * FileName fn_proj("g1tA00001");
+     * fn_proj = fn_proj.to_lowercase(); // fn_proj = "g1ta00001"
+     * @endcode
+     */
+    FileName toLowercase() const;
+
+    /** Change all characters for uppercases
+     *
+     * @code
+     * FileName fn_proj("g1tA00001");
+     * fn_proj = fn_proj.to_uppercase(); // fn_proj = "G1Ta00001"
+     * @endcode
+     */
+    FileName toUppercase() const;
+
+    /** Check whether the filename contains the argument substring
+     *
+     * @code
+     * FileName fn_proj("g1ta00001.raw#d=f");
+     * if (fn_proj.contains("raw) )  // true
+     * @endcode
+     */
+    bool contains(const std::string& str) const;
+
+    /** Return substring before first instance of argument (as in Bsoft)
+     *
+      * @code
+     * FileName fn_proj("g1ta00001.raw#d=f");
+     * fn_proj = fn_proj.before_first_of("#"); // fn_proj = "g1ta00001.raw"
+     * @endcode
+     */
+    FileName beforeFirstOf(const std::string& str) const;
+
+    /** Return substring before last instance of argument (as in Bsoft)
+     *
+      * @code
+     * FileName fn_proj("g1ta00001.raw#d=f");
+     * fn_proj = fn_proj.before_last_of("#"); // fn_proj = "g1ta00001.raw"
+     * @endcode
+     */
+    FileName beforeLastOf(const std::string& str) const;
+
+    /** Return substring after first instance of argument (as in Bsoft)
+     *
+      * @code
+     * FileName fn_proj("g1ta00001.raw#d=f");
+     * fn_proj = fn_proj.after_first_of("#"); // fn_proj = "d=f"
+     * @endcode
+     */
+    FileName afterFirstOf(const std::string& str) const;
+
+    /** Return substring after last instance of argument (as in Bsoft)
+     *
+      * @code
+     * FileName fn_proj("g1ta00001.raw#d=f");
+     * fn_proj = fn_proj.after_last_of("#"); // fn_proj = "d=f"
+     * @endcode
+     */
+    FileName afterLastOf(const std::string& str) const;
+
+    /** Add string at the beginning
+     *
+     * If there is a path then the prefix is added after the path.
+     *
+     * @code
+     * fn_proj = "imgs/g1ta00001";
+     * fn_proj.add_prefix("h"); // fn_proj == "imgs/hg1ta00001"
+     *
+     * fn_proj = "g1ta00001";
+     * fn_proj.add_prefix("h"); // fn_proj == "hg1ta00001"
+     * @endcode
+     */
+    FileName addPrefix(const std::string& prefix) const;
+
+    /** Add extension at the end.
+     *
+     * The "." is added. If teh input extension is "" then the same name is
+     * returned, with nothing added.
+     *
+     * @code
+     * fn_proj = "g1ta00001";
+     * fn_proj.add_extension("xmp"); // fn_proj == "g1ta00001.xmp"
+     * @endcode
+     */
+    FileName addExtension(const std::string& ext) const;
+
+    /** Remove last extension, if any
+     *
+     * @code
+     * fn_proj = "g1ta00001.xmp";
+     * fn_proj = fn_proj.without_extension(); // fn_proj == "g1ta00001"
+     *
+     * fn_proj = "g1ta00001";
+     * fn_proj = fn_proj.without_extension(); // fn_proj == "g1ta00001"
+     * @endcode
+     */
+    FileName withoutExtension() const;
+
+    /** Insert before first extension
+     *
+     * If there is no extension, the insertion is performed at the end.
+     *
+     * @code
+     * fn_proj = "g1ta00001.xmp";
+     * fn_proj = fn_proj.insert_before_extension("pp");
+     * // fn_proj == "g1ta00001pp.xmp"
+     *
+     * fn_proj = "g1ta00001";
+     * fn_proj = fn_proj.insert_before_extension("pp");
+     * // fn_proj=="g1ta00001pp"
+     * @endcode
+     */
+    FileName insertBeforeExtension(const std::string& str) const;
+
+    /** Remove a certain extension
+     *
+     * It doesn't matter if there are several extensions and the one to be
+     * removed is in the middle. If the given extension is not present in the
+     * filename nothing is done.
+     *
+     * @code
+     * fn_proj = "g1ta00001.xmp.bak";
+     * fn_proj = fn_proj.remove_extension("xmp");
+     * // fn_proj == "g1ta00001.bak"
+     * @endcode
+     */
+    FileName removeExtension(const std::string& ext) const;
+
+    /** Remove all extensions
+     */
+    FileName removeAllExtensions() const;
+
+    /** Remove file format
+     * @code
+     * fn_proj = "g1ta00001.xmp";
+     * fn_proj = fn_proj.get_file_format(); // fn_proj == "xmp"
+     * fn_proj = "g1ta00001.nor:spi";
+     * fn_proj = fn_proj.get_file_format(); // fn_proj == "spi"
+     * fn_proj = "input.file#d=f#x=120,120,55#h=1024";
+     * fn_proj = fn_proj.get_file_format(); // fn_proj == "raw"
+     * @endcode
+     */
+    FileName removeFileFormat() const;
+
+    /** Is this file a MetaData file?
+     * Returns false if the filename contains "@", ":" or "#"
+     * Returns true if the get_file_format extension == "star"
+     */
+    bool isStarFile() const;
+
+    /** Clean image FileName (as in Bsoft)
+     *
+     * @code
+     * fn_proj = "g1ta00001.xmp";
+     * fn_proj = fn_proj.get_file_format(); // fn_proj == "g1ta00001.xmp"
+     * fn_proj = "g1ta00001.nor:spi";
+     * fn_proj = fn_proj.clean_image_name(); // fn_proj == "g1ta00001.nor"
+     * fn_proj = "input.file#d=f#x=120,120,55#h=1024";
+     * fn_proj = fn_proj.clean_image_name(); // fn_proj == "input.file"
+     * @endcode
+     */
+    //FileName clean_image_name() const;
+
+    /** Substitute ext1 by ext2
+     *
+     * It doesn't matter if ext1 is in the middle of several extensions. If ext1
+     * is not present in the filename nothing is done.
+     *
+     * @code
+     * fn_proj = "g1ta00001.xmp.bak";
+     * fn_proj = fn_proj.substitute_extension("xmp", "bor");
+     * // fn_proj == "g1ta00001.bor.bak"
+     *
+     * fn_proj = "g1ta00001.xmp.bak";
+     * fn_proj = fn_proj.substitute_extension("tob", "bor");
+     * // fn_proj=="g1ta00001.xmp.bak"
+     * @endcode
+     */
+    FileName substituteExtension(const std::string& ext1,
+                                  const std::string& ext2) const;
+
+    /** Without a substring
+     *
+     * If the substring is not present the same FileName is returned, if it is
+     * there the substring is removed.
+     */
+    FileName without(const std::string& str) const;
+
+    /** Remove until prefix
+     *
+     * Remove the starting string until the given prefix, inclusively. For
+     * instance /usr/local/data/ctf-image00001.fft with ctf- yields
+     * image00001.fft. If the prefix is not found nothing is done.
+     */
+    FileName removeUntilPrefix(const std::string& str) const;
+
+    /** Remove all directories
+     *
+     * Or if keep>0, then keep the lowest keep directories
+     */
+    FileName removeDirectories(int keep = 0) const;
+    /**copy one file
+     *
+     * s
+     */
+    void copyFile(const FileName & target) const;
+
+
+    /** From a wild-card containing filename get a vector with all existing filenames,
+     * return number of existing filenames
+     *
+     */
+    int globFiles(std::vector<FileName> &files) const;
+    //@}
+};
+
+/** This class is used for comparing filenames.
+ *
+ * Example: "g0ta00001.xmp" is less than "g0ta00002.xmp"
+ *
+ * This class is needed to define a std::map as
+ * map<FileName,FileName,FileNameComparison> myMap;
+ *
+ * This function is not ported to Python.
+ */
+class FileNameComparison
+{
+public:
+    inline bool operator ()(const FileName &fn1, const FileName &fn2)
+    {
+        return fn1<fn2;
+    }
+};
+
+/** True if the file exists in the current directory
+ *
+ * @code
+ * if (exists("g1ta00001"))
+ *     std::cout << "The file exists" << std::endl;
+ * @endcode
+ */
+bool exists(const FileName& fn);
+
+/** True if the path is a directory */
+bool isDirectory (const FileName &fn);
+
+/** True if the file exists in the current directory
+ *  Remove leading xx@ and tailing :xx
+ *
+ * @code
+ * if (exists("g1ta00001"))
+ *     std::cout << "The file exists" << std::endl;
+ * @endcode
+ */
+int existsTrim(const FileName& fn);
+
+/** Return the list of files within a directory. */
+void getdir(const std::string &dir, std::vector<FileName> &files);
+
+/** This function raised an ERROR if the filename if not empty and if
+ * the corresponding file does not exist.
+ * This may be useful to have a better (killing) control on (mpi-regulated) jobs
+ *
+ * @code
+ *   exit_if_not_exists("control_file.txt");
+ * @endcode
+ *
+ * This function is not ported to Python.
+ */
+void exit_if_not_exists(const FileName &fn);
+
+/** Waits until the given filename has a stable size
+ *
+ * The stable size is defined as having the same size within two samples
+ * separated by time_step (microsecs).
+ *
+ * An exception is throw if the file exists but its size cannot be stated.
+ */
+void wait_until_stable_size(const FileName& fn,
+                            unsigned long time_step = 250000);
+
+/** Write a zero filled file with the desired size.
+ *
+ * The file is written by blocks to speed up, you can modify the block size.
+ * An exception is thrown if any error happens
+ */
+void create_empty_file(const FileName& fn,
+                       unsigned long long size,
+                       unsigned long long block_size = 102400);
+
+/** Returns the base directory of the Xmipp installation
+ */
+FileName xmippBaseDir();
+//@}
+
+#endif /* FILENAME_H_ */
diff --git a/src/funcs.cpp b/src/funcs.cpp
new file mode 100644
index 0000000..eb28058
--- /dev/null
+++ b/src/funcs.cpp
@@ -0,0 +1,733 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+#include "src/funcs.h"
+#include "src/args.h"
+
+#include <stdio.h>
+#include <fstream>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <time.h>
+#include <complex>
+#include <fstream>
+#include <typeinfo>
+
+void fitStraightLine(std::vector<fit_point2D> &points, double &slope, double &intercept, double &corr_coeff)
+{
+	// From: http://mathworld.wolfram.com/LeastSquaresFitting.html
+	// ss_xx = Sum_i x_i^2 - n ave_x^2
+	// ss_yy = Sum_i y_i^2 - n ave_y^2
+	// ss_xy = Sum_i x_i * y_i - n ave_x n_ave_y
+	// slope = xx_xy / ss_xx
+	// intercept = ave_y - slope * ave_x
+	// corr_coeff = ss_xy^2 / (ss_xx * ss_yy)
+	double ss_xy = 0.;
+	double ss_xx = 0.;
+	double ss_yy = 0.;
+	double ave_x = 0.;
+	double ave_y = 0.;
+	double sum_w = 0.;
+	for (int i = 0; i < points.size(); i++)
+	{
+		ave_x += points[i].w * points[i].x;
+		ave_y += points[i].w * points[i].y;
+		sum_w += points[i].w;
+		ss_xx += points[i].w * points[i].x * points[i].x;
+		ss_yy += points[i].w * points[i].y * points[i].y;
+		ss_xy += points[i].w * points[i].x * points[i].y;
+	}
+	ave_x /= sum_w;
+	ave_y /= sum_w;
+	ss_xx -= sum_w * ave_x * ave_x;
+	ss_yy -= sum_w * ave_y * ave_y;
+	ss_xy -= sum_w * ave_x * ave_y;
+
+	//std::cerr << " ss_xx= " << ss_xx << " ss_yy= " << ss_yy << " ss_xy= " << ss_xy << std::endl;
+	//std::cerr << " sum_w= " << sum_w << " ave_x= " << ave_x << " ave_y= " << ave_y << std::endl;
+	slope = ss_xy / ss_xx;
+	intercept = ave_y - slope * ave_x;
+	corr_coeff = ss_xy * ss_xy / (ss_xx * ss_yy);
+}
+
+/* Value of a blob --------------------------------------------------------- */
+double kaiser_value(double r, double a, double alpha, int m)
+{
+    double rda, rdas, arg, w;
+    rda = r / a;
+    rdas = rda * rda;
+    if (rdas <= 1.0)
+    {
+        arg = alpha * sqrt(1.0 - rdas);
+        if (m == 0)
+        {
+            w = bessi0(arg) / bessi0(alpha);
+        }
+        else if (m == 1)
+        {
+            w = sqrt (1.0 - rdas);
+            if (alpha != 0.0)
+                w *= bessi1(arg) / bessi1(alpha);
+        }
+        else if (m == 2)
+        {
+            w = sqrt (1.0 - rdas);
+            w = w * w;
+            if (alpha != 0.0)
+                w *= bessi2(arg) / bessi2(alpha);
+        }
+        else if (m == 3)
+        {
+            w = sqrt (1.0 - rdas);
+            w = w * w * w;
+            if (alpha != 0.0)
+                w *= bessi3(arg) / bessi3(alpha);
+        }
+        else if (m == 4)
+        {
+            w = sqrt (1.0 - rdas);
+            w = w * w * w *w;
+            if (alpha != 0.0)
+                w *= bessi4(arg) / bessi4(alpha);
+        }
+        else REPORT_ERROR("m out of range in kaiser_value()");
+    }
+    else
+        w = 0.0;
+    return w;
+}
+/* Line integral through a blob -------------------------------------------- */
+/* Value of line integral through Kaiser-Bessel radial function
+   (n >=2 dimensions) at distance s from center of function.
+   Parameter m = 0, 1, or 2. */
+double kaiser_proj(double s, double a, double alpha, int m)
+{
+    double sda, sdas, w, arg, p;
+    sda = s / a;
+    sdas = sda * sda;
+    w = 1.0 - sdas;
+    if (w > 1.0e-10)
+    {
+        arg = alpha * sqrt(w);
+        if (m == 0)
+        {
+            if (alpha == 0.0)
+                p = 2.0 * a * sqrt(w);
+            else
+                p = (2.0 * a / alpha) * sinh(arg) / bessi0(alpha);
+        }
+        else if (m == 1)
+        {
+            if (alpha == 0.0)
+                p = 2.0 * a * w * sqrt(w) * (2.0 / 3.0);
+            else
+                p = (2.0 * a / alpha) * sqrt(w) * (cosh(arg) - sinh(arg) / arg)
+                    / bessi1(alpha);
+        }
+        else if (m == 2)
+        {
+            if (alpha == 0.0)
+                p = 2.0 * a * w * w * sqrt(w) * (8.0 / 15.0);
+            else
+                p = (2.0 * a / alpha) * w *
+                    ((3.0 / (arg * arg) + 1.0) * sinh(arg) - (3.0 / arg) * cosh(arg)) / bessi2(alpha);
+        }
+        else REPORT_ERROR("m out of range in kaiser_proj()");
+    }
+    else
+        p = 0.0;
+    return p;
+}
+/* Fourier value of a blob ------------------------------------------------- */
+double kaiser_Fourier_value(double w, double a, double alpha, int m)
+{
+    double sigma = sqrt(ABS(alpha * alpha - (2. * PI * a * w) * (2. * PI * a * w)));
+    if (m == 2)
+    {
+        if (2.*PI*a*w > alpha)
+            return  pow(2.*PI, 3. / 2.)*pow(a, 3.)*pow(alpha, 2.)*bessj3_5(sigma)
+                    / (bessi0(alpha)*pow(sigma, 3.5));
+        else
+            return  pow(2.*PI, 3. / 2.)*pow(a, 3.)*pow(alpha, 2.)*bessi3_5(sigma)
+                    / (bessi0(alpha)*pow(sigma, 3.5));
+    }
+    else if (m == 0)
+    {
+        if (2*PI*a*w > alpha)
+            return  pow(2.*PI, 3. / 2.)*pow(a, 3)*bessj1_5(sigma)
+                    / (bessi0(alpha)*pow(sigma, 1.5));
+        else
+            return  pow(2.*PI, 3. / 2.)*pow(a, 3)*bessi1_5(sigma)
+                    / (bessi0(alpha)*pow(sigma, 1.5));
+    }
+    else
+    	REPORT_ERROR("m out of range in kaiser_Fourier_value()");
+}
+/* Volume integral of a blob ----------------------------------------------- */
+double  basvolume(double a, double alpha, int m, int n)
+{
+    double  hn, tpi, v;
+    hn = 0.5 * n;
+    tpi = 2.0 * PI;
+    if (alpha == 0.0)
+    {
+        if ((n / 2)*2 == n)           /* n even                               */
+            v = pow(tpi, hn) * in_zeroarg(n / 2 + m) / in_zeroarg(m);
+        else                        /* n odd                                */
+            v = pow(tpi, hn) * inph_zeroarg(n / 2 + m) / in_zeroarg(m);
+    }
+    else
+    {                        /* alpha > 0.0                          */
+        if ((n / 2)*2 == n)           /* n even                               */
+            v = pow(tpi / alpha, hn) * i_n(n / 2 + m, alpha) / i_n(m, alpha);
+        else                        /* n odd                                */
+            v = pow(tpi / alpha, hn) * i_nph(n / 2 + m, alpha) / i_n(m, alpha);
+    }
+    return v * pow(a, (double)n);
+}
+/* Bessel function I_n (x),  n = 0, 1, 2, ...
+ Use ONLY for small values of n     */
+double i_n(int n, double x)
+{
+    int i;
+    double i_ns1, i_n, i_np1;
+    if (n == 0)   return bessi0(x);
+    if (n == 1)   return bessi1(x);
+    if (x == 0.0) return 0.0;
+    i_ns1 = bessi0(x);
+    i_n   = bessi1(x);
+    for (i = 1; i < n; i++)
+    {
+        i_np1 = i_ns1 - (2 * i) / x * i_n;
+        i_ns1 = i_n;
+        i_n   = i_np1;
+    }
+    return i_n;
+}
+/*.....Bessel function I_(n+1/2) (x),  n = 0, 1, 2, ..........................*/
+double i_nph(int n, double x)
+{
+    int i;
+    double r2dpix;
+    double i_ns1, i_n, i_np1;
+    if (x == 0.0) return 0.0;
+    r2dpix = sqrt(2.0 / (PI * x));
+    i_ns1 = r2dpix * cosh(x);
+    i_n   = r2dpix * sinh(x);
+    for (i = 1; i <= n; i++)
+    {
+        i_np1 = i_ns1 - (2 * i - 1) / x * i_n;
+        i_ns1 = i_n;
+        i_n   = i_np1;
+    }
+    return i_n;
+}
+/*....Limit (z->0) of (1/z)^n I_n(z)..........................................*/
+double in_zeroarg(int n)
+{
+    int i;
+    double fact;
+    fact = 1.0;
+    for (i = 1; i <= n; i++)
+    {
+        fact *= 0.5 / i;
+    }
+    return fact;
+}
+/*.......Limit (z->0) of (1/z)^(n+1/2) I_(n+1/2) (z)..........................*/
+double inph_zeroarg(int n)
+{
+    int i;
+    double fact;
+    fact = 1.0;
+    for (i = 1; i <= n; i++)
+    {
+        fact *= 1.0 / (2 * i + 1.0);
+    }
+    return fact*sqrt(2.0 / PI);
+}
+/* Zero freq --------------------------------------------------------------- */
+double blob_freq_zero(struct blobtype b)
+{
+    return sqrt(b.alpha*b.alpha + 6.9879*6.9879) / (2*PI*b.radius);
+}
+/* Attenuation ------------------------------------------------------------- */
+double blob_att(double w, struct blobtype b)
+{
+    return blob_Fourier_val(w, b) / blob_Fourier_val(0, b);
+}
+/* Number of operations ---------------------------------------------------- */
+double blob_ops(double w, struct blobtype b)
+{
+    return pow(b.alpha*b.alpha + 6.9879*6.9879, 1.5) / b.radius;
+}
+
+/* Gaussian value ---------------------------------------------------------- */
+double gaussian1D(double x, double sigma, double mu)
+{
+    x -= mu;
+    return 1 / sqrt(2*PI*sigma*sigma)*exp(-0.5*((x / sigma)*(x / sigma)));
+}
+
+/* t-student value -------------------------------------------------------- */
+double tstudent1D(double x, double df, double sigma, double mu)
+{
+    x -= mu;
+    double norm = exp(gammln((df+1.)/2.)) / exp(gammln(df/2.));
+    norm /= sqrt(df*PI*sigma*sigma);
+    return norm * pow((1 + (x/sigma)*(x/sigma)/df),-((df+1.)/2.));
+
+}
+
+double gaussian2D(double x, double y, double sigmaX, double sigmaY,
+                  double ang, double muX, double muY)
+{
+    // Express x,y in the gaussian internal coordinates
+    x -= muX;
+    y -= muY;
+    double xp = cos(ang) * x + sin(ang) * y;
+    double yp = -sin(ang) * x + cos(ang) * y;
+
+    // Now evaluate
+    return 1 / sqrt(2*PI*sigmaX*sigmaY)*exp(-0.5*((xp / sigmaX)*(xp / sigmaX) +
+                                            (yp / sigmaY)*(yp / sigmaY)));
+}
+
+/* ICDF Gaussian ----------------------------------------------------------- */
+double icdf_gauss(double p)
+{
+    const double c[] =
+        {
+            2.515517, 0.802853, 0.010328
+        };
+    const double d[] =
+        {
+            1.432788, 0.189269, 0.001308
+        };
+    if (p < 0.5)
+    {
+        // F^-1(p) = - G^-1(p)
+        double t=sqrt(-2.0*log(p));
+        double z=t - ((c[2]*t + c[1])*t + c[0]) /
+                 (((d[2]*t + d[1])*t + d[0])*t + 1.0);
+        return -z;
+    }
+    else
+    {
+        // F^-1(p) = G^-1(1-p)
+        double t=sqrt(-2.0*log(1-p));
+        double z=t - ((c[2]*t + c[1])*t + c[0]) /
+                 (((d[2]*t + d[1])*t + d[0])*t + 1.0);
+        return z;
+    }
+}
+
+/* CDF Gaussian ------------------------------------------------------------ */
+double cdf_gauss(double x)
+{
+    return 0.5 * (1. + erf(x/sqrt(2.)));
+}
+
+/*************************************************************************
+Student's t distribution
+
+Computes the integral from minus infinity to t of the Student
+t distribution with integer k > 0 degrees of freedom:
+
+                                     t
+                                     -
+                                    | |
+             -                      |         2   -(k+1)/2
+            | ( (k+1)/2 )           |  (     x   )
+      ----------------------        |  ( 1 + --- )        dx
+                    -               |  (      k  )
+      sqrt( k pi ) | ( k/2 )        |
+                                  | |
+                                   -
+                                  -inf.
+
+Relation to incomplete beta integral:
+
+       1 - stdtr(k,t) = 0.5 * incbet( k/2, 1/2, z )
+where
+       z = k/(k + t**2).
+
+For t < -2, this is the method of computation.  For higher t,
+a direct method is derived from integration by parts.
+Since the function is symmetric about t=0, the area under the
+right tail of the density is found by calling the function
+with -t instead of t.
+
+ACCURACY:
+
+Tested at random 1 <= k <= 25.  The "domain" refers to t.
+                     Relative error:
+arithmetic   domain     # trials      peak         rms
+   IEEE     -100,-2      50000       5.9e-15     1.4e-15
+   IEEE     -2,100      500000       2.7e-15     4.9e-17
+
+Cephes Math Library Release 2.8:  June, 2000
+Copyright 1984, 1987, 1995, 2000 by Stephen L. Moshier
+*************************************************************************/
+double cdf_tstudent(int k, double t)
+{
+    double EPS=5E-16;
+    double result;
+    double x;
+    double rk;
+    double z;
+    double f;
+    double tz;
+    double p;
+    double xsqk;
+    int j;
+
+    if ( t==0 )
+    {
+        result = 0.5;
+        return result;
+    }
+    if ( t<-2.0 )
+    {
+        rk = k;
+        z = rk/(rk+t*t);
+        result = 0.5*betai(0.5*rk, 0.5, z);
+        return result;
+    }
+    if ( t<0 )
+    {
+        x = -t;
+    }
+    else
+    {
+        x = t;
+    }
+    rk = k;
+    z = 1.0+x*x/rk;
+    if ( k%2 != 0 )
+    {
+        xsqk = x/sqrt(rk);
+        p = atan(xsqk);
+        if ( k > 1 )
+        {
+            f = 1.0;
+            tz = 1.0;
+            j = 3;
+            while ( j <= k-2 && tz/f > EPS )
+            {
+                tz = tz*((j-1)/(z*j));
+                f = f+tz;
+                j = j+2;
+            }
+            p = p+f*xsqk/z;
+        }
+        p = p*2.0/PI;
+    }
+    else
+    {
+        f = 1.0;
+        tz = 1.0;
+        j = 2;
+        while ( j<= k-2 && tz/f > EPS)
+        {
+            tz = tz*((j-1)/(z*j));
+            f = f+tz;
+            j = j+2;
+        }
+        p = f*x/sqrt(z*rk);
+    }
+    if ( t<0 )
+    {
+        p = -p;
+    }
+    result = 0.5+0.5*p;
+    return result;
+}
+
+/* Snedecor's F ------------------------------------------------------------ */
+// http://en.wikipedia.org/wiki/F-distribution
+double cdf_FSnedecor(int d1, int d2, double x)
+{
+    return betai(0.5*d1,0.5*d2,(d1*x)/(d1*x+d2));
+}
+
+double icdf_FSnedecor(int d1, int d2, double p)
+{
+    double xl=0, xr=1e6;
+    double pl=cdf_FSnedecor(d1,d2,xl);
+    double pr=cdf_FSnedecor(d1,d2,xr);
+    double xm, pm;
+    do
+    {
+        xm=(xl+xr)*0.5;
+        pm=cdf_FSnedecor(d1,d2,xm);
+        if (pm>p)
+        {
+            xr=xm;
+            pr=pm;
+        }
+        else
+        {
+            xl=xm;
+            pl=pm;
+        }
+    }
+    while (ABS(pm-p)/p>0.001);
+    return xm;
+}
+
+/* Random functions -------------------------------------------------------- */
+int idum;
+
+// Uniform distribution ....................................................
+void  init_random_generator(int seed)
+{
+    idum = -1;
+    ran1(&idum);
+    if (seed != -1)
+    {
+        // Prevent seeds larger than 65000
+        seed %=0xffff;
+        for (int i = 0; i < seed; i++)
+            ran1(&idum);
+    }
+}
+
+void  randomize_random_generator()
+{
+    static  unsigned int seed;
+    int rand_return;
+
+    srand(seed);
+    rand_return = rand();
+
+    time_t t;
+    time(&t);
+    rand_return = abs(rand_return);
+    idum = (-(int)(t % 10000)
+            - (int)(rand_return % 10000));
+    ran1(&idum);
+    seed = (unsigned int)rand_return;
+}
+
+float rnd_unif()
+{
+    return ran1(&idum);
+}
+float rnd_unif(float a, float b)
+{
+    if (a == b)
+        return a;
+    else
+        return a + (b - a)*ran1(&idum);
+}
+
+// t-distribution
+float rnd_student_t(double nu)
+{
+    return tdev(nu, &idum);
+}
+float rnd_student_t(double nu, float a, float b)
+{
+    if (b == 0)
+        return a;
+    else
+        return b*tdev(nu, &idum) + a;
+}
+
+// Gaussian distribution ...................................................
+float rnd_gaus()
+{
+    return gasdev(&idum);
+}
+float rnd_gaus(float a, float b)
+{
+    if (b == 0)
+        return a;
+    else
+        return b*gasdev(&idum) + a;
+}
+float gaus_within_x0(float x0, float mean, float stddev)
+{
+    float z0 = (x0 - mean) / stddev;
+    return erf(ABS(z0) / sqrt(2.0));
+}
+
+float gaus_outside_x0(float x0, float mean, float stddev)
+{
+    float z0 = (x0 - mean) / stddev;
+    return erfc(ABS(z0) / sqrt(2.0));
+}
+
+float gaus_up_to_x0(float x0, float mean, float stddev)
+{
+    if (x0 > mean)
+        return 1.0 -gaus_outside_x0(x0, mean, stddev) / 2;
+    else if (x0 == mean)
+        return 0.5;
+    else
+        return gaus_outside_x0(x0, mean, stddev) / 2;
+}
+
+float gaus_from_x0(float x0, float mean, float stddev)
+{
+    if (x0 > mean)
+        return gaus_outside_x0(x0, mean, stddev) / 2;
+    else if (x0 == mean)
+        return 0.5;
+    else
+        return 1.0 -gaus_outside_x0(x0, mean, stddev) / 2;
+}
+
+float gaus_outside_probb(float p, float mean, float stddev)
+{
+    // Make a Bolzano search for the right value
+    float p1, p2, pm, x1, x2, xm;
+    x1 = mean;
+    x2 = mean + 5 * stddev;
+    do
+    {
+        xm = (x1 + x2) / 2;
+        p1 = gaus_outside_x0(x1, mean, stddev);
+        p2 = gaus_outside_x0(x2, mean, stddev);
+        pm = gaus_outside_x0(xm, mean, stddev);
+        if (pm > p)
+            x1 = xm;
+        else
+            x2 = xm;
+    }
+    while (ABS(pm - p) / p > 0.005);
+    return xm;
+}
+
+// See Numerical Recipes, Chap. 6.3
+float student_within_t0(float t0, float degrees_of_freedom)
+{
+    return 1 -betai(degrees_of_freedom / 2, 0.5,
+                    degrees_of_freedom / (degrees_of_freedom + t0*t0));
+}
+
+float student_outside_t0(float t0, float degrees_of_freedom)
+{
+    return 1 -student_within_t0(t0, degrees_of_freedom);
+}
+
+float student_up_to_t0(float t0, float degrees_of_freedom)
+{
+    if (t0 >= 0)
+        return 1.0 -student_outside_t0(t0, degrees_of_freedom) / 2;
+    else
+        return student_outside_t0(t0, degrees_of_freedom) / 2;
+}
+
+float student_from_t0(float t0, float degrees_of_freedom)
+{
+    return 1 -student_up_to_t0(t0, degrees_of_freedom);
+}
+
+float student_outside_probb(float p, float degrees_of_freedom)
+{
+    // Make a Bolzano search for the right value
+    float p1, p2, pm, t1, t2, tm;
+    t1 = 0;
+    t2 = 100;
+    do
+    {
+        tm = (t1 + t2) / 2;
+        p1 = student_outside_t0(t1, degrees_of_freedom);
+        p2 = student_outside_t0(t2, degrees_of_freedom);
+        pm = student_outside_t0(tm, degrees_of_freedom);
+        if (pm > p)
+            t1 = tm;
+        else
+            t2 = tm;
+    }
+    while (ABS(pm - p) / p > 0.005);
+    return tm;
+}
+
+float chi2_up_to_t0(float t0, float degrees_of_freedom)
+{
+    return gammp(degrees_of_freedom / 2, t0 / 2);
+}
+
+float chi2_from_t0(float t0, float degrees_of_freedom)
+{
+    return 1 -chi2_up_to_t0(t0, degrees_of_freedom);
+}
+
+// Log uniform distribution ................................................
+float rnd_log(float a, float b)
+{
+    if (a == b)
+        return a;
+    else
+        return exp(rnd_unif(log(a), log(b)));
+}
+
+/* Log2 -------------------------------------------------------------------- */
+// Does not work with xlc compiler
+#ifndef __xlC__
+double log2(double value)
+{
+    return 3.32192809488736*log10(value);
+    // log10(value)/log10(2)
+}
+#endif
+
+// Bsoft function
+void swapbytes(char* v, unsigned long n)
+{
+    char            t;
+    for ( int i=0; i<n/2; i++ )
+    {
+        t = v[i];
+        v[i] = v[n-1-i];
+        v[n-1-i] = t;
+    }
+}
+
+
+
diff --git a/src/funcs.h b/src/funcs.h
new file mode 100644
index 0000000..1534f01
--- /dev/null
+++ b/src/funcs.h
@@ -0,0 +1,499 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+*
+* Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+*
+* Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+*
+* 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
+*
+*  All comments concerning this program package may be sent to the
+*  e-mail address 'xmipp at cnb.csic.es'
+***************************************************************************/
+
+#ifndef FUNCS_H
+#define FUNCS_H
+
+#include <iostream>
+#include <fstream>
+#include <cmath>
+#include <cstdlib>
+#include <cstdio>
+#include <string>
+#include <climits>
+#include <algorithm>
+#include <vector>
+#include <typeinfo>
+
+#include "src/numerical_recipes.h"
+#include "src/macros.h"
+#include "src/error.h"
+
+#define FILENAMENUMBERLENGTH 6
+
+/** Structure of the points to do least-squares fitting
+ */
+struct fit_point2D
+{
+    /// x coordinate
+    double x;
+    /// y coordinate (assumed to be a function of x)
+    double y;
+    /// Weight of the point in the Least-Squares problem
+    double w;
+};
+
+void fitStraightLine(std::vector<fit_point2D> &points, double &slope, double &intercept, double &corr_coeff);
+
+/* ========================================================================= */
+/* BLOBS                                                                     */
+/* ========================================================================= */
+/**@defgroup Blobs Blobs
+   @ingroup BasisFunction */
+//@{
+// Blob structure ----------------------------------------------------------
+/** Blob definition.
+    The blob is a space limited function (click here for a theoretical
+    explanation) which is used as basis function for the ART reconstructions.
+    There are several parameters which define the shape of the blob.
+    The following structure holds all needed information for a blob, a
+    variable can be of this type and it is passed to the different functions
+    containing all we need to know about the blob. As a type definition,
+    we can work with several kind of blobs in the same program at the same
+    time.
+
+    The common way of defining a blob is as follows:
+    @code
+    struct blobtype blob;                  // Definition of the blob
+    blob.radius = 2;                       // Blob radius in voxels
+    blob.order  = 2;                       // Order of the Bessel function
+    blob.alpha  = 3.6;                     // Smoothness parameter
+    @endcode
+
+    Sometimes it is useful to plot any quantity related to the blobs. In the
+    following example you have how to plot their Fourier transform in the
+    continuous frequency space.
+
+    @code
+
+      int main(int argc, char **argv) {
+         struct blobtype blob;                  // Definition of the blob
+         blob.radius = 2;                       // Blob radius in voxels
+         blob.order  = 2;                       // Order of the Bessel function
+         blob.alpha  = textToFloat(argv[1]);    // Smoothness parameter
+
+         double M=blob_Fourier_val (0, blob);
+         for (double w=0; w<=2; w += 0.05)
+            std::cout << w << " " <<  blob_Fourier_val (w, blob)/M << std::endl;
+         return 0;
+      }
+    @endcode
+*/
+struct blobtype
+{
+    /// Spatial radius in Universal System units
+    double radius;
+
+    /// Derivation order and Bessel function order
+    int   order;
+
+    /// Smoothness parameter
+    double alpha;
+};
+
+// Blob value --------------------------------------------------------------
+/** Blob value.
+    This function returns the value of a blob at a given distance from its
+    center (in Universal System units). The distance must be
+    always positive. Remember that a blob is spherically symmetrycal so
+    the only parameter to know the blob value at a point is its distance
+    to the center of the blob. It doesn't matter if this distance is
+    larger than the real blob spatial extension, in this case the function
+    returns 0 as blob value.
+    \\ Ex:
+    @code
+    struct blobtype blob; blob.radius = 2; blob.order = 2; blob.alpha = 3.6;
+    Matrix1D<double> v=vectorR3(1,1,1);
+    std::cout << "Blob value at (1,1,1) = " << blob_val(v.mod(),blob) << std::endl;
+    @endcode */
+#define blob_val(r, blob) kaiser_value(r, blob.radius, blob.alpha, blob.order)
+
+/** Function actually computing the blob value. */
+double kaiser_value(double r, double a, double alpha, int m);
+
+// Blob projection ---------------------------------------------------------
+/** Blob projection.
+    This function returns the value of the blob line integral through a
+    straight line which passes at a distance 'r' (in Universal System
+    units) from the center of the
+    blob. Remember that a blob is spherically symmetrycal so
+    the only parameter to know this blob line integral is its distance
+    to the center of the blob. It doesn't matter if this distance is
+    larger than the real blob spatial extension, in this case the function
+    returns 0.
+    \\ Ex:
+    @code
+    struct blobtype blob; blob.radius = 2; blob.order = 2; blob.alpha = 3.6;
+    Matrix1D<double> v=vectorR3(1,1,1);
+    std::cout << "Blob line integral through (1,1,1) = " << blob_proj(v.mod(),blob)
+         << std::endl;
+    @endcode */
+#define blob_proj(r, blob) kaiser_proj(r, blob.radius, blob.alpha, blob.order)
+
+/** Function actually computing the blob projection. */
+double kaiser_proj(double r, double a, double alpha, int m);
+
+/** Fourier transform of a blob.
+    This function returns the value of the Fourier transform of the blob
+    at a given frequency (w). This frequency must be normalized by the
+    sampling rate. For instance, for computing the Fourier Transform of
+    a blob at 1/Ts (Ts in Amstrongs) you must provide the frequency Tm/Ts,
+    where Tm is the sampling rate.
+
+    The Fourier Transform can be computed only for blobs with m=2 or m=0. */
+#define blob_Fourier_val(w, blob) \
+    kaiser_Fourier_value(w, blob.radius, blob.alpha, blob.order)
+
+/** Function actually computing the blob Fourier transform. */
+double kaiser_Fourier_value(double w, double a, double alpha, int m);
+
+/** Formula for a volume integral of a blob (n is the blob dimension) */
+#define blob_mass(blob) \
+    basvolume(blob.radius, blob.alpha, blob.order,3)
+
+/** Function actually computing the blob integral */
+double  basvolume(double a, double alpha, int m, int n);
+
+/** Limit (z->0) of (1/z)^n I_n(z) (needed by basvolume)*/
+double in_zeroarg(int n);
+
+/** Limit (z->0) of (1/z)^(n+1/2) I_(n+1/2) (z) (needed by basvolume)*/
+double inph_zeroarg(int n);
+
+/** Bessel function I_(n+1/2) (x),  n = 0, 1, 2, ... */
+double i_nph(int n, double x);
+
+/** Bessel function I_n (x),  n = 0, 1, 2, ...
+ Use ONLY for small values of n */
+double i_n(int n, double x);
+
+/** Blob pole.
+    This is the normalized frequency at which the blob goes to 0. */
+double blob_freq_zero(struct blobtype b);
+
+/** Attenuation of a blob.
+    The Fourier transform of the blob at w is the Fourier transform at w=0
+    multiplied by the attenuation. This is the value returned. Remind that
+    the frequency must be normalized by the sampling rate. Ie, Tm*w(cont) */
+double blob_att(double w, struct blobtype b);
+
+/** Number of operations for a blob.
+    This is a number proportional to the number of operations that ART
+    would need to make a reconstruction with this blob. */
+double blob_ops(double w, struct blobtype b);
+
+/** 1D gaussian value
+ *
+ * This function returns the value of a univariate gaussian function at the
+ * point x.
+ */
+double gaussian1D(double x, double sigma, double mu = 0);
+
+/** 1D t-student value
+ *
+ * This function returns the value of a univariate t-student function at the
+ * point x, and with df degrees of freedom
+ */
+double tstudent1D(double x, double df, double sigma, double mu = 0);
+
+/** Inverse Cumulative distribution function for a Gaussian
+ *
+ * This function returns the z of a N(0,1) such that the probability below z is p
+ *
+ * The function employs an fast approximation to z which is valid up to 1e-4.
+ * See http://www.johndcook.com/normal_cdf_inverse.html
+ */
+double icdf_gauss(double p);
+
+/** Cumulative distribution function for a Gaussian
+ *
+ * This function returns the value of the CDF of a univariate gaussian function at the
+ * point x.
+ */
+double cdf_gauss(double x);
+
+/** Cumulative distribution function for a t-distribution
+ *
+ * This function returns the value of the CDF of a univariate t-distribution
+ * with k degrees of freedom  at the point t.
+ *  Adapted by Sjors from: http://www.alglib.net/specialfunctions/distributions/student.php
+ */
+double cdf_tstudent(int k, double t);
+
+/** Cumulative distribution function for a Snedecor's F-distribution.
+ *
+ * This function returns the value of the CDF of a univariate Snedecor's
+ * F-distribution
+ * with d1, d2 degrees of freedom  at the point x.
+ */
+double cdf_FSnedecor(int d1, int d2, double x);
+
+/** Inverse Cumulative distribution function for a Snedecor's F-distribution.
+ *
+ * This function returns the value of the ICDF of a univariate Snedecor's
+ * F-distribution
+ * with d1, d2 degrees of freedom with probability p, i.e., it returns
+ * x such that CDF(d1,d2,x)=p
+ */
+double icdf_FSnedecor(int d1, int d2, double p);
+
+/** 2D gaussian value
+ *
+ * This function returns the value of a multivariate (2D) gaussian function at
+ * the point (x,y) when the X axis of the gaussian is rotated ang
+ * (counter-clockwise) radians (the angle is positive when measured from the
+ * universal X to the gaussian X). X and Y are supposed to be independent.
+ */
+double gaussian2D(double x,
+                  double y,
+                  double sigmaX,
+                  double sigmaY,
+                  double ang,
+                  double muX = 0,
+                  double muY = 0);
+//@}
+
+/** Compute the logarithm in base 2
+ */
+// Does not work with xlc compiler
+#ifndef __xlC__
+double log2(double value);
+#endif
+//@}
+
+/** @name Random functions
+ *
+ * These functions allow you to work in an easier way with the random functions
+ * of the Numerical Recipes. Only an uniform and a gaussian random number
+ * generators have been implemented. In fact only a uniform generator exists and
+ * the gaussian one is based on a call to it. For this reason, if you initialize
+ * the gaussian random generator, you are also initialising the uniform one.
+ *
+ * Here goes an example for uniform random numbers to show how to use this set
+ * of functions.
+ *
+ * @code
+ * // Initialise according to the clock
+ * randomize_random_generator();
+ *
+ * // Show 10 random numbers between -1 and 1
+ * for (int i=0; i<10; i++)
+ *     std::cout << rnd_unif(-1,1) << std::endl;
+ * @endcode
+ */
+//@{
+/** Reset uniform random generator to a known point
+ *
+ * If you initialize the random generator with this function each time, then the
+ * same random sequence will be generated
+ *
+ * @code
+ * init_rnd_unif();
+ * init_rnd_unif(17891)
+ * @endcode
+ */
+void init_random_generator(int seed = -1);
+
+/** Reset random generator according to the clock.
+ *
+ * This time the initialisation itself assures a random sequence different each
+ * time the program is run. Be careful not to run the program twice within the
+ * same second as the initialisation will be the same for both runs.
+ */
+void randomize_random_generator();
+
+/** Produce a uniform random number between 0 and 1
+ *
+ * @code
+ * std::cout << "This random number should be between 0 and 1: " << rnd_unif()
+ * << std::endl;
+ * @endcode
+ */
+float rnd_unif();
+
+/** Produce a uniform random number between a and b
+ *
+ * @code
+ * std::cout << "This random number should be between 0 and 10: " << rnd_unif(0,10)
+ * << std::endl;
+ * @endcode
+ */
+float rnd_unif(float a, float b);
+
+/** Produce a t-distributed random number with mean 0 and standard deviation 1 and nu degrees of freedom
+ *
+ * @code
+ * std::cout << "This random number should follow t(0,1) with 3 degrees of freedon: " << rnd_student_t(3.)
+ * << std::endl;
+ * @endcode
+ */
+float rnd_student_t(double nu);
+
+/** Produce a gaussian random number with mean a and standard deviation b and nu degrees of freedom
+ *
+ * @code
+ * std::cout << "This random number should follow t(1,4) with 3 d.o.f.: " << rnd_gaus(3,1,2)
+ * << std::endl;
+ * @endcode
+ */
+float rnd_student_t(double nu, float a, float b);
+
+/** Produce a gaussian random number with mean 0 and standard deviation 1
+ *
+ * @code
+ * std::cout << "This random number should follow N(0,1): " << rnd_gaus()
+ * << std::endl;
+ * @endcode
+ */
+float rnd_gaus();
+
+/** Produce a gaussian random number with mean a and standard deviation b
+ *
+ * @code
+ * std::cout << "This random number should follow N(1,4): " << rnd_gaus(1,2)
+ * << std::endl;
+ * @endcode
+ */
+float rnd_gaus(float a, float b);
+
+/** Gaussian area from -x0 to x0
+ *
+ * By default the gaussian mean is 0 and the gaussian standard deviation is 1.
+ * x0 must be positive
+ */
+float gaus_within_x0(float x0, float mean = 0, float stddev = 1);
+
+/** Gaussian area outisde -x0 to x0
+ *
+ * By default the gaussian mean is 0 and the gaussian standard deviation is 1.
+ * x0 must be positive
+ */
+float gaus_outside_x0(float x0, float mean = 0, float stddev = 1);
+
+/** Gaussian area from -inf to x0
+ *
+ * By default the gaussian mean is 0 and the gaussian standard deviation is 1.
+ * There is no restriction over the sign of x0
+ */
+float gaus_up_to_x0(float x0, float mean = 0, float stddev = 1);
+
+/** Gaussian area from x0 to inf
+ *
+ * By default the gaussian mean is 0 and the gaussian standard deviation is 1.
+ * There is no restriction over the sign of x0
+ */
+float gaus_from_x0(float x0, float mean = 0, float stddev = 1);
+
+/** t0 for a given two-sided probability
+ *
+ * This function returns t0 such that the student probability outside t0 is
+ * equal to p
+ */
+float student_outside_probb(float p, float degrees_of_freedom);
+
+/** student area from -t0 to t0
+ *
+ * By default the student mean is 0 and the student standard deviation is 1.
+ * t0 must be positive
+ */
+float student_within_t0(float t0, float degrees_of_freedom);
+
+/** student area outisde -t0 to t0
+ *
+ * By default the student mean is 0 and the student standard deviation is 1.
+ * t0 must be positive
+ */
+float student_outside_t0(float t0, float degrees_of_freedom);
+
+/** student area from -inf to t0
+ *
+ * By default the student mean is 0 and the student standard deviation is 1.
+ * There is no restriction over the sign of t0
+ */
+float student_up_to_t0(float t0, float degrees_of_freedom);
+
+/** student area from t0 to inf
+ *
+ * By default the student mean is 0 and the student standard deviation is 1.
+ * There is no restriction over the sign of t0
+ */
+float student_from_t0(float t0, float degrees_of_freedom);
+
+/** chi2 area from -inf to t0
+ *
+ * By default the chi2 mean is 0 and the chi2 standard deviation is 1.
+ * There is no restriction over the sign of t0
+ */
+float chi2_up_to_t0(float t0, float degrees_of_freedom);
+
+/** chi2 area from t0 to inf
+ *
+ * By default the chi2 mean is 0 and the chi2 standard deviation is 1.
+ * There is no restriction over the sign of t0
+ */
+float chi2_from_t0(float t0, float degrees_of_freedom);
+
+/** Produce a log uniform random number between a and b
+ *
+ * Watch out that the following inequation must hold 0<a<=b.
+ *
+ * @code
+ * std::cout << "This random number should be between 1 and 1000: "
+ * << rnd_log(10,1000)<< std::endl;
+ * @endcode
+ */
+float rnd_log(float a, float b);
+//@}
+
+/** Conversion little-big endian
+ */
+void swapbytes(char* v, unsigned long n);
+
+
+//@}
+
+//@}
+#endif
+
+
diff --git a/src/gcc_version.h b/src/gcc_version.h
new file mode 100644
index 0000000..6400a59
--- /dev/null
+++ b/src/gcc_version.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+*
+* Authors:     Sjors H.W. Scheres
+*              Roberto Marabini
+*
+* Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+*
+* 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
+*
+*  All comments concerning this program package may be sent to the
+*  e-mail address 'xmipp at cnb.csic.es'
+***************************************************************************/
+
+#ifndef GCC_VERSION_H
+#define GCC_VERSION_H
+
+// If we do not use a GNU compiler, then set the GCC_VERSION to a very high number
+#ifdef __GNUC__
+#define GCC_VERSION (__GNUC__ * 10000 \
+                     + __GNUC_MINOR__ * 100 \
+                     + __GNUC_PATCHLEVEL__)
+#else
+#define GCC_VERSION 999999
+#endif
+
+#if GCC_VERSION < 30300
+#include <strstream>
+#else
+#include <sstream>
+#endif
+
+
+#endif
+
+
diff --git a/src/gui_entries.cpp b/src/gui_entries.cpp
new file mode 100644
index 0000000..88d0e04
--- /dev/null
+++ b/src/gui_entries.cpp
@@ -0,0 +1,655 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/gui_entries.h"
+
+
+bool replaceStringOnce(Fl_Text_Buffer *textbuf, std::string findthis, std::string replaceby)
+{
+	const char *find = findthis.c_str();
+	const char *replace = replaceby.c_str();
+
+	// Loop through the whole string
+	int pos = 0;
+	if (textbuf->search_forward(pos, find, &pos))
+	{
+		// Found a match; update the position and replace text...
+		textbuf->select(pos, pos+strlen(find));
+		textbuf->remove_selection();
+		textbuf->insert(pos, replace);
+		pos += strlen(replace);
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+void replaceStringAll(Fl_Text_Buffer *textbuf, std::string findthis, std::string replaceby)
+{
+
+	bool do_search_more = true;
+	while (do_search_more)
+		do_search_more = replaceStringOnce(textbuf, findthis, replaceby);
+}
+
+void appendLineString(Fl_Text_Buffer *textbuf, std::string copylinewiththis, int times)
+{
+	const char *find = copylinewiththis.c_str();
+	// Loop through the whole string
+	int pos = 0;
+	char * sel;
+
+	if (textbuf->search_forward(pos, find, &pos))
+	{
+		// Found a match; get the entire line and append at the end
+		int line0 = textbuf->line_start(pos);
+		int lineF = textbuf->line_end(pos);
+		textbuf->select(line0,lineF);
+		sel = textbuf->selection_text();
+	}
+	else
+	{
+		std::cerr <<" appendLineString ERROR: Could not find" << copylinewiththis << " in textfile..." << std::endl;
+		exit(1);
+	}
+
+	for (int n = 0; n < times; n++)
+	{
+		textbuf->append("\n");
+		textbuf->append(sel);
+		textbuf->append("\n");
+	}
+	textbuf->append("\n");
+
+}
+
+ShowHelpText::ShowHelpText(const char *help)
+{
+    int w=640;
+    int h=480;
+	Fl_Window *win = new Fl_Window(w, h);
+    Fl_Text_Buffer *buff = new Fl_Text_Buffer();
+    Fl_Text_Display *disp = new Fl_Text_Display(20, 20, w-40, h-40, "relion additional text.");
+    disp->buffer(buff);
+    disp->wrap_mode(1,79);
+    win->resizable(*disp);
+    win->show();
+    buff->text(help);
+}
+
+ShowHelpText::~ShowHelpText(){};
+
+
+// ==============================================================================
+// AnyEntry =====================================================================
+// ==============================================================================
+
+void AnyEntry::initialise(int x, int y, int height,
+				   int wcol2, int wcol3,
+				   const char* title,
+				   const char* defaultvalue,
+				   const char* helptext)
+{
+    // Set the label
+    label = title;
+
+    // The input field
+	if (defaultvalue != NULL)
+	{
+		inp = new Fl_Input(XCOL2, y, wcol2, height, title);
+
+		// Set the input value
+		inp->value(defaultvalue);
+		inp->color(GUI_INPUT_COLOR);
+	}
+
+	// Display help button if needed
+    if (helptext != NULL)
+    {
+    	// Set the help text
+		myhelptext = helptext;
+
+		// The Help button
+		help = new Fl_Button( XCOL3, y, wcol3, height, "?");
+		help->callback( cb_help, this );
+		help->color(GUI_BUTTON_COLOR);
+
+    }
+}
+
+void AnyEntry::place(int &y,
+		const char * title,
+		const char* defaultvalue,
+		const char* helptext,
+		int x, int h, int wcol2, int wcol3 )
+{
+
+	// Clear if existing
+	clear();
+
+	// Add the entry to the window
+	initialise(x, y, h, wcol2, wcol3, title, defaultvalue, helptext);
+
+	// Update the Y-coordinate
+    y += h + 2;
+
+}
+
+std::string AnyEntry::getValue()
+{
+	return (std::string)inp->value();
+}
+
+void AnyEntry::setValue(const char* val)
+{
+	inp->value(val);
+}
+
+void AnyEntry::writeValue(std::ostream& out)
+{
+	// Only write entries that have been initialised
+	if (label != "")
+		out << label << " == " << getValue() << std::endl;
+}
+
+
+void AnyEntry::readValue(std::ifstream& in)
+{
+    if (label != "")
+    {
+		// Start reading the ifstream at the top
+		in.clear(); // reset eof if happened...
+    	in.seekg(0, std::ios::beg);
+		std::string line;
+		while (getline(in, line, '\n'))
+		{
+			if (line.rfind(label) == 0)
+			{
+				// found my label
+				int equalsigns = line.rfind("==");
+				std::string newval = line.substr(equalsigns + 3, line.length() - equalsigns - 3);
+				inp->value(newval.c_str());
+				return;
+			}
+		}
+    }
+}
+
+void AnyEntry::clear()
+{
+	if (label != "")
+	{
+		label="";
+		delete inp;
+		delete help;
+	}
+}
+
+void AnyEntry::deactivate(bool do_deactivate)
+{
+	if (do_deactivate)
+	{
+		inp->deactivate();
+		help->deactivate();
+	}
+	else
+	{
+		inp->activate();
+		help->activate();
+	}
+
+}
+
+// Help button call-back functions
+void AnyEntry::cb_help(Fl_Widget* o, void* v) {
+
+    AnyEntry* T=(AnyEntry*)v;
+    T->cb_help_i();
+}
+
+void AnyEntry::cb_help_i() {
+
+    ShowHelpText *help = new ShowHelpText(myhelptext);
+
+}
+
+
+// ==============================================================================
+// FileNameEntry ================================================================
+// ==============================================================================
+
+void FileNameEntry::initialise(int x, int y, int height,
+		                     int wcol2, int wcol3, int wcol4,
+		                     const char* title,
+		                     const char* defaultvalue,
+		                     const char* _pattern,
+		                     const char* helptext)
+{
+
+	AnyEntry::initialise(x,y,height,
+			wcol2,wcol3,
+			title,
+			defaultvalue,
+			helptext);
+
+	// Store the pattern for the file chooser
+	pattern = _pattern;
+
+    // The Browse button
+    browse = new Fl_Button( XCOL4, y, WCOL4, height, "Browse");
+    browse->callback( cb_browse, this );
+    browse->color(GUI_BUTTON_COLOR);
+}
+
+
+void FileNameEntry::place(int &y,
+		const char * title,
+		const char* defaultvalue,
+		const char* pattern,
+		const char* helptext,
+		int x, int h, int wcol2, int wcol3, int wcol4 )
+{
+
+	// Clear if existing
+	clear();
+
+	// Add the entry to the window
+	initialise(x, y, h, wcol2, wcol3, wcol4, title, defaultvalue, pattern, helptext);
+
+	// Update the Y-coordinate
+    y += h + 2;
+
+}
+
+void FileNameEntry::clear()
+{
+	if (label != "")
+	{
+		AnyEntry::clear();
+		delete browse;
+	}
+}
+
+void FileNameEntry::deactivate(bool do_deactivate)
+{
+	AnyEntry::deactivate(do_deactivate);
+	if (do_deactivate)
+	{
+		browse->deactivate();
+	}
+	else
+	{
+		browse->activate();
+	}
+
+}
+
+void FileNameEntry::cb_browse(Fl_Widget* o, void* v) {
+
+    FileNameEntry* T=(FileNameEntry*)v;
+    T->cb_browse_i();
+}
+
+
+void FileNameEntry::cb_browse_i() {
+
+    Fl::scheme("gtk+");
+    Fl_File_Chooser * G_chooser = new Fl_File_Chooser("", pattern, Fl_File_Chooser::SINGLE, "");
+
+    G_chooser->directory(NULL);
+    G_chooser->color(GUI_BACKGROUND_COLOR);
+    G_chooser->show();
+
+    // Block until user picks something.
+    //     (The other way to do this is to use a callback())
+    //
+    while(G_chooser->shown()) {
+        Fl::wait();
+    }
+
+    // Print the results
+    if ( G_chooser->value() == NULL ) {
+        //fprintf(stderr, "(User hit 'Cancel')\n");
+        return;
+    }
+
+    char relname[FL_PATH_MAX];
+    fl_filename_relative(relname,sizeof(relname),G_chooser->value());
+    inp->value(relname);
+}
+
+// ==============================================================================
+// RadioEntry ================================================================
+// ==============================================================================
+void RadioEntry::initialise(int x, int y, int height,
+		                     int wcol2, int wcol3, int wcol4,
+		                     const char* title,
+		                     Fl_Menu_Item *options,
+		                     Fl_Menu_Item* defaultvalue,
+		                     const char* helptext,
+		    				 Fl_Group * deactivate_this_group)
+{
+	AnyEntry::initialise(x,y,height,
+			wcol2,wcol3,
+			title,
+			defaultvalue->label(),
+			helptext);
+
+    // Pull-down menu button
+	//Fl_File_Chooser * G_chooser = new Fl_File_Chooser("", "", Fl_File_Chooser::SINGLE, "");
+
+	my_deactivate_group = deactivate_this_group;
+	choice = new Fl_Choice(XCOL2, y, WCOL2, height);
+    choice->menu(options);
+    choice->picked(defaultvalue);
+    choice->callback(cb_menu, this);
+
+    menu = choice;
+    //menu->color(GUI_BACKGROUND_COLOR);
+    menu->color(GUI_INPUT_COLOR);
+}
+
+
+void RadioEntry::place(int &y,
+			const char * title,
+			Fl_Menu_Item *options,
+			Fl_Menu_Item* defaultvalue,
+			const char* helptext,
+			int x, int h, int wcol2, int wcol3, int wcol4 )
+
+{
+    // Clear if existing
+	clear();
+
+	// Add the entry to the window
+	initialise(x, y, h, wcol2, wcol3, wcol4, title, options, defaultvalue, helptext);
+
+    // Update the Y-coordinate
+    y += h + 2;
+
+}
+
+void RadioEntry::clear()
+{
+	if (label != "")
+	{
+		AnyEntry::clear();
+		//delete choice;
+		delete menu;
+	}
+}
+
+void RadioEntry::deactivate(bool do_deactivate)
+{
+	AnyEntry::deactivate(do_deactivate);
+	if (do_deactivate)
+	{
+		menu->deactivate();
+	}
+	else
+	{
+		menu->activate();
+	}
+
+}
+
+std::string RadioEntry::getValue()
+{
+	return (std::string)inp->value();
+}
+
+void RadioEntry::readValue(std::ifstream& in)
+{
+	if (label != "")
+	{
+		AnyEntry::readValue(in);
+		const Fl_Menu_Item *p = choice->find_item(inp->value());
+		if ( p )
+			choice->picked(p);
+		else
+			std::cerr << "Error readValue: Menu item not found:" << inp->value()<< std::endl;
+	}
+}
+
+
+void RadioEntry::cb_menu(Fl_Widget* o, void* v) {
+
+    RadioEntry* T=(RadioEntry*)v;
+    T->cb_menu_i();
+}
+
+
+void RadioEntry::cb_menu_i()
+{
+
+	const Fl_Menu_Item* m = menu->mvalue();
+	// Set my own value
+	inp->value(m->label());
+
+	// In case this was a boolean that deactivates a group, do so:
+	if (my_deactivate_group != NULL)
+	if (strcmp(inp->value(), "No") == 0)
+		my_deactivate_group->deactivate();
+	else
+		my_deactivate_group->activate();
+
+}
+
+// ==============================================================================
+// BooleanEntry ================================================================
+// ==============================================================================
+void BooleanEntry::initialise(int x, int y, int height,
+		                     int wcol2, int wcol3, int wcol4,
+		                     const char* title,
+		                     bool defaultvalue,
+		                     const char* helptext,
+		    				 Fl_Group * deactivate_this_group)
+{
+
+	Fl_Menu_Item* defval;
+
+	if (defaultvalue)
+		defval = &bool_options[0];
+	else
+		defval = &bool_options[1];
+	RadioEntry::initialise(x,y,height,
+			wcol2,wcol3,wcol4,
+			title,
+			bool_options,
+			defval,
+			helptext,
+			deactivate_this_group);
+
+}
+
+void BooleanEntry::place(int &y,
+		const char * title,
+		bool defaultvalue,
+		const char* helptext,
+		Fl_Group * deactivate_this_group,
+		int x, int h, int wcol2, int wcol3, int wcol4 )
+{
+
+    // Clear if existing
+	clear();
+
+	// Add the entry to the window
+	initialise(x, y, h, wcol2, wcol3, wcol4, title, defaultvalue, helptext, deactivate_this_group);
+
+    // Update the Y-coordinate
+    y += h + 2;
+
+
+}
+
+bool BooleanEntry::getValue()
+{
+	if (strcmp(inp->value(), "Yes") == 0)
+		return true;
+	else
+		return false;
+}
+
+// ==============================================================================
+// SliderEntry ================================================================
+// ==============================================================================
+void SliderEntry::initialise(int x, int y, int height,
+		                     int wcol2, int wcol3, int wcol4,
+		                     const char* title,
+		                     float defaultvalue,
+		                     float minvalue,
+		                     float maxvalue,
+		                     float valuestep,
+		                     const char* helptext)
+{
+
+	int floatwidth = 50;
+	AnyEntry::initialise(x,y,height,
+			floatwidth,wcol3,
+			title,
+			"",
+			helptext);
+
+	// Initialise label
+	label = title;
+
+	// Slider is shorter than wcol2, so that underlying input field becomes visible
+	slider = new Fl_Slider(XCOL2 + floatwidth, y, wcol2 - floatwidth, height);
+	slider->type(1);
+	slider->callback(cb_slider, this);
+	slider->minimum(minvalue);
+	slider->maximum(maxvalue);
+	slider->step(valuestep);
+	slider->type(FL_HOR_NICE_SLIDER);
+	slider->color(GUI_BACKGROUND_COLOR);
+	inp->callback(cb_input, this);
+	inp->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED);
+
+	// Set the default in the input and the slider:
+	std::string str = floatToString(defaultvalue);
+	inp->value(str.c_str());
+	slider->value(defaultvalue);
+
+}
+
+void SliderEntry::place(int &y,
+		const char* title,
+		float defaultvalue,
+		float minvalue,
+		float maxvalue,
+		float valuestep,
+		const char* helptext,
+		int x, int h, int wcol2, int wcol3, int wcol4 )
+{
+
+    // Clear if existing
+	clear();
+
+	// Add the entry to the window
+	initialise(x, y, h, wcol2, wcol3, wcol4, title, defaultvalue, minvalue, maxvalue, valuestep, helptext);
+
+    // Update the Y-coordinate
+    y += h + 2;
+
+}
+
+void SliderEntry::clear()
+{
+	if (label != "")
+	{
+		AnyEntry::clear();
+		delete slider;
+	}
+}
+
+void SliderEntry::deactivate(bool do_deactivate)
+{
+	AnyEntry::deactivate(do_deactivate);
+	if (do_deactivate)
+	{
+		slider->deactivate();
+	}
+	else
+	{
+		slider->activate();
+	}
+
+}
+
+
+float SliderEntry::getValue()
+{
+	return textToFloat(inp->value());
+}
+
+void SliderEntry::readValue(std::ifstream& in)
+{
+	if (label != "")
+	{
+		AnyEntry::readValue(in);
+		// Also reset the slider
+		slider->value(textToFloat(inp->value()));
+	}
+}
+
+void SliderEntry::cb_slider(Fl_Widget* o, void* v) {
+
+    SliderEntry* T=(SliderEntry*)v;
+    T->cb_slider_i();
+}
+
+
+void SliderEntry::cb_slider_i() {
+
+    static int recurse = 0;
+    if ( recurse ) {
+        return;
+    } else {
+        recurse = 1;
+        std::string str = floatToString(slider->value());
+        inp->value(str.c_str());
+        slider->redraw();
+        recurse = 0;
+    }
+}
+
+void SliderEntry::cb_input(Fl_Widget* o, void* v) {
+
+    SliderEntry* T=(SliderEntry*)v;
+    T->cb_input_i();
+}
+
+
+void SliderEntry::cb_input_i() {
+
+    static int recurse = 0;
+    if ( recurse ) {
+        return;
+    } else {
+        recurse = 1;
+        //slider->value(textToFloat(my_input->value()));         // pass input's value to slider
+        slider->value(textToFloat(inp->value()));         // pass input's value to slider
+        //inp->value(my_input->value()); // also set the normal input for getValue!
+        recurse = 0;
+    }
+}
+
+
diff --git a/src/gui_entries.h b/src/gui_entries.h
new file mode 100644
index 0000000..72a21f6
--- /dev/null
+++ b/src/gui_entries.h
@@ -0,0 +1,418 @@
+/*
+ * gui_entries.h
+ *
+ *  Created on: Oct 7, 2013
+ *      Author: "Sjors H.W. Scheres"
+ */
+
+#ifndef GUI_ENTRIES_H_
+#define GUI_ENTRIES_H_
+#include <FL/Fl.H>
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Text_Display.H>
+#include <FL/Fl_Text_Buffer.H>
+#include <FL/Fl_Box.H>
+#include <FL/Fl_Input.H>
+#include <FL/Fl_Float_Input.H>
+#include <FL/Fl_File_Chooser.H>
+#include <FL/Fl_Tabs.H>
+#include <FL/Fl_Slider.H>
+#include <FL/Fl_Group.H>
+#include <FL/Fl_Tabs.H>
+#include <FL/Fl_Hold_Browser.H>
+#include <FL/Fl_Menu_Bar.H>
+#include <FL/Fl_Menu_Button.H>
+#include <FL/Fl_Choice.H>
+#include <FL/Fl_Toggle_Button.H>
+#include <FL/Fl_Widget.H>
+#include <FL/Fl_Wizard.H>
+#include "src/macros.h"
+#include "src/strings.h"
+#include <string>
+#include <sstream>
+#include <iomanip>
+#include <math.h>
+#include <fstream>
+#include <cstdio>
+#include <vector>
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+// Gui layout
+//#define XCOL1 10
+//#define XCOL2 260
+//#define XCOL3 460
+//#define XCOL4 475
+//#define XCOL5 535
+#define GUIWIDTH 800
+#define GUIHEIGHT 400
+#define XCOL0 200
+#define WCOL0 200
+#define XCOL1 ( (XCOL0) + 10  )
+#define XCOL2 ( (XCOL0) + 260 )
+#define XCOL3 ( (XCOL0) + 460 )
+#define XCOL4 ( (XCOL0) + 475 )
+#define XCOL5 ( (XCOL0) + 535 )
+#define STEPY 22
+#define COLUMN_SEPARATION 3
+#define WCOL1 ( (XCOL2) - (XCOL1) - (COLUMN_SEPARATION) )
+#define WCOL2 ( (XCOL3) - (XCOL2) - (COLUMN_SEPARATION) )
+#define WCOL3 ( (XCOL4) - (XCOL3) - (COLUMN_SEPARATION) )
+#define WCOL4 ( (XCOL5) - (XCOL4) - (COLUMN_SEPARATION) )
+//version-1.0 #define GUI_BUTTON_COLOR (fl_rgb_color(200,255,100))
+//version-1.1 #define GUI_BUTTON_COLOR (fl_rgb_color(50,150,250))
+//version-1.2 #define GUI_BUTTON_COLOR (fl_rgb_color(155,150,255))
+//devel-version
+#define GUI_BUTTON_COLOR (fl_rgb_color(50, 200, 50))
+#define GUI_BUTTON_DARK_COLOR (fl_rgb_color(0, 155, 0))
+//possible?#define GUI_BUTTON_COLOR (fl_rgb_color(50, 200, 255))
+//version-1.0 #define GUI_RUNBUTTON_COLOR (fl_rgb_color(255,155,0))
+//version-1.1 #define GUI_RUNBUTTON_COLOR (fl_rgb_color(255,50,50))
+//version-1.2 #define GUI_RUNBUTTON_COLOR (fl_rgb_color(205,53,100))
+//devel-version
+#define GUI_RUNBUTTON_COLOR (fl_rgb_color(255,80,80))
+//possible?#define GUI_RUNBUTTON_COLOR (fl_rgb_color(205,0,155))
+#
+#define GUI_BACKGROUND_COLOR (fl_rgb_color(240,240,240))
+#define GUI_BACKGROUND_COLOR2 (fl_rgb_color(200,200,200))
+#define GUI_INPUT_COLOR (fl_rgb_color(255,255,230))
+
+// Replace a single instance of text in a buffer. Return true if replaced, false otherwise
+bool replaceStringOnce(Fl_Text_Buffer *textbuf, std::string replacethis, std::string replaceby);
+// General utility to replace strings in a text buffer.
+void replaceStringAll(Fl_Text_Buffer *textbuf, std::string replacethis, std::string replaceby);
+void appendLineString(Fl_Text_Buffer *textbuf, std::string copylinewiththis, int times);
+
+/** This class displays opens an additional window with (help) text
+ *
+ */
+class ShowHelpText{
+
+public:
+    // Constructor that opens and displays the window
+	ShowHelpText(const char* help = NULL);
+	// Empty destructor
+    ~ShowHelpText();
+};
+
+
+static Fl_Menu_Item bool_options[] = {
+			      {"Yes"},
+			      {"No"},
+			      {0} // this should be the last entry
+			      };
+
+class textOnlyEntry{
+
+public:
+	Fl_Text_Display* mydisp;
+	Fl_Text_Buffer *textbuff;
+	bool has_been_set;
+
+	textOnlyEntry()
+	{
+		has_been_set=false;
+	}
+	~textOnlyEntry(){};
+
+	void initialise(int x, int y, int width, int height, const char* text)
+	{
+		mydisp = new Fl_Text_Display(XCOL1, y, width, height);
+		textbuff = new Fl_Text_Buffer();
+		textbuff->text(text);
+		mydisp->buffer(textbuff);
+		mydisp->color(GUI_BACKGROUND_COLOR);
+		has_been_set=true;
+	}
+
+	void place(int &y,
+			const char* text,
+			int width= WCOL1 + WCOL2 + WCOL3, int height = STEPY + 6, int x = XCOL1)
+	{
+	    // Clear if existing
+		clear();
+
+		// Add the entry to the window
+		// Add 3 to step_y, otherwise the text may not fit...
+		initialise(x, y, width, height, text);
+
+	    // Update the Y-coordinate
+	    y += height + 2;
+
+
+	}
+
+	void clear()
+	{
+		if (has_been_set)
+		{
+			delete mydisp;
+			delete textbuff;
+			has_been_set = false;
+		}
+	}
+};
+
+/** This is the main class to generate input entry-lines in the Gui windows.
+ *  It implements three columns to be displayed:
+ *  1. box with the label
+ *  2. Input field with the input value
+ *  3. Help button that pops up a window with additional help text
+ *
+ *  All specific entries (e.g. to get FileName, Boolean, etc. inherit from this class)
+ *
+ *
+ */
+class AnyEntry{
+
+public:
+    // Input value storage
+	Fl_Input* inp;
+
+	// Label
+	std::string label;
+
+    // Button to show additional help text
+	Fl_Button* help;
+
+	// The additional help text
+    const char *myhelptext;
+
+    /** Constructor with x,y-position from top left
+	 *  wcol1, wcol2 and wcol3 are the widths of the three columns described above
+	 *  title is the value displayed in the first column
+	 *  defaultvalue is what will appear by default in the input value
+	 *  help is the additional help text. If it is set to NULL, no help button will be displayed
+	 */
+	AnyEntry(){};
+
+    /** Empty destructor
+     */
+	~AnyEntry(){};
+
+	/** Here really start the entry
+	 */
+	void initialise(int x, int y, int height, int wcol2, int wcol3, const char* title, const char* defaultvalue = NULL, const char* help = NULL);
+
+	/** Place an entry on a window
+	 */
+	void place(int &y,
+				const char * title,
+				const char* defaultvalue = NULL,
+				const char* helptext = NULL,
+				int x = XCOL1, int h = STEPY, int wcol2 = WCOL2, int wcol3 = WCOL3 );
+
+	// Get the value
+    std::string getValue();
+
+    // Set the value
+    void setValue(const char* inp);
+
+    // Clear this entry
+	void clear();
+
+    // Deactivate this entry if the input boolean is true
+    void deactivate(bool do_deactivate = true);
+
+    // Save the value to a file
+    void writeValue(std::ostream& out);
+
+    // Read the value from a file
+    void readValue(std::ifstream& in);
+
+    /** Call-back functions for the help button
+     *  The method of using two functions of static void and inline void was copied from:
+     *  http://www3.telus.net/public/robark/
+     */
+    static void cb_help(Fl_Widget*, void*);
+    void cb_help_i();
+};
+
+
+// Get a FileName value from the user (with browse button).
+class FileNameEntry: public AnyEntry
+{
+
+public:
+	// Browse button
+    Fl_Button* browse;
+
+    const char* pattern;
+
+    // Constructor (with 4 column widths)
+	FileNameEntry() {};
+
+    // Destructor
+	~FileNameEntry(){};
+
+	void initialise(int x, int y, int height,
+    		int wcol2, int wcol3, int wcol4,
+    		const char* title,
+    		const char* defaultvalue,
+    		const char* _pattern = "",
+    		const char* help = NULL);
+
+	// places on one the window
+	void place(int &y,
+				const char * title,
+				const char* defaultvalue = NULL,
+				const char* pattern = "",
+				const char* helptext = NULL,
+				int x = XCOL1, int h = STEPY, int wcol2 = WCOL2, int wcol3 = WCOL3, int wcol4 = WCOL4 );
+
+    // Clear this entry
+	void clear();
+
+	// Deactivate this entry if the input boolean is true
+    void deactivate(bool do_deactivate = true);
+
+
+private:
+    // Call-back functions for the browse button
+    static void cb_browse(Fl_Widget*, void*);
+    void cb_browse_i();
+
+};
+
+// Get an entry from a list of possible values from the user.
+class RadioEntry: public AnyEntry
+{
+public:
+
+    // The choices
+    Fl_Choice * choice;
+    // The menu
+    Fl_Menu_* menu;
+    // Deactivate this group
+    Fl_Group * my_deactivate_group;
+
+    // Constructor
+    RadioEntry(){};
+
+    // Destructor
+    ~RadioEntry(){};
+
+    void initialise(int x, int y, int height,
+				 int wcol2, int wcol3, int wcol4,
+				 const char* title,
+				 Fl_Menu_Item *options,
+				 Fl_Menu_Item* defaultvalue,
+				 const char* help = NULL,
+				 Fl_Group * deactivate_this_group = NULL);
+
+    void place(int &y,
+				const char * title,
+				Fl_Menu_Item *options,
+				Fl_Menu_Item* defaultvalue,
+				const char* helptext = NULL,
+				int x = XCOL1, int h = STEPY, int wcol2 = WCOL2, int wcol3 = WCOL3, int wcol4 = WCOL4 );
+
+    // Clear this entry
+	void clear();
+
+	// Deactivate this entry if the input boolean is true
+    void deactivate(bool do_deactivate = true);
+
+    // Get the value
+    std::string getValue();
+
+    // Read the value from a file
+    void readValue(std::ifstream& in);
+
+	void call_menu_i()
+    {
+        cb_menu_i();
+    }
+
+public: // this one is public so that it can be called in mainwindow to deactivate default groups
+    static void cb_menu(Fl_Widget*, void*);
+    void cb_menu_i();
+};
+
+class BooleanEntry: public RadioEntry
+{
+public:
+	// Constructor
+	BooleanEntry(){};
+
+	// Destructor
+    ~BooleanEntry(){};
+
+    void initialise(int x, int y, int height,
+				 int wcol2, int wcol3, int wcol4,
+				 const char* title,
+				 bool defaultvalue,
+				 const char* help = NULL,
+				 Fl_Group * deactivate_this_group = NULL);
+
+    void place(int &y,
+				const char * title,
+				bool defaultvalue = true,
+				const char* help = NULL,
+				Fl_Group * deactivate_this_group = NULL,
+				int x = XCOL1, int h = STEPY, int wcol2 = WCOL2, int wcol3 = WCOL3, int wcol4 = WCOL4 );
+
+    // Get the value
+    bool getValue();
+
+
+};
+
+class SliderEntry:  public RadioEntry
+{
+
+public:
+    // The slider
+    Fl_Slider * slider;
+
+    // Constructor
+	SliderEntry(){};
+
+	// Destructor
+    ~SliderEntry(){};
+
+    void initialise(int x, int y, int height,
+				 int wcol2, int wcol3, int wcol4,
+				 const char* title,
+				 float defaultvalue,
+                 float minvalue,
+                 float maxvalue,
+                 float valuestep,
+				 const char* help = NULL);
+
+    void place(int &y,
+				const char* title,
+				float defaultvalue,
+				float minvalue,
+				float maxvalue,
+				float valuestep,
+				const char* help,
+				int x = XCOL1, int h = STEPY, int wcol2 = WCOL2, int wcol3 = WCOL3, int wcol4 = WCOL4 );
+
+    // Clear this entry
+	void clear();
+
+	// Deactivate this entry if the input boolean is true
+    void deactivate(bool do_deactivate = true);
+
+    // Get the value
+    float getValue();
+
+    // Read the value from a file
+    void readValue(std::ifstream& in);
+
+
+private:
+    static void cb_slider(Fl_Widget*, void*);
+    void cb_slider_i();
+
+    static void cb_input(Fl_Widget*, void*);
+    void cb_input_i();
+
+
+};
+
+
+#endif /* GUI_ENTRIES_H_ */
diff --git a/src/gui_jobwindow.cpp b/src/gui_jobwindow.cpp
new file mode 100644
index 0000000..46c9817
--- /dev/null
+++ b/src/gui_jobwindow.cpp
@@ -0,0 +1,3132 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/gui_jobwindow.h"
+
+RelionJobWindow::RelionJobWindow(int nr_tabs, bool _has_mpi, bool _has_thread, bool _has_run,
+		int x, int y, int w, int h, const char* title) : Fl_Box(x,y,w,h,title)
+{
+
+	current_y = y;
+	has_mpi = _has_mpi;
+	has_thread = _has_thread;
+
+    // Set up tabs
+    if (nr_tabs >= 1) // there is always the running tab, which is not counted on the input nr_tabs!
+    {
+    	tabs = new Fl_Tabs(x, current_y, w, h - MENUHEIGHT);
+    	current_y += TABHEIGHT;
+    	tabs->begin();
+		tab1 = new Fl_Group(x, current_y , w, h - MENUHEIGHT, "");
+		tab1->end();
+		tab1->color(GUI_BACKGROUND_COLOR);
+		tab1->selection_color(GUI_BACKGROUND_COLOR2);
+		if (nr_tabs >= 2)
+		{
+
+			tab2 = new Fl_Group(x, current_y , w, h - MENUHEIGHT, "");
+			tab2->end();
+			tab2->color(GUI_BACKGROUND_COLOR);
+			tab2->selection_color(GUI_BACKGROUND_COLOR2);
+		}
+		if (nr_tabs >= 3)
+		{
+			tab3 = new Fl_Group(x, current_y, w, h - MENUHEIGHT, "");
+			tab3->end();
+			tab3->color(GUI_BACKGROUND_COLOR);
+			tab3->selection_color(GUI_BACKGROUND_COLOR2);
+		}
+		if (nr_tabs >= 4)
+		{
+			tab4 = new Fl_Group(x, current_y, w, h - MENUHEIGHT, "");
+			tab4->end();
+			tab4->color(GUI_BACKGROUND_COLOR);
+			tab4->selection_color(GUI_BACKGROUND_COLOR2);
+		}
+		if (nr_tabs >= 5)
+		{
+			tab5 = new Fl_Group(x, current_y, w, h - MENUHEIGHT, "");
+			tab5->end();
+			tab5->color(GUI_BACKGROUND_COLOR);
+			tab5->selection_color(GUI_BACKGROUND_COLOR2);
+		}
+		if (nr_tabs >= 6)
+		{
+			tab6 = new Fl_Group(x, current_y, w, h - MENUHEIGHT, "");
+			tab6->end();
+			tab6->color(GUI_BACKGROUND_COLOR);
+			tab6->selection_color(GUI_BACKGROUND_COLOR2);
+		}
+		if (nr_tabs >= 7)
+		{
+			std::cerr << "ERROR: only 6 job-specific tabs implemented..." << std::endl;
+			exit(1);
+		}
+		current_y += 15;
+	    start_y = current_y;
+
+	    if (_has_run)
+	    {
+			runtab = new Fl_Group(x, current_y, w, h - MENUHEIGHT, "");
+			runtab->label("Running");
+			setupRunTab();
+			runtab->end();
+			runtab->color(GUI_BACKGROUND_COLOR);
+			runtab->selection_color(GUI_BACKGROUND_COLOR2);
+	    }
+
+	    tabs->end();
+
+    }
+
+}
+
+void RelionJobWindow::resetHeight()
+{
+	current_y = start_y;
+}
+
+void RelionJobWindow::setupRunTab()
+{
+    resetHeight();
+
+	if (has_mpi)
+		nr_mpi.place(current_y, "Number of MPI procs:", 1, 1, 64, 1, "Number of MPI nodes to use in parallel. When set to 1, MPI will not be used.");
+
+	if (has_thread)
+	{
+		nr_threads.place(current_y, "Number of threads:", 1, 1, 16, 1, "Number of shared-memory (POSIX) threads to use in parallel. \
+When set to 1, no multi-threading will be used. Multi-threading is often useful in 3D refinements to have more memory. 2D class averaging often proceeds more efficiently without threads.");
+
+		ram_per_thread.place(current_y, "Available RAM (in Gb) per thread:", 4, 1, 16, 1, "Computer memory in Gigabytes that is avaliable for each thread. This will only affect some of the warnings about required computer memory.");
+
+	}
+
+	// Add a little spacer
+	if (has_mpi || has_thread)
+		current_y += STEPY/2;
+
+    // Set up queue groups for running tab
+    queue_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+    queue_group->end();
+
+    do_queue.place(current_y, "Submit to queue?", false, "Is set to Yes, the job will be submit to a queue, otherwise \
+the job will be executed locally. Note that only MPI jobs may be sent to a queue.", queue_group);
+
+	queue_group->begin();
+
+	queuename.place(current_y, "Queue name: ", "openmpi", "Name of the queue to which to submit the job.");
+
+	qsub.place(current_y, "Queue submit command:", "qsub", "Name of the command used to submit scripts to the queue, e.g. qsub or bsub.\n\n\
+Note that the person who installed RELION should have made a custom script for your cluster/queue setup. Check this is the case \
+(or create your own script following the RELION WIKI) if you have trouble submitting jobs.");
+
+	// Two additional options that may be set through environment variables RELION_QSUB_EXTRA1 and RELION_QSUB_EXTRA2 (for more flexibility)
+	char * extra1_text = getenv ("RELION_QSUB_EXTRA1");
+	if (extra1_text != NULL)
+	{
+		have_extra1 = true;
+		char * extra1_default = getenv ("RELION_QSUB_EXTRA1_DEFAULT");
+		char emptychar[] = "";
+		if (extra1_default == NULL)
+			extra1_default=emptychar;
+		qsub_extra1.place(current_y, extra1_text, extra1_default, "Extra option to pass to the qsub template script. \
+Any occurrences of XXXextra1XXX will be changed by this value.");
+	}
+	else
+		have_extra1 = false;
+
+	char * extra2_text = getenv ("RELION_QSUB_EXTRA2");
+	if (extra2_text != NULL)
+	{
+		have_extra2 = true;
+		char * extra2_default = getenv ("RELION_QSUB_EXTRA2_DEFAULT");
+		char emptychar[] = "";
+		if (extra2_default == NULL)
+			extra2_default=emptychar;
+		qsub_extra2.place(current_y, extra2_text, extra2_default, "Extra option to pass to the qsub template script. \
+Any occurrences of XXXextra2XXX will be changed by this value.");
+	}
+	else
+		have_extra2 = false;
+
+
+	// Check for environment variable RELION_QSUB_TEMPLATE
+	char * default_location = getenv ("RELION_QSUB_TEMPLATE");
+	if (default_location==NULL)
+	{
+		char mydefault[]=DEFAULTQSUBLOCATION;
+		default_location=mydefault;
+	}
+
+	qsubscript.place(current_y, "Standard submission script:", default_location, "Script Files (*.{csh,sh,bash,script})",
+"The template for your standard queue job submission script. \
+Its default location may be changed by setting the environment variable RELION_QSUB_TEMPLATE. \
+In the template script a number of variables will be replaced: \n \
+XXXcommandXXX = relion command + arguments; \n \
+XXXqueueXXX = The queue name; \n \
+XXXmpinodesXXX = The number of MPI nodes; \n \
+XXXthreadsXXX = The number of threads; \n \
+XXXcoresXXX = The number of MPI nodes * nr_threads; \n \
+If these options are not enough for your standard jobs, you may define two extra variables: XXXextra1XXX and XXXextra2XXX \
+Their help text is set by the environment variables RELION_QSUB_EXTRA1 and RELION_QSUB_EXTRA2 \
+For example, setenv RELION_QSUB_EXTRA1 \"Max number of hours in queue\" will result in an additional (text) ein the GUI \
+Any variables XXXextra1XXX in the template script will be replaced by the corresponding value.\
+Likewise, default values for the extra entries can be set through environment variables RELION_QSUB_EXTRA1_DEFAULT and  RELION_QSUB_EXTRA2_DEFAULT. \
+But note that (unlike all other entries in the GUI) the extra values are not remembered from one run to the other.");
+
+
+	queue_group->end();
+	do_queue.cb_menu_i(); // This is to make the default effective
+
+    // Add a little spacer
+    current_y += STEPY/2;
+
+    other_args.place(current_y, "Additional arguments:", "", "In this box command-line arguments may be provided that are not generated by the GUI. \
+This may be useful for testing developmental options and/or expert use of the program. \
+The command 'relion_refine' will print a list of possible options.");
+
+}
+
+void RelionJobWindow::toggle_new_continue(bool is_continue)
+{
+	std::cerr << "toggle default is_continue=" << is_continue << std::endl;
+	return;
+}
+
+void RelionJobWindow::openWriteFile(std::string fn, std::ofstream &fh)
+{
+	fh.open((fn).c_str(), std::ios::out);
+    if (!fh)
+    {
+    	std::cerr << "Cannot write to file: "<<fn<<std::endl;
+    	exit(1);
+    }
+
+    // is_continue flag
+    if (is_continue)
+    	fh << "is_continue == true" << std::endl;
+    else
+    	fh << "is_continue == false" << std::endl;
+}
+
+bool RelionJobWindow::openReadFile(std::string fn, std::ifstream &fh)
+{
+	fh.open(fn.c_str(), std::ios_base::in);
+    if (fh.fail())
+    	return false;
+    else
+    {
+		fh.seekg(0, std::ios::beg);
+		std::string line;
+		getline(fh, line, '\n');
+		if (line.rfind("is_continue == true") == 0)
+			is_continue = true;
+		else
+			is_continue = false;
+
+		return true;
+    }
+}
+
+void RelionJobWindow::closeWriteFile(std::ofstream& fh)
+{
+	if (has_mpi)
+		nr_mpi.writeValue(fh);
+	if (has_thread)
+	{
+		nr_threads.writeValue(fh);
+		ram_per_thread.writeValue(fh);
+	}
+	do_queue.writeValue(fh);
+	queuename.writeValue(fh);
+	qsub.writeValue(fh);
+	if (have_extra1)
+		qsub_extra1.writeValue(fh);
+	if (have_extra2)
+		qsub_extra2.writeValue(fh);
+	qsubscript.writeValue(fh);
+	other_args.writeValue(fh);
+
+	fh.close();
+}
+
+void RelionJobWindow::closeReadFile(std::ifstream& fh)
+{
+	if (has_mpi)
+		nr_mpi.readValue(fh);
+	if (has_thread)
+	{
+		nr_threads.readValue(fh);
+		ram_per_thread.readValue(fh);
+	}
+	do_queue.readValue(fh);
+	queuename.readValue(fh);
+	qsub.readValue(fh);
+	if (have_extra1)
+		qsub_extra1.readValue(fh);
+	if (have_extra2)
+		qsub_extra2.readValue(fh);
+	qsubscript.readValue(fh);
+	other_args.readValue(fh);
+
+}
+
+void RelionJobWindow::saveJobSubmissionScript(std::string newfilename, std::string outputname, std::vector<std::string> commands)
+{
+	Fl_Text_Buffer *textbuf = new Fl_Text_Buffer;
+
+	// Open the standard job submission file
+	int errno;
+	if (errno = textbuf->loadfile(qsubscript.getValue().c_str()))
+	    fl_alert("Error reading from file \'%s\':\n%s.", qsubscript.getValue().c_str(), strerror(errno));
+
+	// default to a single thread
+	int nthr = (has_thread) ? nr_threads.getValue() : 1;
+
+	replaceStringAll(textbuf, "XXXmpinodesXXX", floatToString(nr_mpi.getValue()) );
+	replaceStringAll(textbuf, "XXXthreadsXXX", floatToString(nthr) );
+	replaceStringAll(textbuf, "XXXcoresXXX", floatToString(nr_mpi.getValue() * nthr) );
+	replaceStringAll(textbuf, "XXXnameXXX", outputname);
+	replaceStringAll(textbuf, "XXXerrfileXXX", outputname + ".err");
+	replaceStringAll(textbuf, "XXXoutfileXXX", outputname + ".out");
+	replaceStringAll(textbuf, "XXXqueueXXX", queuename.getValue() );
+	if (have_extra1)
+		replaceStringAll(textbuf, "XXXextra1XXX", qsub_extra1.getValue() );
+	if (have_extra2)
+		replaceStringAll(textbuf, "XXXextra2XXX", qsub_extra2.getValue() );
+
+	// Get commands.size() entries with the actual command
+	if (commands.size() > 1)
+		appendLineString(textbuf, "XXXcommandXXX", commands.size() - 1);
+
+	for (int icom = 0; icom < commands.size(); icom++)
+		replaceStringOnce(textbuf, "XXXcommandXXX", commands[icom] );
+
+	// Make sure the file ends with an empty line
+	textbuf->append("\n");
+
+	// Save the modified job submission script using a local name
+	if (errno = textbuf->savefile(newfilename.c_str()))
+	    fl_alert("Error writing to file \'%s\':\n%s.", newfilename.c_str(), strerror(errno));
+
+}
+
+
+void RelionJobWindow::prepareFinalCommand(std::string &outputname, std::vector<std::string> &commands, std::string &final_command)
+{
+
+	// Create output directory if the outname contains a "/"
+	int last_slash = outputname.rfind("/");
+	if (last_slash < outputname.size())
+	{
+		std::string dirs = outputname.substr(0, last_slash);
+		std::string makedirs = "mkdir -p " + dirs;
+		system(makedirs.c_str());
+	}
+
+	// Prepare full mpi commands or save jobsubmission script to disc
+	if (do_queue.getValue())
+	{
+		// Make the submission script and write it to disc
+		std::string output_script = outputname + "_submit.script";
+		saveJobSubmissionScript(output_script, outputname, commands);
+		final_command = qsub.getValue() + " " + output_script + " &";
+	}
+	else
+	{
+		// If there are multiple commands, then join them all on a single line (final_command)
+		// Also add mpirun in front of all commands if no submission via the queue is done
+		std::string one_command;
+		final_command = "";
+		for (int icom = 0; icom < commands.size(); icom++)
+		{
+			if (has_mpi && nr_mpi.getValue() > 1)
+				one_command = "mpirun -n " + floatToString(nr_mpi.getValue()) + " " + commands[icom] ;
+			else
+				one_command = commands[icom];
+			final_command += one_command;
+			if (icom == commands.size() - 1)
+				final_command += " & "; // end by putting composite job in the background
+			else
+				final_command += " && "; // execute one command after the other...
+		}
+	}
+
+}
+
+/*
+XXXXJobWindow::XXXXJobWindow() : RelionJobWindow(4, HAS_MPI, HAS_THREAD)
+{
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+	//ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	//ctf_group->end();
+
+	tab1->end();
+
+	// read settings if hidden file exists
+	read(".gui_general.settings", is_continue);
+}
+void XXXXJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_general.settings", fh);
+	closeWriteFile(fh);
+}
+void XXXXJobWindow::read(std::string fn, bool &_is_continue)
+{
+	std::ifstream fh;
+	// Only read things if the file exists
+	if (openReadFile(fn, fh))
+	{
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+void XXXXJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+}
+void XXXXJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command)
+{
+	commands.clear();
+	std::string command;
+	if (nr_mpi.getValue() > 1)
+		command="`which relion_XXX_mpi`";
+	else
+		command="`which relion_XXX`";
+
+
+	// Other arguments for extraction
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+	outputname = "run_ctffind";
+	prepareFinalCommand(outputname, commands, final_command);
+}
+*/
+
+GeneralJobWindow::GeneralJobWindow() : RelionJobWindow(1, HAS_MPI, HAS_NOT_THREAD, HAS_NOT_RUN)
+{
+
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+
+	angpix.place(current_y, "Magnified pixel size (Angstrom):", 1.0, 0.1, 5.0, 0.1, "Magnified pixel size in Angstroms (preferably calculated using a calibrated magnification). \
+However, when an exact calibrated pixel size is not available, one may use a preliminary one throughout the entire RELION processing workflow. This will all be internally consistent. \
+Then, at the postprocessing step (when one has a better idea of the actual pixel size, e.g. through the fitting of an atomic model) one may change to a more accurate pixel size at that stage.");
+
+	particle_diameter.place(current_y, "Particle mask diameter (A):", 200, 0, 1000, 10, "The experimental images will be masked with a soft \
+circular mask with this diameter. Make sure this radius is not set too small because that may mask away part of the signal! \
+If set to a value larger than the image size no masking will be performed.\n\n\
+The same diameter will also be used for a spherical mask of the reference structures if no user-provided mask is specified.");
+
+	tab1->end();
+
+	// read settings if hidden file exists
+	read(".gui_general.settings", is_continue);
+}
+
+void GeneralJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_general.settings", fh);
+
+	angpix.writeValue(fh);
+	particle_diameter.writeValue(fh);
+
+	closeWriteFile(fh);
+
+}
+
+void GeneralJobWindow::read(std::string fn, bool &_is_continue)
+{
+
+	std::ifstream fh;
+	// Only read things if the file exists
+	if (openReadFile(fn, fh))
+	{
+		angpix.readValue(fh);
+		particle_diameter.readValue(fh);
+
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+void GeneralJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+
+}
+
+void GeneralJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command)
+{
+	commands.clear();
+	outputname = "run_general";
+	final_command="";
+
+}
+
+CtffindJobWindow::CtffindJobWindow() : RelionJobWindow(3, HAS_MPI, HAS_NOT_THREAD)
+{
+
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+
+	mic_names.place(current_y, "Input micrographs for CTF:", "micrographs_selected.star", "Input micrographs (*.{star,mrc})", "STAR file with the filenames of all micrographs on which to run CTFFIND3, OR a unix-type wildcard to the filenames of the micrograph(s) (e.g. Micrographs/*.mrc).\
+Note that the micrographs should be in a subdirectory (e.g. called Micrographs/) of the project directory, i.e. the directory from where you are launching the GUI. \
+If this is not the case, then make a symbolic link inside the project directory to the directory where your micrographs are stored.");
+
+	output_star_ctf_mics.place(current_y, "Output STAR file:", "micrographs_ctf.star", "Name of the output STAR file with all CTF information for each micrograph");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	// Check for environment variable RELION_QSUB_TEMPLATE
+	char * default_location = getenv ("RELION_CTFFIND3_EXECUTABLE");
+	if (default_location == NULL)
+	{
+		char mydefault[]=DEFAULTCTFFINDLOCATION;
+		default_location=mydefault;
+	}
+
+	fn_ctffind3_exe.place(current_y, "CTFFIND3 executable:", default_location, "*.exe", "Location of the CTFFIND3 executable. You can control the default of this field by setting environment variable RELION_CTFFIND3_EXECUTABLE, or by editing the first few lines in src/gui_jobwindow.h and recompile the code.");
+
+	ctf_win.place(current_y, "Estimate CTF on window size (pix) ", -1, -16, 4096, 16, "If a positive value is given, a squared window of this size at the center of the micrograph will be used to estimate the CTF. This may be useful to exclude parts of the micrograph that are unsuitable for CTF estimation, e.g. the labels at the edge of phtographic film. \n \n The original micrograph will be used (i.e. this option will be ignored) if a negative value is given.");
+
+	tab1->end();
+
+
+	tab2->begin();
+	tab2->label("Microscopy");
+	resetHeight();
+
+	cs.place(current_y, "Spherical aberration (mm):", 2, 0, 8, 0.1, "Spherical aberration of the microscope used to collect these images (in mm)");
+
+	kv.place(current_y, "Voltage (kV):", 300, 50, 500, 10, "Voltage the microscope was operated on (in kV)");
+
+	q0.place(current_y, "Amplitude contrast:", 0.1, 0, 0.3, 0.01, "Fraction of amplitude contrast. Often values around 10% work better than theoretically more accurate lower values...");
+
+	dstep.place(current_y, "Physical pixel size on detector (um):", 14, 1, 32, 1, "Physical pixel size of the detector (in micrometer), e.g. Falcon is 14 um, K2 is 5 um");
+
+	tab2->end();
+
+	tab3->begin();
+	tab3->label("CTFFIND3");
+	resetHeight();
+
+	box.place(current_y, "FFT box size (pix):", 512, 64, 1024, 8, "CTFFIND3's Box parameter");
+
+	resmin.place(current_y, "Minimum resolution (A):", 100, 10, 200, 10, "CTFFIND3's ResMin parameter");
+
+	resmax.place(current_y, "Maximum resolution (A):", 7, 1, 20, 1, "CTFFIND3's ResMax parameter");
+
+	dfmin.place(current_y, "Minimum defocus value (A):", 5000, 0, 25000, 1000, "CTFFIND3's dFMin parameter");
+
+	dfmax.place(current_y, "Maximum defocus value (A):", 50000, 20000, 100000, 1000, "CTFFIND3's dFMax parameter");
+
+	dfstep.place(current_y, "Defocus step size (A):", 500, 200, 2000, 100,"CTFFIND3's FStep parameter");
+
+	dast.place(current_y, "Amount of astigmatism (A):", 0, 0, 2000, 100,"CTFFIND3's dAst parameter");
+
+	tab3->end();
+
+	// read settings if hidden file exists
+	read(".gui_ctffind.settings", is_continue);
+}
+
+void CtffindJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_ctffind.settings", fh);
+
+	mic_names.writeValue(fh);
+	output_star_ctf_mics.writeValue(fh);
+	cs.writeValue(fh);
+	kv.writeValue(fh);
+	q0.writeValue(fh);
+	dstep.writeValue(fh);
+	box.writeValue(fh);
+	resmin.writeValue(fh);
+	resmax.writeValue(fh);
+	dfmin.writeValue(fh);
+	dfmax.writeValue(fh);
+	dfstep.writeValue(fh);
+	dast.writeValue(fh);
+	fn_ctffind3_exe.writeValue(fh);
+	ctf_win.writeValue(fh);
+
+	closeWriteFile(fh);
+}
+
+void CtffindJobWindow::read(std::string fn, bool &_is_continue)
+{
+
+	std::ifstream fh;
+	// Only read things if the file exists
+	if (openReadFile(fn, fh))
+	{
+		mic_names.readValue(fh);
+		output_star_ctf_mics.readValue(fh);
+		cs.readValue(fh);
+		kv.readValue(fh);
+		q0.readValue(fh);
+		dstep.readValue(fh);
+		box.readValue(fh);
+		resmin.readValue(fh);
+		resmax.readValue(fh);
+		dfmin.readValue(fh);
+		dfmax.readValue(fh);
+		dfstep.readValue(fh);
+		dast.readValue(fh);
+		fn_ctffind3_exe.readValue(fh);
+		ctf_win.readValue(fh);
+
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+
+void CtffindJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+
+	mic_names.deactivate(is_continue);
+	output_star_ctf_mics.deactivate(is_continue);
+	cs.deactivate(is_continue);
+	kv.deactivate(is_continue);
+	q0.deactivate(is_continue);
+	dstep.deactivate(is_continue);
+	fn_ctffind3_exe.deactivate(is_continue);
+
+	// TODO: check which log files do not have Final values and re-run on those
+	// for that: modify run_ctffind wrapper program
+}
+
+void CtffindJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
+		std::string &final_command, double angpix)
+{
+	commands.clear();
+	std::string command;
+	if (nr_mpi.getValue() > 1)
+		command="`which relion_run_ctffind_mpi`";
+	else
+		command="`which relion_run_ctffind`";
+
+
+	// Calculate magnification from user-specified pixel size in Angstroms
+	double magn = ROUND((dstep.getValue() * 1e-6) / (angpix * 1e-10));
+
+	command += " --i \"" + mic_names.getValue()+"\"";
+	command += " --o \"" + output_star_ctf_mics.getValue()+"\"";
+	command += " --ctfWin " + floatToString(ctf_win.getValue());
+	command += " --CS " + floatToString(cs.getValue());
+	command += " --HT " + floatToString(kv.getValue());
+	command += " --AmpCnst " + floatToString(q0.getValue());
+	command += " --XMAG " + floatToString(magn);
+	command += " --DStep " + floatToString(dstep.getValue());
+	command += " --Box " + floatToString(box.getValue());
+	command += " --ResMin " + floatToString(resmin.getValue());
+	command += " --ResMax " + floatToString(resmax.getValue());
+	command += " --dFMin " + floatToString(dfmin.getValue());
+	command += " --dFMax " + floatToString(dfmax.getValue());
+	command += " --FStep " + floatToString(dfstep.getValue());
+	command += " --dAst " + floatToString(dast.getValue());
+	command += " --ctffind3_exe " + fn_ctffind3_exe.getValue();
+
+	if (is_continue)
+		command += " --only_do_unfinished ";
+
+	// Other arguments
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+
+	int last_slash_out = mic_names.getValue().rfind("/");
+	if (last_slash_out < mic_names.getValue().size())
+	{
+		// The output name contains a directory: use that one for output
+		outputname = mic_names.getValue().substr(0, last_slash_out + 1) + "run_ctffind";
+	}
+	else
+	{
+		outputname = "run_ctffind";
+	}
+
+	prepareFinalCommand(outputname, commands, final_command);
+
+}
+
+
+ManualpickJobWindow::ManualpickJobWindow() : RelionJobWindow(3, HAS_NOT_MPI, HAS_NOT_THREAD)
+{
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+
+	fn_in.place(current_y, "Input micrographs:", "micrographs_ctf.star", "Input micrographs (*.{star,mrc})", "Input STAR file (with or without CTF information), OR a unix-type wildcard with all micrographs in MRC format (in this case no CTFs can be used).");
+
+	fn_out.place(current_y, "Output STAR file: ", "selected_micrographs_ctf.star", "Output STAR file (*.star)", "The selected micrographs will all be joined in a new STAR file (which has fewer lines than the original input one if micrographs are deselected on the GUI.");
+
+	manualpick_rootname.place(current_y, "Picking rootname: ", "manualpick", "Rootname for the coordinate files of all manually picked particles.");
+
+	tab1->end();
+	tab2->begin();
+	tab2->label("Display");
+	resetHeight();
+
+	micscale.place(current_y, "Scale for micrographs:", 0.2, 0.1, 1, 0.05, "The micrographs will be displayed at this relative scale, i.e. a value of 0.5 means that only every second pixel will be displayed." );
+	sigma_contrast.place(current_y, "Sigma contrast:", 3, 0, 10, 0.5, "The micrographs will be displayed with the black value set to the average of all values MINUS this values times the standard deviation of all values in the micrograph, and the white value will be set \
+to the average PLUS this value times the standard deviation. Use zero to set the minimum value in the micrograph to black, and the maximum value to white ");
+	white_val.place(current_y, "White value:", 0, 0, 512, 16, "Use non-zero values to set the value of the whitest pixel in the micrograph.");
+	black_val.place(current_y, "Black value:", 0, 0, 512, 16, "Use non-zero values to set the value of the blackest pixel in the micrograph.");
+
+	current_y += STEPY/2;
+	lowpass.place(current_y, "Lowpass filter (A)", 0, 0, 100, 5, "Lowpass filter that will be applied to the micrograph before displaying (zero for no filter).");
+
+	current_y += STEPY/2;
+	ctfscale.place(current_y, "Scale for CTF image:", 1, 0.1, 2, 0.1, "CTFFINDs CTF image (with the Thonrings) will be displayed at this relative scale, i.e. a value of 0.5 means that only every second pixel will be displayed." );
+
+	tab2->end();
+	tab3->begin();
+	tab3->label("Colors");
+	color_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	color_group->end();
+
+	resetHeight();
+	do_color.place(current_y, "Blue<>red color particles?", false, "If set to true, then the circles for each particles are coloured from red to blue (or the other way around) for a given metadatalabel. If this metadatalabel is not in the picked coordinates STAR file \
+(basically only the rlnAutopickFigureOfMerit or rlnClassNumber) would be useful values there, then you may provide an additional STAR file (e.g. after classification/refinement below. Particles with values -999, or that are not in the additional STAR file will be coloured the default color: green", color_group);
+
+	color_group->begin();
+	color_label.place(current_y, "MetaDataLabel for color:", "rlnParticleSelectZScore", "The Metadata label of the value to plot from red<>blue. Useful examples might be: \n \
+rlnParticleSelectZScore \n rlnClassNumber \n rlnAutopickFigureOfMerit \n rlnAngleTilt \n rlnLogLikeliContribution \n rlnMaxValueProbDistribution \n rlnNrOfSignificantSamples\n");
+
+	fn_color.place(current_y, "STAR file with color label: ", "", "STAR file (*.star)", "The program will figure out which particles in this STAR file are on the current micrograph and color their circles according to the value in the corresponding column. \
+Particles that are not in this STAR file, but present in the picked coordinates file will be colored green. If this field is left empty, then the color label (e.g. rlnAutopickFigureOfMerit) should be present in the coordinates STAR file.");
+
+	blue_value.place(current_y, "Blue value: ", 0., 0., 4., 0.1, "The value of this entry will be blue. There will be a linear scale from blue to red, according to this value and the one given below.");
+	red_value.place(current_y, "Red value: ", 2., 0., 4., 0.1, "The value of this entry will be red. There will be a linear scale from blue to red, according to this value and the one given above.");
+	color_group->end();
+	do_color.cb_menu_i(); // make default active
+
+	tab3->end();
+
+	// read settings if hidden file exists
+	read(".gui_manualpick.settings", is_continue);
+}
+
+void ManualpickJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_manualpick.settings", fh);
+	fn_in.writeValue(fh);
+	fn_out.writeValue(fh);
+	manualpick_rootname.writeValue(fh);
+	lowpass.writeValue(fh);
+	micscale.writeValue(fh);
+	ctfscale.writeValue(fh);
+	sigma_contrast.writeValue(fh);
+	white_val.writeValue(fh);
+	black_val.writeValue(fh);
+	do_color.writeValue(fh);
+	color_label.writeValue(fh);
+	fn_color.writeValue(fh);
+	blue_value.writeValue(fh);
+	red_value.writeValue(fh);
+
+
+	closeWriteFile(fh);
+}
+
+void ManualpickJobWindow::read(std::string fn, bool &_is_continue)
+{
+	std::ifstream fh;
+	// Only read things if the file exists
+	if (openReadFile(fn, fh))
+	{
+		fn_in.readValue(fh);
+		fn_out.readValue(fh);
+		manualpick_rootname.readValue(fh);
+		lowpass.readValue(fh);
+		micscale.readValue(fh);
+		ctfscale.readValue(fh);
+		sigma_contrast.readValue(fh);
+		white_val.readValue(fh);
+		black_val.readValue(fh);
+		do_color.readValue(fh);
+		color_label.readValue(fh);
+		fn_color.readValue(fh);
+		blue_value.readValue(fh);
+		red_value.readValue(fh);
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+
+void ManualpickJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+	do_queue.deactivate(true);
+}
+
+void ManualpickJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
+		double angpix, double particle_diameter)
+{
+	commands.clear();
+	std::string command;
+	command="`which relion_manualpick`";
+
+	command += " --i \"" + fn_in.getValue() + "\"";
+	command += " --o " + fn_out.getValue();
+	command += " --pickname " + manualpick_rootname.getValue();
+
+	command += " --scale " + floatToString(micscale.getValue());
+	command += " --sigma_contrast " + floatToString(sigma_contrast.getValue());
+	command += " --black " + floatToString(black_val.getValue());
+	command += " --white " + floatToString(white_val.getValue());
+
+	command += " --lowpass " + floatToString(lowpass.getValue());
+	command += " --angpix " + floatToString(angpix);
+
+	command += " --ctf_scale " + floatToString(ctfscale.getValue());
+
+	command += " --particle_diameter " + floatToString(particle_diameter);
+
+	if (do_color.getValue())
+	{
+		command += " --color_label " + color_label.getValue();
+		command += " --blue " + floatToString(blue_value.getValue());
+		command += " --red " + floatToString(red_value.getValue());
+		if (fn_color.getValue().length() > 0)
+			command += " --color_star " + fn_color.getValue();
+	}
+
+	// Other arguments for extraction
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+
+	outputname = "run_manualpick";
+	prepareFinalCommand(outputname, commands, final_command);
+}
+
+AutopickJobWindow::AutopickJobWindow() : RelionJobWindow(3, HAS_MPI, HAS_NOT_THREAD)
+{
+
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+
+	fn_input_autopick.place(current_y, "Input micrographs for autopick:", "micrographs_ctf.star", "Input micrographs (*.{star,mrc})", "Input STAR file (with CTF information), or a unix-type wildcard with all micrographs in MRC format (in this case no CTFs can be used).");
+	autopick_rootname.place(current_y, "Autopick rootname:", "autopick", "Output coordinate files will end in rootname.star");
+
+	tab1->end();
+	tab2->begin();
+	tab2->label("References");
+	resetHeight();
+
+	//set up group
+	autopick_ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	autopick_ctf_group->end();
+
+	fn_refs_autopick.place(current_y, "References:", "", "Input references (*.{star,mrc,mrcs})", "Input STAR file or MRC (stack of) image(s) with the references to be used for picking. Note that the absolute greyscale needs to be correct, so only use images created by RELION itself, e.g. by 2D class averaging or projecting a RELION reconstruction.");
+
+	lowpass_autopick.place(current_y, "Lowpass filter references (A)", 20, 10, 100, 5, "Lowpass filter that will be applied to the references before template matching. Do NOT use very high-resolution templates to search your micrographs. The signal will be too weak at high resolution anyway, and you may find Einstein from noise....");
+
+	psi_sampling_autopick.place(current_y, "Angular sampling (deg)", 5, 1, 30, 1, "Angular sampling in degrees for exhaustive searches of the in-plane rotations for all references.");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	do_invert_refs.place(current_y, "References have inverted contrast?", true, "Set to Yes to indicate that the reference have inverted contrast with respect to the particles in the micrographs.");
+
+	do_ctf_autopick.place(current_y, "Are References CTF corrected?", true, "Set to Yes if the references were created with CTF-correction inside RELION. \n \n If set to Yes, the input micrographs can only be given as a STAR file, which should contain the CTF information for each micrograph.", autopick_ctf_group);
+
+	autopick_ctf_group->begin();
+
+	do_ignore_first_ctfpeak_autopick.place(current_y, "Ignore CTFs until first peak?", false,"Set this to Yes, only if this option was also used to generate the references.");
+
+	autopick_ctf_group->end();
+	do_ctf_autopick.cb_menu_i();
+
+	tab2->end();
+	tab3->begin();
+	tab3->label("autopicking");
+	resetHeight();
+
+	threshold_autopick.place(current_y, "Picking threshold:", 0.05, 0, 1., 0.01, "Use lower thresholds to pick more particles (and more junk probably)");
+
+	mindist_autopick.place(current_y, "Minimum inter-particle distance (A):", 100, 0, 1000, 20, "Particles closer together than this distance will be consider to be a single cluster. From each cluster, only one particle will be picked.");
+
+	current_y += STEPY/2;
+
+	do_write_fom_maps.place(current_y, "Write FOM maps?", false, "If set to Yes, intermediate probability maps will be written out, which (upon reading them back in) will speed up tremendously the optimization of the threshold and inter-particle distance parameters. However, with this option, one cannot run in parallel, as disc I/O is very heavy with this option set.");
+
+	do_read_fom_maps.place(current_y, "Read FOM maps?", false, "If written out previously, read the FOM maps back in and re-run the picking to quickly find the optimal threshold and inter-particle distance parameters");
+
+	tab3->end();
+
+	// read settings if hidden file exists
+	read(".gui_autopick.settings", is_continue);
+}
+
+void AutopickJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_autopick.settings", fh);
+
+	fn_input_autopick.writeValue(fh);
+	fn_refs_autopick.writeValue(fh);
+	autopick_rootname.writeValue(fh);
+	do_invert_refs.writeValue(fh);
+	do_ctf_autopick.writeValue(fh);
+	do_ignore_first_ctfpeak_autopick.writeValue(fh);
+	lowpass_autopick.writeValue(fh);
+	psi_sampling_autopick.writeValue(fh);
+	do_write_fom_maps.writeValue(fh);
+	do_read_fom_maps.writeValue(fh);
+	threshold_autopick.writeValue(fh);
+	mindist_autopick.writeValue(fh);
+
+	closeWriteFile(fh);
+}
+
+void AutopickJobWindow::read(std::string fn, bool &_is_continue)
+{
+
+	std::ifstream fh;
+	if (openReadFile(fn, fh))
+	{
+
+		fn_input_autopick.readValue(fh);
+		fn_refs_autopick.readValue(fh);
+		autopick_rootname.readValue(fh);
+		do_invert_refs.readValue(fh);
+		do_ctf_autopick.readValue(fh);
+		do_ignore_first_ctfpeak_autopick.readValue(fh);
+		lowpass_autopick.readValue(fh);
+		psi_sampling_autopick.readValue(fh);
+		do_write_fom_maps.readValue(fh);
+		do_read_fom_maps.readValue(fh);
+		threshold_autopick.readValue(fh);
+		mindist_autopick.readValue(fh);
+
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+
+void AutopickJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+	return;
+}
+
+void AutopickJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
+		std::string &final_command, double angpix, double particle_diameter)
+{
+	commands.clear();
+	std::string command;
+	if (nr_mpi.getValue() > 1)
+		command="`which relion_autopick_mpi`";
+	else
+		command="`which relion_autopick`";
+
+	command += " --i " + fn_input_autopick.getValue();
+	command += " --o " + autopick_rootname.getValue();
+	command += " --particle_diameter " + floatToString(particle_diameter);
+	command += " --angpix " + floatToString(angpix);
+	command += " --ref " + fn_refs_autopick.getValue();
+
+	if (do_invert_refs.getValue())
+		command += " --invert ";
+
+	if (do_ctf_autopick.getValue())
+	{
+		command += " --ctf ";
+		if (do_ignore_first_ctfpeak_autopick.getValue())
+			command += " --ctf_intact_first_peak ";
+	}
+	command += " --ang " + floatToString(psi_sampling_autopick.getValue());
+	command += " --lowpass " + floatToString(lowpass_autopick.getValue());
+
+	if (do_write_fom_maps.getValue())
+		command += " --write_fom_maps ";
+
+	if (do_read_fom_maps.getValue())
+		command += " --read_fom_maps ";
+
+	command += " --threshold " + floatToString(threshold_autopick.getValue());
+	command += " --min_distance " + floatToString(mindist_autopick.getValue());
+
+
+	// Other arguments
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+
+	outputname = autopick_rootname.getValue();
+
+	prepareFinalCommand(outputname, commands, final_command);
+
+}
+
+
+ExtractJobWindow::ExtractJobWindow() : RelionJobWindow(3, HAS_MPI, HAS_NOT_THREAD)
+{
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+
+	star_mics.place(current_y,"micrograph STAR file: ", "selected_micrographs_ctf.star", "Input STAR file (*.{star})", "Filename of the STAR file that contains all micrographs from which to extract particles.");
+	pick_suffix.place(current_y,"Coordinate-file suffix: ", "_autopick.star", "Suffix for all the particle coordinate files. The micrograph rootnames will be extracted from each line in the input micrograph STAR file by removing the (.mrc) extension. \
+Then the coordinate filenames are formed by the micrograph rootname + this suffix. For example, a suffix of _autopick.star yields a coordinate filename of mic001_autopick.star for micrograph mic001.mrc. Likewise, a .box suffix would yield mic001.box. \n \n \
+Possible formats for coordinate files are RELION-generated STAR files (.star), EMAN boxer (.box) or ASCII files (with any other extension), where each line has the X and Y coordinates of a particle, possibly preceded by a single-line non-numeric header.");
+	extract_rootname.place(current_y, "Extract rootname:", "particles", "Output rootname. All particle stacks will contain this rootname, and the final particles STAR file will be called this rootname plus a .star extension. This rootname should NOT contain a directory structure. \n \n Also, when extracting movie-particles, this rootname should be THE SAME ONE as the one you used to extract the average particles. \
+On disc, movie particles will be distinguished from the average particles by the movie rootname on the movie tab. If you change the extract rootname upon extration of the movies, then movie processing will NOT work! ");
+
+	tab1->end();
+	tab2->begin();
+	tab2->label("extract");
+	resetHeight();
+	extract_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	extract_group->end();
+
+	do_extract.place(current_y, "Extract particles from micrographs?", true, "If set to Yes, particles will be extracted from the micrographs using all selected coordinate files. \
+Niko Grigorieff's program CTFFIND3 will be used for this.", extract_group);
+
+	extract_group->begin();
+
+	extract_size.place(current_y,"Particle box size :", 128, 64, 512, 8, "Size of the extracted particles (in pixels). This should be an even number!");
+	do_invert.place(current_y, "Invert contrast?", false, "If set to Yes, the contrast in the particles will be inverted.");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	rescale_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	rescale_group->end();
+	do_rescale.place(current_y, "Rescale particles?", false, "If set to Yes, particles will be re-scaled. Note that the particle diameter below will be in the down-scaled images.", rescale_group);
+	rescale_group->begin();
+	rescale.place(current_y, "Re-scaled size (pixels): ", 128, 64, 512, 8, "The re-scaled value needs to be an even number");
+	rescale_group->end();
+	do_rescale.cb_menu_i();
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	norm_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	norm_group->end();
+	do_norm.place(current_y, "Normalize particles?", true, "If set to Yes, particles will be normalized in the way RELION prefers it.", norm_group);
+
+	norm_group->begin();
+	white_dust.place(current_y, "Stddev for white dust removal: ", -1, -1, 10, 0.1, "Remove very white pixels from the extracted particles. \
+Pixels values higher than this many times the image stddev will be replaced with values from a Gaussian distribution. \n \n Use negative value to switch off dust removal.");
+
+	black_dust.place(current_y, "Stddev for black dust removal: ", -1, -1, 10, 0.1, "Remove very black pixels from the extracted particles. \
+Pixels values higher than this many times the image stddev will be replaced with values from a Gaussian distribution. \n \n Use negative value to switch off dust removal.");
+	norm_group->end();
+	do_norm.cb_menu_i();
+
+	extract_group->end();
+	do_extract.cb_menu_i();
+
+	tab2->end();
+	tab3->begin();
+	tab3->label("movies");
+	resetHeight();
+	movie_extract_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	movie_extract_group->end();
+
+	do_movie_extract.place(current_y, "Extract from movies?", false, "If set to yes, then particles will be extracted from all frames of the MRC stacks that hold the movies.\n \
+The name of the MCR stacks should be the rootname of the micrographs + '_movierootname.mrcs', where the movierootname is given below.", movie_extract_group);
+
+	movie_extract_group->begin();
+
+	movie_rootname.place(current_y, "Rootname of movies files:", "movie", "rootname to relate each movie to the single-frame averaged micropgraph. With a rootname of 'movie', the movie for mic001.mrc should be called mic001_movie.mrcs");
+
+	first_movie_frame.place(current_y, "First movie frame to extract: ", 1, 1, 20, 1, "Extract from this movie frame onwards. The first frame is number 1.");
+
+	last_movie_frame.place(current_y, "Last movie frame to extract: ", 0, 0, 64, 1, "Extract until this movie frame. Zero means: extract all frames in the movie");
+
+	movie_extract_group->end();
+	do_movie_extract.cb_menu_i();
+
+	tab3->end();
+
+	// read settings if hidden file exists
+	read(".gui_extract.settings", is_continue);
+}
+
+
+void ExtractJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_extract.settings", fh);
+
+	// I/O
+	star_mics.writeValue(fh);
+	pick_suffix.writeValue(fh);
+	extract_rootname.writeValue(fh);
+
+	// extract
+	do_extract.writeValue(fh);
+	extract_size.writeValue(fh);
+	do_rescale.writeValue(fh);
+	rescale.writeValue(fh);
+	do_norm.writeValue(fh);
+	white_dust.writeValue(fh);
+	black_dust.writeValue(fh);
+	do_invert.writeValue(fh);
+
+	// movies
+	do_movie_extract.writeValue(fh);
+	movie_rootname.writeValue(fh);
+	first_movie_frame.writeValue(fh);
+	last_movie_frame.writeValue(fh);
+
+	closeWriteFile(fh);
+}
+void ExtractJobWindow::read(std::string fn, bool &_is_continue)
+{
+	std::ifstream fh;
+	// Only read things if the file exists
+	if (openReadFile(fn, fh))
+	{
+
+		// I/O
+		star_mics.readValue(fh);
+		pick_suffix.readValue(fh);
+		extract_rootname.readValue(fh);
+
+		// extract
+		do_extract.readValue(fh);
+		extract_size.readValue(fh);
+		do_rescale.readValue(fh);
+		rescale.readValue(fh);
+		do_norm.readValue(fh);
+		white_dust.readValue(fh);
+		black_dust.readValue(fh);
+		do_invert.readValue(fh);
+
+		// movies
+		do_movie_extract.readValue(fh);
+		movie_rootname.readValue(fh);
+		first_movie_frame.readValue(fh);
+		last_movie_frame.readValue(fh);
+
+
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+void ExtractJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+}
+
+void ExtractJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
+		double angpix, double particle_diameter)
+{
+	commands.clear();
+	std::string command;
+	if (nr_mpi.getValue() > 1)
+		command="`which relion_preprocess_mpi`";
+	else
+		command="`which relion_preprocess`";
+
+	command += " --o " + extract_rootname.getValue();
+	command += " --mic_star " + star_mics.getValue();
+	command += " --coord_suffix " + pick_suffix.getValue();
+
+	if (do_extract.getValue())
+	{
+		command += " --extract";
+		command += " --extract_size " + floatToString(extract_size.getValue());
+		if (do_movie_extract.getValue())
+		{
+			command += " --extract_movies";
+			command += " --movie_rootname " + movie_rootname.getValue();
+			command += " --first_movie_frame " + floatToString(first_movie_frame.getValue());
+			command += " --last_movie_frame " + floatToString(last_movie_frame.getValue());
+		}
+
+		// Operate stuff
+		double bg_radius;
+		bg_radius = (particle_diameter / (2. * angpix));
+		if (do_rescale.getValue())
+		{
+			command += " --scale " + floatToString(rescale.getValue());
+			bg_radius *= rescale.getValue() / extract_size.getValue();
+		}
+		// Get an integer number for the bg_radius
+		bg_radius = (int)(bg_radius);
+		if (do_norm.getValue())
+		{
+			command += " --norm --bg_radius " + floatToString(bg_radius);
+			command += " --white_dust " + floatToString(white_dust.getValue());
+			command += " --black_dust " + floatToString(black_dust.getValue());
+		}
+		if (do_invert.getValue())
+			command += " --invert_contrast ";
+
+	}
+
+	// Other arguments for extraction
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+	outputname = extract_rootname.getValue();
+	prepareFinalCommand(outputname, commands, final_command);
+}
+
+SortJobWindow::SortJobWindow() : RelionJobWindow(1, HAS_MPI, HAS_NOT_THREAD)
+{
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+	ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	ctf_group->end();
+
+	input_star.place(current_y, "Input particles to be sorted:", "", "Input particles(*.{star})", "This STAR file should contain in-plane rotations, in-plane translations and a class number that were obtained by alignment (class2D/class3D or auto3D) OR auto-picking. A column called rlnParticleSelectZScore will be added to this same STAR file with the sorting result. This column can then be used in the display programs to sort the particles on.");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	fn_refs.place(current_y, "References:", "", "Input references (*.{star,mrc,mrcs})", "Input STAR file or MRC (stack of) image(s) with the references to be used for sorting. These should be the same references as used to determine the class number and in-plane orientations as given in the STAR file with the input particles");
+	do_ctf.place(current_y, "Are References CTF corrected?", true, "Set to Yes if the references were created with CTF-correction inside RELION. \n ", ctf_group);
+
+	ctf_group->begin();
+	do_ignore_first_ctfpeak.place(current_y, "Ignore CTFs until first peak?", false,"Set this to Yes, only if this option was also used to generate the references.");
+	ctf_group->end();
+	do_ctf.cb_menu_i();
+
+
+	tab1->end();
+
+	// read settings if hidden file exists
+	read(".gui_sort.settings", is_continue);
+}
+
+void SortJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_sort.settings", fh);
+
+	input_star.writeValue(fh);
+	fn_refs.writeValue(fh);
+	do_ctf.writeValue(fh);
+	do_ignore_first_ctfpeak.writeValue(fh);
+
+	closeWriteFile(fh);
+}
+void SortJobWindow::read(std::string fn, bool &_is_continue)
+{
+	std::ifstream fh;
+	// Only read things if the file exists
+	if (openReadFile(fn, fh))
+	{
+		input_star.readValue(fh);
+		fn_refs.readValue(fh);
+		do_ctf.readValue(fh);
+		do_ignore_first_ctfpeak.readValue(fh);
+
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+void SortJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+}
+
+void SortJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
+		std::string &final_command, double angpix, double particle_diameter)
+{
+	commands.clear();
+	std::string command;
+	if (nr_mpi.getValue() > 1)
+		command="`which relion_particle_sort_mpi`";
+	else
+		command="`which relion_particle_sort`";
+
+	command += " --i " + input_star.getValue();
+	command += " --ref " + fn_refs.getValue();
+	command += " --angpix " + floatToString(angpix);
+	command += " --particle_diameter " + floatToString(particle_diameter);
+
+	if (do_ctf.getValue())
+	{
+		command += " --ctf ";
+		if (do_ignore_first_ctfpeak.getValue())
+			command += " --ctf_intact_first_peak ";
+	}
+
+	// Other arguments for extraction
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+
+
+	int last_slash = input_star.getValue().rfind("/");
+	if (last_slash < input_star.getValue().size())
+	{
+		// The output name contains a directory: use that one for output
+		outputname = input_star.getValue().substr(0, last_slash + 1) + "run_sort";
+	}
+	else
+	{
+		outputname = "run_sort";
+	}
+
+	prepareFinalCommand(outputname, commands, final_command);
+}
+
+
+
+
+Class2DJobWindow::Class2DJobWindow() : RelionJobWindow(4, HAS_MPI, HAS_THREAD)
+{
+
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+
+	fn_img.place(current_y, "Input images STAR file:", "", "STAR files (*.star) \t Image stacks (not recommended, read help!) (*.{spi,mrcs})", "A STAR file with all images (and their metadata). \n \n Alternatively, you may give a Spider/MRC stack of 2D images, but in that case NO metadata can be included and thus NO CTF correction can be performed, \
+nor will it be possible to perform noise spectra estimation or intensity scale corrections in image groups. Therefore, running RELION with an input stack will in general provide sub-optimal results and is therefore not recommended!! Use the Preprocessing procedure to get the input STAR file in a semi-automated manner. Read the RELION wiki for more information.");
+
+	fn_out.place(current_y, "Output rootname:", "Class2D/run1", "Output rootname for all files of this run. \
+If this rootname contains a directory structure (e.g. 20110724/run1), the directory (20110724) will be created if it does not exist.");
+
+	fn_cont.place(current_y, "Continue from here: ", "", "STAR Files (*_optimiser.star)", "Select the *_optimiser.star file for the iteration \
+from which you want to continue a previous run. \
+Note that the Output rootname of the continued run and the rootname of the previous run cannot be the same. \
+If they are the same, the program will automatically add a '_ctX' to the output rootname, \
+with X being the iteration from which one continues the previous run.");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	nr_classes.place(current_y, "Number of classes:", 1, 1, 50, 1, "The number of classes (K) for a multi-reference refinement. \
+These classes will be made in an unsupervised manner from a single reference by division of the data into random subsets during the first iteration.");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+
+
+
+	tab1->end();
+
+	tab2->begin();
+	tab2->label("CTF");
+
+	ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	ctf_group->end();
+
+	resetHeight();
+	do_ctf_correction.place(current_y, "Do CTF-correction?", true, "If set to Yes, CTFs will be corrected inside the MAP refinement. \
+The resulting algorithm intrinsically implements the optimal linear, or Wiener filter. \
+Note that CTF parameters for all images need to be given in the input STAR file. \
+The command 'relion_refine --print_metadata_labels' will print a list of all possible metadata labels for that STAR file. \
+See the RELION Wiki for more details.\n\n Also make sure that the correct pixel size (in Angstrom) is given above!)", ctf_group);
+
+	ctf_group->begin();
+
+	ctf_phase_flipped.place(current_y, "Have data been phase-flipped?", false, "Set this to Yes if the images have been \
+ctf-phase corrected during the pre-processing steps. \
+Note that CTF-phase flipping is NOT a necessary pre-processing step for MAP-refinement in RELION, \
+as this can be done inside the internal CTF-correction. \
+However, if the phases have been flipped, you should tell the program about it by setting this option to Yes.");
+
+	ctf_intact_first_peak.place(current_y, "Ignore CTFs until first peak?", false, "If set to Yes, then CTF-amplitude correction will \
+only be performed from the first peak of each CTF onward. This can be useful if the CTF model is inadequate at the lowest resolution. \
+Still, in general using higher amplitude contrast on the CTFs (e.g. 10-20%) often yields better results. \
+Therefore, this option is not generally recommended: try increasing amplitude contrast (in your input STAR file) first!");
+
+	ctf_group->end();
+
+	do_ctf_correction.cb_menu_i(); // To make default effective
+
+	tab2->end();
+
+	tab3->begin();
+	tab3->label("Optimisation");
+	resetHeight();
+
+	nr_iter.place(current_y, "Number of iterations:", 25, 1, 50, 1, "Number of iterations to be performed. \
+Note that the current implementation of 2D class averaging and 3D classification does NOT comprise a convergence criterium. \
+Therefore, the calculations will need to be stopped by the user if further iterations do not yield improvements in resolution or classes. \n\n \
+Also note that upon restarting, the iteration number continues to be increased, starting from the final iteration in the previous run. \
+The number given here is the TOTAL number of iterations. For example, if 10 iterations have been performed previously and one restarts to perform \
+an additional 5 iterations (for example with a finer angular sampling), then the number given here should be 10+5=15.");
+
+	tau_fudge.place(current_y, "Regularisation parameter T:", 2 , 0.1, 10, 0.1, "Bayes law strictly determines the relative weight between \
+the contribution of the experimental data and the prior. However, in practice one may need to adjust this weight to put slightly more weight on \
+the experimental data to allow optimal results. Values greater than 1 for this regularisation parameter (T in the JMB2011 paper) put more \
+weight on the experimental data. Values around 2-4 have been observed to be useful for 3D refinements, values of 1-2 for 2D refinements. \
+Too small values yield too-low resolution structures; too high values result in over-estimated resolutions, mostly notable by the apparition of high-frequency noise in the references.");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	do_zero_mask.place(current_y, "Mask individual particles with zeros?", true, "If set to Yes, then in the individual particles, \
+the area outside a circle with the radius of the particle will be set to zeros prior to taking the Fourier transform. \
+This will remove noise and therefore increase sensitivity in the alignment and classification. However, it will also introduce correlations \
+between the Fourier components that are not modelled. When set to No, then the solvent area is filled with random noise, which prevents introducing correlations.\
+High-resolution refinements (e.g. ribosomes or other large complexes in 3D auto-refine) tend to work better when filling the solvent area with random noise (i.e. setting this option to No), refinements of smaller complexes and most classifications go better when using zeros (i.e. setting this option to Yes).");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	highres_limit.place(current_y, "Limit resolution E-step to (A): ", -1, -1, 20, 1, "If set to a positive number, then the expectation step (i.e. the alignment) will be done only including the Fourier components up to this resolution (in Angstroms). \
+This is useful to prevent overfitting, as the classification runs in RELION are not to be guaranteed to be 100% overfitting-free (unlike the 3D auto-refine with its gold-standard FSC). In particular for very difficult data sets, e.g. of very small or featureless particles, this has been shown to give much better class averages. \
+In such cases, values in the range of 7-12 Angstroms have proven useful.");
+
+	tab3->end();
+
+	tab4->begin();
+	tab4->label("Sampling");
+
+	//set up groups
+	dont_skip_align_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	dont_skip_align_group->end();
+
+	resetHeight();
+
+	dont_skip_align.place(current_y, "Perform image alignment?", true, "If set to No, then rather than \
+performing both alignment and classification, only classification will be performed. This allows the use of very focused masks.\
+This requires that the optimal orientations of all particles are already stored in the input STAR file. ", dont_skip_align_group);
+	dont_skip_align_group->begin();
+
+	psi_sampling.place(current_y, "In-plane angular sampling:", 5., 0.5, 20, 0.5, "The sampling rate for the in-plane rotation angle (psi) in degrees. \
+Using fine values will slow down the program. Recommended value for most 2D refinements: 5 degrees.\n\n \
+If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
+
+
+	offset_range.place(current_y, "Offset search range (pix):", 5, 0, 30, 1, "Probabilities will be calculated only for translations \
+in a circle with this radius (in pixels). The center of this circle changes at every iteration and is placed at the optimal translation \
+for each image in the previous iteration.\n\n \
+If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
+
+	offset_step.place(current_y, "Offset search step (pix):", 1, 0.1, 5, 0.1, "Translations will be sampled with this step-size (in pixels).\
+Translational sampling is also done using the adaptive approach. \
+Therefore, if adaptive=1, the translations will first be evaluated on a 2x coarser grid.\n\n \
+If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
+
+	dont_skip_align_group->end();
+	dont_skip_align.cb_menu_i(); // to make default effective
+
+	tab4->end();
+
+	// read settings if hidden file exists
+	read(".gui_class2d.settings", is_continue);
+
+}
+
+void Class2DJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_class2d.settings", fh);
+
+	// I/O
+	fn_out.writeValue(fh);
+	fn_cont.writeValue(fh);
+	fn_img.writeValue(fh);
+	nr_classes.writeValue(fh);
+
+	// CTF
+	do_ctf_correction.writeValue(fh);
+	ctf_phase_flipped.writeValue(fh);
+	ctf_intact_first_peak.writeValue(fh);
+
+	// Optimisation
+	nr_iter.writeValue(fh);
+	tau_fudge.writeValue(fh);
+	do_zero_mask.writeValue(fh);
+	highres_limit.writeValue(fh);
+
+	// Sampling
+	dont_skip_align.writeValue(fh);
+	psi_sampling.writeValue(fh);
+	offset_range.writeValue(fh);
+	offset_step.writeValue(fh);
+
+	closeWriteFile(fh);
+}
+
+void Class2DJobWindow::read(std::string fn, bool &_is_continue)
+{
+
+	std::ifstream fh;
+	if (openReadFile(fn, fh))
+	{
+
+		// I/O
+		fn_out.readValue(fh);
+		fn_cont.readValue(fh);
+		fn_img.readValue(fh);
+		nr_classes.readValue(fh);
+
+		// CTF
+		do_ctf_correction.readValue(fh);
+		ctf_phase_flipped.readValue(fh);
+		ctf_intact_first_peak.readValue(fh);
+
+		// Optimisation
+		nr_iter.readValue(fh);
+		tau_fudge.readValue(fh);
+		do_zero_mask.readValue(fh);
+		highres_limit.readValue(fh);
+
+		// Sampling
+		dont_skip_align.readValue(fh);
+		psi_sampling.readValue(fh);
+		offset_range.readValue(fh);
+		offset_step.readValue(fh);
+
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+
+void Class2DJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+
+	fn_cont.deactivate(!is_continue);
+	fn_img.deactivate(is_continue);
+	nr_classes.deactivate(is_continue);
+	do_zero_mask.deactivate(is_continue);
+	do_ctf_correction.deactivate(is_continue);
+	ctf_phase_flipped.deactivate(is_continue);
+	ctf_intact_first_peak.deactivate(is_continue);
+
+}
+
+void Class2DJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
+		std::string &final_command, double angpix, double particle_diameter)
+{
+	commands.clear();
+	std::string command;
+
+	if (nr_mpi.getValue() > 1)
+		command="`which relion_refine_mpi`";
+	else
+		command="`which relion_refine`";
+
+	// I/O
+	// Save the real output name (could be with _ctX for continuation)
+	// This name will also be used for the stderr and stdout outputs and the submit script and gui settings filenames
+	outputname = fn_out.getValue();
+	if (is_continue)
+	{
+		int pos_it = fn_cont.getValue().rfind("_it");
+		int pos_op = fn_cont.getValue().rfind("_optimiser");
+		if (pos_it < 0 || pos_op < 0)
+			std::cerr << "Warning: invalid optimiser.star filename provided for continuation run: " << fn_cont.getValue() << std::endl;
+		int it = (int)textToFloat((fn_cont.getValue().substr(pos_it+3, 6)).c_str());
+		outputname += "_ct" + floatToString(it);
+	}
+	command += " --o " + outputname;
+	if (is_continue)
+	{
+		command += " --continue " + fn_cont.getValue();
+	}
+	else
+	{
+		command += " --i " + fn_img.getValue();
+		command += " --particle_diameter " + floatToString(particle_diameter);
+		command += " --angpix " + floatToString(angpix);
+	}
+
+	// CTF stuff
+	if (!is_continue)
+	{
+
+		if (do_ctf_correction.getValue())
+		{
+			command += " --ctf ";
+			if (ctf_phase_flipped.getValue())
+				command += " --ctf_phase_flipped ";
+			if (ctf_intact_first_peak.getValue())
+				command += " --ctf_intact_first_peak ";
+		}
+	}
+
+	// Optimisation
+	command += " --iter " + floatToString(nr_iter.getValue());
+	command += " --tau2_fudge " + floatToString(tau_fudge.getValue());
+	if (!is_continue)
+	{
+		command += " --K " + floatToString(nr_classes.getValue());
+		// Always flatten the solvent
+		command += " --flatten_solvent ";
+		if (do_zero_mask.getValue())
+			command += " --zero_mask ";
+		if (highres_limit.getValue() > 0)
+			command += " --strict_highres_exp " + floatToString(highres_limit.getValue());
+	}
+
+	// Sampling
+	int iover = 1;
+	command += " --oversampling " + floatToString((float)iover);
+
+	if (!dont_skip_align.getValue())
+	{
+		command += " --skip_align ";
+	}
+	else
+	{
+		// The sampling given in the GUI will be the oversampled one!
+		command += " --psi_step " + floatToString(psi_sampling.getValue() * pow(2., iover));
+		// Offset range
+		command += " --offset_range " + floatToString(offset_range.getValue());
+		// The sampling given in the GUI will be the oversampled one!
+		command += " --offset_step " + floatToString(offset_step.getValue() * pow(2., iover));
+	}
+
+	// Always do norm and scale correction
+	if (!is_continue)
+		command += " --norm --scale ";
+
+	// Running stuff
+	command += " --j " + floatToString(nr_threads.getValue());
+	if (!is_continue)
+		command += " --memory_per_thread " + floatToString(ram_per_thread.getValue());
+
+	// Other arguments
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+
+	prepareFinalCommand(outputname, commands, final_command);
+
+}
+
+
+
+Class3DJobWindow::Class3DJobWindow() : RelionJobWindow(5, HAS_MPI, HAS_THREAD)
+{
+
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+
+	fn_img.place(current_y, "Input images STAR file:", "", "STAR files (*.star) \t Image stacks (not recommended, read help!) (*.{spi,mrcs})", "A STAR file with all images (and their metadata). \n \n Alternatively, you may give a Spider/MRC stack of 2D images, but in that case NO metadata can be included and thus NO CTF correction can be performed, \
+nor will it be possible to perform noise spectra estimation or intensity scale corrections in image groups. Therefore, running RELION with an input stack will in general provide sub-optimal results and is therefore not recommended!! Use the Preprocessing procedure to get the input STAR file in a semi-automated manner. Read the RELION wiki for more information.");
+
+	fn_out.place(current_y, "Output rootname:", "Class3D/run1", "Output rootname for all files of this run. \
+If this rootname contains a directory structure (e.g. 20110724/run1), the directory (20110724) will be created if it does not exist.");
+
+	fn_cont.place(current_y, "Continue from here: ", "", "STAR Files (*_optimiser.star)", "Select the *_optimiser.star file for the iteration \
+from which you want to continue a previous run. \
+Note that the Output rootname of the continued run and the rootname of the previous run cannot be the same. \
+If they are the same, the program will automatically add a '_ctX' to the output rootname, \
+with X being the iteration from which one continues the previous run.");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	nr_classes.place(current_y, "Number of classes:", 1, 1, 50, 1, "The number of classes (K) for a multi-reference refinement. \
+These classes will be made in an unsupervised manner from a single reference by division of the data into random subsets during the first iteration.");
+
+	tab1->end();
+	tab2->begin();
+	tab2->label("Reference");
+	resetHeight();
+
+	fn_ref.place(current_y, "Reference map:", "", "Image Files (*.{spi,vol,mrc})", "A 3D map in MRC/Spider format. \
+	Make sure this map has the same dimensions and the same pixel size as your input images.");
+
+	ref_correct_greyscale.place(current_y, "Ref. map is on absolute greyscale?", false, "Probabilities are calculated based on a Gaussian noise model, \
+which contains a squared difference term between the reference and the experimental image. This has a consequence that the \
+reference needs to be on the same absolute intensity grey-scale as the experimental images. \
+RELION and XMIPP reconstruct maps at their absolute intensity grey-scale. \
+Other packages may perform internal normalisations of the reference density, which will result in incorrect grey-scales. \
+Therefore: if the map was reconstructed in RELION or in XMIPP, set this option to Yes, otherwise set it to No. \
+If set to No, RELION will use a (grey-scale invariant) cross-correlation criterion in the first iteration, \
+and prior to the second iteration the map will be filtered again using the initial low-pass filter. \
+This procedure is relatively quick and typically does not negatively affect the outcome of the subsequent MAP refinement. \
+Therefore, if in doubt it is recommended to set this option to No.");
+
+	ini_high.place(current_y, "Initial low-pass filter (A):", 60, 0, 200, 5, "It is recommended to strongly low-pass filter your initial reference map. \
+If it has not yet been low-pass filtered, it may be done internally using this option. \
+If set to 0, no low-pass filter will be applied to the initial reference(s).");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	sym_name.place(current_y, "Symmetry:", "C1", "If the molecule is asymmetric, \
+set Symmetry group to C1. Note their are multiple possibilities for icosahedral symmetry: \n \
+* I1: No-Crowther 222 (standard in Heymann, Chagoyen & Belnap, JSB, 151 (2005) 196–207) \n \
+* I2: Crowther 222 \n \
+* I3: 52-setting (as used in SPIDER?)\n \
+* I4: A different 52 setting \n \
+The command 'relion_refine --sym D2 --print_symmetry_ops' prints a list of all symmetry operators for symmetry group D2. \
+RELION uses XMIPP's libraries for symmetry operations. \
+Therefore, look at the XMIPP Wiki for more details:  http://xmipp.cnb.csic.es/twiki/bin/view/Xmipp/WebHome?topic=Symmetry");
+
+	tab2->end();
+	tab3->begin();
+	tab3->label("CTF");
+
+	ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	ctf_group->end();
+
+	resetHeight();
+	do_ctf_correction.place(current_y, "Do CTF-correction?", true, "If set to Yes, CTFs will be corrected inside the MAP refinement. \
+The resulting algorithm intrinsically implements the optimal linear, or Wiener filter. \
+Note that CTF parameters for all images need to be given in the input STAR file. \
+The command 'relion_refine --print_metadata_labels' will print a list of all possible metadata labels for that STAR file. \
+See the RELION Wiki for more details.\n\n Also make sure that the correct pixel size (in Angstrom) is given above!)", ctf_group);
+
+	ctf_group->begin();
+
+	ctf_corrected_ref.place(current_y, "Has reference been CTF-corrected?", false, "Set this option to Yes if the reference map \
+represents density that is unaffected by CTF phases and amplitudes, e.g. it was created using CTF correction (Wiener filtering) inside RELION or from a PDB. \n\n\
+If set to No, then in the first iteration, the Fourier transforms of the reference projections are not multiplied by the CTFs.");
+
+	ctf_phase_flipped.place(current_y, "Have data been phase-flipped?", false, "Set this to Yes if the images have been \
+ctf-phase corrected during the pre-processing steps. \
+Note that CTF-phase flipping is NOT a necessary pre-processing step for MAP-refinement in RELION, \
+as this can be done inside the internal CTF-correction. \
+However, if the phases have been flipped, you should tell the program about it by setting this option to Yes.");
+
+	ctf_intact_first_peak.place(current_y, "Ignore CTFs until first peak?", false, "If set to Yes, then CTF-amplitude correction will \
+only be performed from the first peak of each CTF onward. This can be useful if the CTF model is inadequate at the lowest resolution. \
+Still, in general using higher amplitude contrast on the CTFs (e.g. 10-20%) often yields better results. \
+Therefore, this option is not generally recommended: try increasing amplitude contrast (in your input STAR file) first!");
+
+	ctf_group->end();
+
+	do_ctf_correction.cb_menu_i(); // To make default effective
+
+	tab3->end();
+	tab4->begin();
+	tab4->label("Optimisation");
+	resetHeight();
+
+	nr_iter.place(current_y, "Number of iterations:", 25, 1, 50, 1, "Number of iterations to be performed. \
+Note that the current implementation of 2D class averaging and 3D classification does NOT comprise a convergence criterium. \
+Therefore, the calculations will need to be stopped by the user if further iterations do not yield improvements in resolution or classes. \n\n \
+Also note that upon restarting, the iteration number continues to be increased, starting from the final iteration in the previous run. \
+The number given here is the TOTAL number of iterations. For example, if 10 iterations have been performed previously and one restarts to perform \
+an additional 5 iterations (for example with a finer angular sampling), then the number given here should be 10+5=15.");
+
+	tau_fudge.place(current_y, "Regularisation parameter T:", 2 , 0.1, 10, 0.1, "Bayes law strictly determines the relative weight between \
+the contribution of the experimental data and the prior. However, in practice one may need to adjust this weight to put slightly more weight on \
+the experimental data to allow optimal results. Values greater than 1 for this regularisation parameter (T in the JMB2011 paper) put more \
+weight on the experimental data. Values around 2-4 have been observed to be useful for 3D refinements, values of 1-2 for 2D refinements. \
+Too small values yield too-low resolution structures; too high values result in over-estimated resolutions, mostly notable by the apparition of high-frequency noise in the references.");
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	do_zero_mask.place(current_y, "Mask individual particles with zeros?", true, "If set to Yes, then in the individual particles, \
+the area outside a circle with the radius of the particle will be set to zeros prior to taking the Fourier transform. \
+This will remove noise and therefore increase sensitivity in the alignment and classification. However, it will also introduce correlations \
+between the Fourier components that are not modelled. When set to No, then the solvent area is filled with random noise, which prevents introducing correlations.\
+High-resolution refinements (e.g. ribosomes or other large complexes in 3D auto-refine) tend to work better when filling the solvent area with random noise (i.e. setting this option to No), refinements of smaller complexes and most classifications go better when using zeros (i.e. setting this option to Yes).");
+
+	fn_mask.place(current_y, "Reference mask (optional):", "", "Image Files (*.{spi,vol,msk,mrc})", "\
+If no mask is provided, a soft spherical mask based on the particle diameter will be used.\n\
+\n\
+Otherwise, provide a Spider/mrc map containing a (soft) mask with the same \
+dimensions as the reference(s), and values between 0 and 1, with 1 being 100% protein and 0 being 100% solvent. \
+The reconstructed reference map will be multiplied by this mask.\n\
+\n\
+In some cases, for example for non-empty icosahedral viruses, it is also useful to use a second mask. For all white (value 1) pixels in this second mask \
+the corresponding pixels in the reconstructed map are set to the average value of these pixels. \
+Thereby, for example, the higher density inside the virion may be set to a constant. \
+Note that this second mask should have one-values inside the virion and zero-values in the capsid and the solvent areas. \
+To use a second mask, use the additional option --solvent_mask2, which may given in the Additional arguments line (in the Running tab).");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	highres_limit.place(current_y, "Limit resolution E-step to (A): ", -1, -1, 20, 1, "If set to a positive number, then the expectation step (i.e. the alignment) will be done only including the Fourier components up to this resolution (in Angstroms). \
+This is useful to prevent overfitting, as the classification runs in RELION are not to be guaranteed to be 100% overfitting-free (unlike the 3D auto-refine with its gold-standard FSC). In particular for very difficult data sets, e.g. of very small or featureless particles, this has been shown to give much better class averages. \
+In such cases, values in the range of 7-12 Angstroms have proven useful.");
+
+	tab4->end();
+
+	tab5->begin();
+	tab5->label("Sampling");
+
+	//set up groups
+	dont_skip_align_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	dont_skip_align_group->end();
+
+	resetHeight();
+
+	dont_skip_align.place(current_y, "Perform image alignment?", true, "If set to No, then rather than \
+performing both alignment and classification, only classification will be performed. This allows the use of very focused masks.\
+This requires that the optimal orientations of all particles are already stored in the input STAR file. ", dont_skip_align_group);
+	dont_skip_align_group->begin();
+
+	sampling.place(current_y, "Angular sampling interval:", sampling_options, &sampling_options[2], "There are only a few discrete \
+angular samplings possible because we use the HealPix library to generate the sampling of the first two Euler angles on the sphere. \
+The samplings are approximate numbers and vary slightly over the sphere.\n\n \
+If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
+
+	offset_range.place(current_y, "Offset search range (pix):", 5, 0, 30, 1, "Probabilities will be calculated only for translations \
+in a circle with this radius (in pixels). The center of this circle changes at every iteration and is placed at the optimal translation \
+for each image in the previous iteration.\n\n \
+If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
+
+	offset_step.place(current_y, "Offset search step (pix):", 1, 0.1, 5, 0.1, "Translations will be sampled with this step-size (in pixels).\
+Translational sampling is also done using the adaptive approach. \
+Therefore, if adaptive=1, the translations will first be evaluated on a 2x coarser grid.\n\n \
+If auto-sampling is used, this will be the value for the first iteration(s) only, and the sampling rate will be increased automatically after that.");
+
+	localsearch_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	localsearch_group->end();
+
+	do_local_ang_searches.place(current_y, "Perform local angular searches?", false, "If set to Yes, then rather than \
+performing exhaustive angular searches, local searches within the range given below will be performed. \
+A prior Gaussian distribution centered at the optimal orientation in the previous iteration and \
+with a stddev of 1/3 of the range given below will be enforced.", localsearch_group);
+	localsearch_group->begin();
+
+	sigma_angles.place(current_y, "Local angular search range:", 5., 0, 15, 0.1, "Local angular searches will be performed \
+within +/- the given amount (in degrees) from the optimal orientation in the previous iteration. \
+A Gaussian prior (also see previous option) will be applied, so that orientations closer to the optimal orientation \
+in the previous iteration will get higher weights than those further away.");
+
+	localsearch_group->end();
+	do_local_ang_searches.cb_menu_i(); // to make default effective
+
+	dont_skip_align_group->end();
+	dont_skip_align.cb_menu_i(); // to make default effective
+
+	tab5->end();
+
+	// read settings if hidden file exists
+	read(".gui_class3d.settings", is_continue);
+
+}
+
+void Class3DJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_class3d.settings", fh);
+
+	// I/O
+	fn_out.writeValue(fh);
+	fn_cont.writeValue(fh);
+	fn_img.writeValue(fh);
+	nr_classes.writeValue(fh);
+
+	// Reference
+	fn_ref.writeValue(fh);
+	ref_correct_greyscale.writeValue(fh);
+	ini_high.writeValue(fh);
+	sym_name.writeValue(fh);
+
+	// CTF
+	do_ctf_correction.writeValue(fh);
+	ctf_corrected_ref.writeValue(fh);
+	ctf_phase_flipped.writeValue(fh);
+	ctf_intact_first_peak.writeValue(fh);
+
+	// Optimisation
+	nr_iter.writeValue(fh);
+	tau_fudge.writeValue(fh);
+	do_zero_mask.writeValue(fh);
+	fn_mask.writeValue(fh);
+	highres_limit.writeValue(fh);
+
+	// Sampling
+	dont_skip_align.writeValue(fh);
+	sampling.writeValue(fh);
+	offset_range.writeValue(fh);
+	offset_step.writeValue(fh);
+	do_local_ang_searches.writeValue(fh);
+	sigma_angles.writeValue(fh);
+
+	closeWriteFile(fh);
+}
+
+void Class3DJobWindow::read(std::string fn, bool &_is_continue)
+{
+
+	std::ifstream fh;
+	if (openReadFile(fn, fh))
+	{
+
+		// I/O
+		fn_out.readValue(fh);
+		fn_cont.readValue(fh);
+		fn_img.readValue(fh);
+		nr_classes.readValue(fh);
+
+		// Reference
+		fn_ref.readValue(fh);
+		ref_correct_greyscale.readValue(fh);
+		ini_high.readValue(fh);
+		sym_name.readValue(fh);
+
+		// CTF
+		do_ctf_correction.readValue(fh);
+		ctf_corrected_ref.readValue(fh);
+		ctf_phase_flipped.readValue(fh);
+		ctf_intact_first_peak.readValue(fh);
+
+		// Optimisation
+		nr_iter.readValue(fh);
+		tau_fudge.readValue(fh);
+		do_zero_mask.readValue(fh);
+		fn_mask.readValue(fh);
+		highres_limit.readValue(fh);
+
+		// Sampling
+		dont_skip_align.readValue(fh);
+		sampling.readValue(fh);
+		offset_range.readValue(fh);
+		offset_step.readValue(fh);
+		do_local_ang_searches.readValue(fh);
+		sigma_angles.readValue(fh);
+
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+
+void Class3DJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+
+	fn_cont.deactivate(!is_continue);
+	fn_img.deactivate(is_continue);
+	nr_classes.deactivate(is_continue);
+
+	// Reference
+	fn_ref.deactivate(is_continue);
+	ref_correct_greyscale.deactivate(is_continue);
+	ini_high.deactivate(is_continue);
+	sym_name.deactivate(is_continue);
+
+	//CTF
+	do_ctf_correction.deactivate(is_continue);
+	ctf_corrected_ref.deactivate(is_continue);
+	ctf_phase_flipped.deactivate(is_continue);
+	ctf_intact_first_peak.deactivate(is_continue);
+
+	//Optimisation
+	do_zero_mask.deactivate(is_continue);
+
+	// Sampling
+
+
+}
+
+void Class3DJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
+		std::string &final_command, double angpix, double particle_diameter)
+{
+	commands.clear();
+	std::string command;
+
+	if (nr_mpi.getValue() > 1)
+		command="`which relion_refine_mpi`";
+	else
+		command="`which relion_refine`";
+
+	// I/O
+	// Save the real output name (could be with _ctX for continuation)
+	// This name will also be used for the stderr and stdout outputs and the submit script and gui settings filenames
+	outputname = fn_out.getValue();
+	if (is_continue)
+	{
+		int pos_it = fn_cont.getValue().rfind("_it");
+		int pos_op = fn_cont.getValue().rfind("_optimiser");
+		if (pos_it < 0 || pos_op < 0)
+			std::cerr << "Warning: invalid optimiser.star filename provided for continuation run: " << fn_cont.getValue() << std::endl;
+		int it = (int)textToFloat((fn_cont.getValue().substr(pos_it+3, 6)).c_str());
+		outputname += "_ct" + floatToString(it);
+	}
+	command += " --o " + outputname;
+	if (is_continue)
+	{
+		command += " --continue " + fn_cont.getValue();
+	}
+	else
+	{
+		command += " --i " + fn_img.getValue();
+		command += " --particle_diameter " + floatToString(particle_diameter);
+		command += " --angpix " + floatToString(angpix);
+		if (fn_ref.getValue() != "None")
+			command += " --ref " + fn_ref.getValue();
+		if (!ref_correct_greyscale.getValue() && fn_ref.getValue() != "None") // dont do firstiter_cc when giving None
+			command += " --firstiter_cc";
+		if (ini_high.getValue() > 0.)
+			command += " --ini_high " + floatToString(ini_high.getValue());
+
+	}
+
+	// CTF stuff
+	if (!is_continue)
+	{
+
+		if (do_ctf_correction.getValue())
+		{
+			command += " --ctf";
+			if (ctf_corrected_ref.getValue())
+				command += " --ctf_corrected_ref";
+			if (ctf_phase_flipped.getValue())
+				command += " --ctf_phase_flipped";
+			if (ctf_intact_first_peak.getValue())
+				command += " --ctf_intact_first_peak";
+		}
+	}
+
+	// Optimisation
+	command += " --iter " + floatToString(nr_iter.getValue());
+	command += " --tau2_fudge " + floatToString(tau_fudge.getValue());
+	if (!is_continue)
+	{
+		command += " --K " + floatToString(nr_classes.getValue());
+		// Always flatten the solvent
+		command += " --flatten_solvent";
+		if (do_zero_mask.getValue())
+			command += " --zero_mask";
+		if (highres_limit.getValue() > 0)
+			command += " --strict_highres_exp " + floatToString(highres_limit.getValue());
+	}
+	if (fn_mask.getValue().length() > 0)
+		command += " --solvent_mask " + fn_mask.getValue();
+
+	// Sampling
+	int iover = 1;
+	command += " --oversampling " + floatToString((float)iover);
+
+	if (!dont_skip_align.getValue())
+	{
+		command += " --skip_align ";
+	}
+	else
+	{
+		for (int i = 0; i < 10; i++)
+		{
+			if (strcmp((sampling.getValue()).c_str(), sampling_options[i].label()) == 0)
+			{
+				// The sampling given in the GUI will be the oversampled one!
+				command += " --healpix_order " + floatToString((float)i + 1 - iover);
+				break;
+			}
+		}
+		// Manually input local angular searches
+		if (do_local_ang_searches.getValue())
+			command += " --sigma_ang " + floatToString(sigma_angles.getValue() / 3.);
+
+		// Offset range
+		command += " --offset_range " + floatToString(offset_range.getValue());
+		// The sampling given in the GUI will be the oversampled one!
+		command += " --offset_step " + floatToString(offset_step.getValue() * pow(2., iover));
+	}
+
+	// Provide symmetry, and always do norm and scale correction
+	if (!is_continue)
+	{
+		command += " --sym " + sym_name.getValue();
+		command += " --norm --scale ";
+	}
+
+	// Running stuff
+	command += " --j " + floatToString(nr_threads.getValue());
+	if (!is_continue)
+		command += " --memory_per_thread " + floatToString(ram_per_thread.getValue());
+
+	// Other arguments
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+
+	prepareFinalCommand(outputname, commands, final_command);
+
+}
+
+
+Auto3DJobWindow::Auto3DJobWindow() : RelionJobWindow(6, HAS_MPI, HAS_THREAD)
+{
+
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+
+	fn_img.place(current_y, "Input images STAR file:", "", "STAR files (*.star) \t Image stacks (not recommended, read help!) (*.{spi,mrcs})", "A STAR file with all images (and their metadata). \n \n Alternatively, you may give a Spider/MRC stack of 2D images, but in that case NO metadata can be included and thus NO CTF correction can be performed, \
+nor will it be possible to perform noise spectra estimation or intensity scale corrections in image groups. Therefore, running RELION with an input stack will in general provide sub-optimal results and is therefore not recommended!! Use the Preprocessing procedure to get the input STAR file in a semi-automated manner. Read the RELION wiki for more information.");
+
+	fn_out.place(current_y, "Output rootname:", "Refine3D/run1", "Output rootname for all files of this run. \
+If this rootname contains a directory structure (e.g. 20110724/run1), the directory (20110724) will be created if it does not exist.");
+
+	fn_cont.place(current_y, "Continue from here: ", "", "STAR Files (*_optimiser.star)", "Select the *_optimiser.star file for the iteration \
+from which you want to continue a previous run. \
+Note that the Output rootname of the continued run and the rootname of the previous run cannot be the same. \
+If they are the same, the program will automatically add a '_ctX' to the output rootname, \
+with X being the iteration from which one continues the previous run. \n \
+Besides restarting jobs that were somehow stopped before convergence, also use the continue-option after the last iteration to do movie processing.");
+
+	tab1->end();
+	tab2->begin();
+	tab2->label("Reference");
+	resetHeight();
+
+	fn_ref.place(current_y, "Reference map:", "", "Image Files (*.{spi,vol,mrc})", "A 3D map in MRC/Spider format. \
+	Make sure this map has the same dimensions and the same pixel size as your input images.");
+
+	ref_correct_greyscale.place(current_y, "Ref. map is on absolute greyscale?", false, "Probabilities are calculated based on a Gaussian noise model, \
+which contains a squared difference term between the reference and the experimental image. This has a consequence that the \
+reference needs to be on the same absolute intensity grey-scale as the experimental images. \
+RELION and XMIPP reconstruct maps at their absolute intensity grey-scale. \
+Other packages may perform internal normalisations of the reference density, which will result in incorrect grey-scales. \
+Therefore: if the map was reconstructed in RELION or in XMIPP, set this option to Yes, otherwise set it to No. \
+If set to No, RELION will use a (grey-scale invariant) cross-correlation criterion in the first iteration, \
+and prior to the second iteration the map will be filtered again using the initial low-pass filter. \
+This procedure is relatively quick and typically does not negatively affect the outcome of the subsequent MAP refinement. \
+Therefore, if in doubt it is recommended to set this option to No.");
+
+	ini_high.place(current_y, "Initial low-pass filter (A):", 60, 0, 200, 5, "It is recommended to strongly low-pass filter your initial reference map. \
+If it has not yet been low-pass filtered, it may be done internally using this option. \
+If set to 0, no low-pass filter will be applied to the initial reference(s).");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+
+	sym_name.place(current_y, "Symmetry:", "C1", "If the molecule is asymmetric, \
+set Symmetry group to C1. Note their are multiple possibilities for icosahedral symmetry: \n \
+* I1: No-Crowther 222 (standard in Heymann, Chagoyen & Belnap, JSB, 151 (2005) 196–207) \n \
+* I2: Crowther 222 \n \
+* I3: 52-setting (as used in SPIDER?)\n \
+* I4: A different 52 setting \n \
+The command 'relion_refine --sym D2 --print_symmetry_ops' prints a list of all symmetry operators for symmetry group D2. \
+RELION uses XMIPP's libraries for symmetry operations. \
+Therefore, look at the XMIPP Wiki for more details:  http://xmipp.cnb.csic.es/twiki/bin/view/Xmipp/WebHome?topic=Symmetry");
+
+	tab2->end();
+	tab3->begin();
+	tab3->label("CTF");
+
+	ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	ctf_group->end();
+
+	resetHeight();
+	do_ctf_correction.place(current_y, "Do CTF-correction?", true, "If set to Yes, CTFs will be corrected inside the MAP refinement. \
+The resulting algorithm intrinsically implements the optimal linear, or Wiener filter. \
+Note that CTF parameters for all images need to be given in the input STAR file. \
+The command 'relion_refine --print_metadata_labels' will print a list of all possible metadata labels for that STAR file. \
+See the RELION Wiki for more details.\n\n Also make sure that the correct pixel size (in Angstrom) is given above!)", ctf_group);
+
+	ctf_group->begin();
+
+	ctf_corrected_ref.place(current_y, "Has reference been CTF-corrected?", false, "Set this option to Yes if the reference map \
+represents density that is unaffected by CTF phases and amplitudes, e.g. it was created using CTF correction (Wiener filtering) inside RELION or from a PDB. \n\n\
+If set to No, then in the first iteration, the Fourier transforms of the reference projections are not multiplied by the CTFs.");
+
+	ctf_phase_flipped.place(current_y, "Have data been phase-flipped?", false, "Set this to Yes if the images have been \
+ctf-phase corrected during the pre-processing steps. \
+Note that CTF-phase flipping is NOT a necessary pre-processing step for MAP-refinement in RELION, \
+as this can be done inside the internal CTF-correction. \
+However, if the phases have been flipped, you should tell the program about it by setting this option to Yes.");
+
+	ctf_intact_first_peak.place(current_y, "Ignore CTFs until first peak?", false, "If set to Yes, then CTF-amplitude correction will \
+only be performed from the first peak of each CTF onward. This can be useful if the CTF model is inadequate at the lowest resolution. \
+Still, in general using higher amplitude contrast on the CTFs (e.g. 10-20%) often yields better results. \
+Therefore, this option is not generally recommended: try increasing amplitude contrast (in your input STAR file) first!");
+
+	ctf_group->end();
+
+	do_ctf_correction.cb_menu_i(); // To make default effective
+
+	tab3->end();
+	tab4->begin();
+	tab4->label("Optimisation");
+	resetHeight();
+
+	do_zero_mask.place(current_y, "Mask individual particles with zeros?", true, "If set to Yes, then in the individual particles, \
+the area outside a circle with the radius of the particle will be set to zeros prior to taking the Fourier transform. \
+This will remove noise and therefore increase sensitivity in the alignment and classification. However, it will also introduce correlations \
+between the Fourier components that are not modelled. When set to No, then the solvent area is filled with random noise, which prevents introducing correlations.\
+High-resolution refinements (e.g. ribosomes or other large complexes in 3D auto-refine) tend to work better when filling the solvent area with random noise (i.e. setting this option to No), refinements of smaller complexes and most classifications go better when using zeros (i.e. setting this option to Yes).");
+
+	fn_mask.place(current_y, "Reference mask (optional):", "", "Image Files (*.{spi,vol,msk,mrc})", "\
+If no mask is provided, a soft spherical mask based on the particle diameter will be used.\n\
+\n\
+Otherwise, provide a Spider/mrc map containing a (soft) mask with the same \
+dimensions as the reference(s), and values between 0 and 1, with 1 being 100% protein and 0 being 100% solvent. \
+The reconstructed reference map will be multiplied by this mask.\n\
+\n\
+In some cases, for example for non-empty icosahedral viruses, it is also useful to use a second mask. For all white (value 1) pixels in this second mask \
+the corresponding pixels in the reconstructed map are set to the average value of these pixels. \
+Thereby, for example, the higher density inside the virion may be set to a constant. \
+Note that this second mask should have one-values inside the virion and zero-values in the capsid and the solvent areas. \
+To use a second mask, use the additional option --solvent_mask2, which may given in the Additional arguments line (in the Running tab).");
+
+
+	tab4->end();
+	tab5->begin();
+	tab5->label("Auto-sampling");
+	resetHeight();
+
+	autosample_text.place(current_y, "Note that initial sampling rates will be auto-incremented!");
+
+	sampling.place(current_y, "Initial angular sampling:", sampling_options, &sampling_options[2], "There are only a few discrete \
+angular samplings possible because we use the HealPix library to generate the sampling of the first two Euler angles on the sphere. \
+The samplings are approximate numbers and vary slightly over the sphere.\n\n \
+Note that this will only be the value for the first few iteration(s): the sampling rate will be increased automatically after that.");
+
+	offset_range.place(current_y, "Initial offset range (pix):", 5, 0, 30, 1, "Probabilities will be calculated only for translations \
+in a circle with this radius (in pixels). The center of this circle changes at every iteration and is placed at the optimal translation \
+for each image in the previous iteration.\n\n \
+Note that this will only be the value for the first few iteration(s): the sampling rate will be increased automatically after that.");
+
+	offset_step.place(current_y, "Initial offset step (pix):", 1, 0.1, 5, 0.1, "Translations will be sampled with this step-size (in pixels).\
+Translational sampling is also done using the adaptive approach. \
+Therefore, if adaptive=1, the translations will first be evaluated on a 2x coarser grid.\n\n \
+Note that this will only be the value for the first few iteration(s): the sampling rate will be increased automatically after that.");
+
+	// Add a little spacer
+	current_y += STEPY/2;
+
+	auto_local_sampling.place(current_y, "Local searches from auto-sampling:", sampling_options, &sampling_options[4], "In the automated procedure to \
+increase the angular samplings, local angular searches of -6/+6 times the sampling rate will be used from this angular sampling rate onwards. For most \
+lower-symmetric particles a value of 1.8 degrees will be sufficient. Perhaps icosahedral symmetries may benefit from a smaller value such as 0.9 degrees.");
+
+	tab5->end();
+	tab4->end();
+	tab6->begin();
+	tab6->label("Movies");
+	resetHeight();
+	movie_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	movie_group->end();
+
+	do_movies.place(current_y, "Realign movie frames?", false, "If set to Yes, then running averages of the individual frames of recorded movies will be aligned as independent particles.", movie_group);
+
+	movie_group->begin();
+
+	fn_movie_star.place(current_y, "Input movie frames STAR file:", "", "STAR Files (*.{star})", "Select the output STAR file from the preprocessing \
+procedure of the movie frames.");
+
+	movie_runavg_window.place(current_y, "Running average window:", 5, 1, 15, 1, "The individual movie frames will be averaged using a running \
+average window with the specified width. Use an odd number. The optimal value will depend on the SNR in the individual movie frames. For ribosomes, we used a value of 5, where \
+each movie frame integrated approximately 1 electron per squared Angstrom.");
+
+	movie_sigma_offset.place(current_y, "Stddev on the translations (pix):", 1., 0.5, 10, 0.5, "A Gaussian prior with the specified standard deviation \
+will be centered at the rotations determined for the corresponding particle where all movie-frames were averaged. For ribosomes, we used a value of 2 pixels");
+
+	alsorot_movie_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	alsorot_movie_group->end();
+
+	do_alsorot_movies.place(current_y, "Also include rotational searches?", false, "If set to Yes, then running averages of the individual frames of recorded movies will also be aligned rotationally. \n \
+If one wants to perform particle polishing, then rotational alignments of the movie frames is NOT necessary and will only take more computing time.", alsorot_movie_group);
+
+	alsorot_movie_group->begin();
+
+	movie_sigma_angles.place(current_y, "Stddev on the rotations (deg):", 1., 0.5, 10, 0.5, "A Gaussian prior with the specified standard deviation \
+will be centered at the rotations determined for the corresponding particle where all movie-frames were averaged. For ribosomes, we used a value of 1 degree");
+
+	alsorot_movie_group->end();
+	do_alsorot_movies.cb_menu_i(); // to make default effective
+
+	movie_group->end();
+	do_movies.cb_menu_i(); // to make default effective
+
+	tab6->end();
+	// read settings if hidden file exists
+	read(".gui_auto3d.settings", is_continue);
+
+}
+
+void Auto3DJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_auto3d.settings", fh);
+
+	// I/O
+	fn_out.writeValue(fh);
+	fn_cont.writeValue(fh);
+	fn_img.writeValue(fh);
+
+	// Reference
+	fn_ref.writeValue(fh);
+	ref_correct_greyscale.writeValue(fh);
+	ini_high.writeValue(fh);
+	sym_name.writeValue(fh);
+
+	// CTF
+	do_ctf_correction.writeValue(fh);
+	ctf_corrected_ref.writeValue(fh);
+	ctf_phase_flipped.writeValue(fh);
+	ctf_intact_first_peak.writeValue(fh);
+
+	// Optimisation
+	do_zero_mask.writeValue(fh);
+	fn_mask.writeValue(fh);
+
+	// Sampling
+	sampling.writeValue(fh);
+	offset_range.writeValue(fh);
+	offset_step.writeValue(fh);
+	auto_local_sampling.writeValue(fh);
+
+	// Movies
+	do_movies.writeValue(fh);
+	fn_movie_star.writeValue(fh);
+	movie_runavg_window.writeValue(fh);
+	movie_sigma_offset.writeValue(fh);
+	do_alsorot_movies.writeValue(fh);
+	movie_sigma_angles.writeValue(fh);
+
+	closeWriteFile(fh);
+}
+
+void Auto3DJobWindow::read(std::string fn, bool &_is_continue)
+{
+
+	std::ifstream fh;
+	if (openReadFile(fn, fh))
+	{
+
+		// I/O
+		fn_out.readValue(fh);
+		fn_cont.readValue(fh);
+		fn_img.readValue(fh);
+
+		// Reference
+		fn_ref.readValue(fh);
+		ref_correct_greyscale.readValue(fh);
+		ini_high.readValue(fh);
+		sym_name.readValue(fh);
+
+		// CTF
+		do_ctf_correction.readValue(fh);
+		ctf_corrected_ref.readValue(fh);
+		ctf_phase_flipped.readValue(fh);
+		ctf_intact_first_peak.readValue(fh);
+
+		// Optimisation
+		do_zero_mask.readValue(fh);
+		fn_mask.readValue(fh);
+
+		// Sampling
+		sampling.readValue(fh);
+		offset_range.readValue(fh);
+		offset_step.readValue(fh);
+		auto_local_sampling.readValue(fh);
+
+		// Movies
+		do_movies.readValue(fh);
+		fn_movie_star.readValue(fh);
+		movie_runavg_window.readValue(fh);
+		movie_sigma_offset.readValue(fh);
+		do_alsorot_movies.readValue(fh);
+		movie_sigma_angles.readValue(fh);
+
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+
+void Auto3DJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+
+	fn_cont.deactivate(!is_continue);
+	fn_img.deactivate(is_continue);
+
+	// Reference
+	fn_ref.deactivate(is_continue);
+	ref_correct_greyscale.deactivate(is_continue);
+	ini_high.deactivate(is_continue);
+	sym_name.deactivate(is_continue);
+
+	//CTF
+	do_ctf_correction.deactivate(is_continue);
+	ctf_corrected_ref.deactivate(is_continue);
+	ctf_phase_flipped.deactivate(is_continue);
+	ctf_intact_first_peak.deactivate(is_continue);
+
+	//Optimisation
+	do_zero_mask.deactivate(is_continue);
+
+	// Sampling
+	sampling.deactivate(is_continue);
+	offset_range.deactivate(is_continue);
+	offset_step.deactivate(is_continue);
+	auto_local_sampling.deactivate(is_continue);
+
+	// Movies
+	do_movies.deactivate(!is_continue);
+	fn_movie_star.deactivate(!is_continue);
+	movie_runavg_window.deactivate(!is_continue);
+	movie_sigma_offset.deactivate(!is_continue);
+	do_alsorot_movies.deactivate(!is_continue);
+	movie_sigma_angles.deactivate(!is_continue);
+
+
+}
+
+void Auto3DJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands,
+		std::string &final_command, double angpix, double particle_diameter)
+{
+	commands.clear();
+	std::string command;
+
+	if (nr_mpi.getValue() > 1)
+		command="`which relion_refine_mpi`";
+	else
+		command="`which relion_refine`";
+
+	// I/O
+	// Save the real output name (could be with _ctX for continuation)
+	// This name will also be used for the stderr and stdout outputs and the submit script and gui settings filenames
+	outputname = fn_out.getValue();
+	if (is_continue)
+	{
+		int pos_it = fn_cont.getValue().rfind("_it");
+		int pos_op = fn_cont.getValue().rfind("_optimiser");
+		if (pos_it < 0 || pos_op < 0)
+			std::cerr << "Warning: invalid optimiser.star filename provided for continuation run: " << fn_cont.getValue() << std::endl;
+		int it = (int)textToFloat((fn_cont.getValue().substr(pos_it+3, 6)).c_str());
+		outputname += "_ct" + floatToString(it);
+	}
+	command += " --o " + outputname;
+	if (is_continue)
+	{
+		command += " --continue " + fn_cont.getValue();
+	}
+	else
+	{
+		command += " --auto_refine --split_random_halves --i " + fn_img.getValue();
+		command += " --particle_diameter " + floatToString(particle_diameter);
+		command += " --angpix " + floatToString(angpix);
+		if (fn_ref.getValue() != "None")
+			command += " --ref " + fn_ref.getValue();
+		if (!ref_correct_greyscale.getValue() && fn_ref.getValue() != "None") // dont do firstiter_cc when giving None
+			command += " --firstiter_cc";
+		if (ini_high.getValue() > 0.)
+			command += " --ini_high " + floatToString(ini_high.getValue());
+
+	}
+
+	// CTF stuff
+	if (!is_continue)
+	{
+
+		if (do_ctf_correction.getValue())
+		{
+			command += " --ctf";
+			if (ctf_corrected_ref.getValue())
+				command += " --ctf_corrected_ref";
+			if (ctf_phase_flipped.getValue())
+				command += " --ctf_phase_flipped";
+			if (ctf_intact_first_peak.getValue())
+				command += " --ctf_intact_first_peak";
+		}
+	}
+
+	// Optimisation
+	if (!is_continue)
+	{
+		// Always flatten the solvent
+		command += " --flatten_solvent";
+		if (do_zero_mask.getValue())
+			command += " --zero_mask";
+	}
+	if (fn_mask.getValue().length() > 0)
+		command += " --solvent_mask " + fn_mask.getValue();
+
+	// Sampling
+	int iover = 1;
+	command += " --oversampling " + floatToString((float)iover);
+
+	for (int i = 0; i < 10; i++)
+	{
+		if (strcmp((sampling.getValue()).c_str(), sampling_options[i].label()) == 0)
+		{
+			// The sampling given in the GUI will be the oversampled one!
+			command += " --healpix_order " + floatToString((float)i + 1 - iover);
+			break;
+		}
+
+	}
+	// Minimum sampling rate to perform local searches (may be changed upon continuation
+	for (int i = 0; i < 10; i++)
+	{
+		if (strcmp((auto_local_sampling.getValue()).c_str(), sampling_options[i].label()) == 0)
+		{
+			command += " --auto_local_healpix_order " + floatToString((float)i + 1 - iover);
+			break;
+		}
+	}
+
+	// Offset range
+	command += " --offset_range " + floatToString(offset_range.getValue());
+	// The sampling given in the GUI will be the oversampled one!
+	command += " --offset_step " + floatToString(offset_step.getValue() * pow(2., iover));
+
+	// Provide symmetry, and always do norm and scale correction
+	if (!is_continue)
+	{
+
+		command += " --sym " + sym_name.getValue();
+                // Always join low-res data, as some D&I point group refinements may fall into different hands!
+                command += " --low_resol_join_halves 40";
+		command += " --norm --scale ";
+	}
+
+	// Movies
+	if (is_continue && do_movies.getValue())
+	{
+		command += " --realign_movie_frames " + fn_movie_star.getValue();
+		command += " --movie_frames_running_avg " + floatToString(movie_runavg_window.getValue());
+		command += " --sigma_off " + floatToString(movie_sigma_offset.getValue());
+
+		if (do_alsorot_movies.getValue())
+		{
+			command += " --sigma_ang " + floatToString(movie_sigma_angles.getValue());
+		}
+		else
+		{
+			command += " --skip_rotate --skip_maximize ";
+		}
+	}
+
+	// Running stuff
+	command += " --j " + floatToString(nr_threads.getValue());
+	if (!is_continue)
+		command += " --memory_per_thread " + floatToString(ram_per_thread.getValue());
+
+	// Other arguments
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+
+	prepareFinalCommand(outputname, commands, final_command);
+
+}
+
+PostJobWindow::PostJobWindow() : RelionJobWindow(4, HAS_NOT_MPI, HAS_NOT_THREAD)
+{
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+	fn_in.place(current_y, "One of the 2 unfiltered half-maps:", "", "MRC map files (*_unfil.mrc)",  "Provide one of the two unfiltered half-reconstructions that were output upon convergence of a 3D auto-refine run.");
+
+	fn_out.place(current_y, "Output rootname", "postprocess", "Output rootname. All output files will be saved in the same directory as the unfiltered maps, unless the output name contains a forward slash. In that case, the corresponding directory will be created .");
+
+	//ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	//ctf_group->end();
+
+	tab1->end();
+	tab2->begin();
+	tab2->label("Mask");
+	resetHeight();
+	automask_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	automask_group->end();
+
+	do_automask.place(current_y, "Perform auto-masking?", true, "If set to Yes, the program will automatically calculate a mask around the reconstructed particle. \
+ A nicely fitting mask will result in an optimal resolution-estimation, as a maximal amount of noise will be removed from the resolution-estimation process. \
+The effect of the masking on the FSC-curve will be measured using the randomised phase-approach as in Shaoxia Chen et al, (2013) Ultramicroscopy", automask_group);
+
+	automask_group->begin();
+
+	inimask_threshold.place(current_y, "Initial binarisation threshold:", 0.02, 0., 0.5, 0.01, "This threshold is used to make an initial binary mask from the average of the two unfiltered half-reconstructions. \
+If you don't know what value to use, display one of the unfiltered half-maps in a 3D surface rendering viewer and find the lowest threshold that gives no noise peaks outside the reconstruction.");
+	extend_inimask.place(current_y, "Extend binary map this many pixels:", 3, 0, 20, 1, "The initial binary mask is extended this number of pixels in all directions." );
+	width_mask_edge.place(current_y, "Add a soft-edge of this many pixels:", 3, 0, 20, 1, "The extended binary mask is further extended with a raised-cosine soft edge of the specified width." );
+	automask_group->end();
+	do_automask.cb_menu_i();
+
+	usermask_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	usermask_group->end();
+
+	do_usermask.place(current_y, "Provide your own mask?", false, "If set to Yes, the program will mask the unfiltered half-reconstructions using a user-provided mask below. This also allows you to save execution time, by providing a previously determined automask for the same particle.", usermask_group);
+	usermask_group->begin();
+	fn_mask.place(current_y, "User-provided mask:", "", "Image Files (*.{spi,vol,msk,mrc})", "Use this to skip auto-masking by providing your own mask. You may also save execution time by providing a previously determined automask for the same particle.");
+	usermask_group->end();
+	do_usermask.cb_menu_i();
+
+	tab2->end();
+	tab3->begin();
+	tab3->label("Sharpen");
+	resetHeight();
+	//ctf_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	//ctf_group->end();
+
+	fn_mtf.place(current_y, "MTF of the detector (STAR file)", "", "STAR Files (*.star)", "The MTF of the detector is used in the (later) post-processing and particle polishing stages of refinement.  \
+If you know the MTF of your detector, provide it here. Curves for some well-known detectors may be downloaded from the RELION Wiki. Also see there for the exact format \
+\n If you do not know the MTF of your detector and do not want to measure it, then by leaving this entry empty, you include the MTF of your detector in your overall estimated B-factor upon sharpening the map.\
+Although that is probably slightly less accurate, the overall quality of your map will probably not suffer very much.");
+
+	current_y += STEPY/2;
+
+	autobfac_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	autobfac_group->end();
+	do_auto_bfac.place(current_y,"Estimate B-factor automatically?", true, "If set to Yes, then the program will use the automated procedure described by Rosenthal and Henderson (2003, JMB) to estimate an overall B-factor for your map, and sharpen it accordingly. \
+Note that your map must extend well beyond the lowest resolution included in the procedure below, which should not be set to resolutions much lower than 10 Angstroms. ", autobfac_group);
+
+	autobfac_group->begin();
+	autob_lowres.place(current_y,"Lowest resolution for auto-B fit (A):", 10, 8, 15, 0.5, "This is the lowest frequency (in Angstroms) that will be included in the linear fit of the Guinier plot as described in Rosenthal and Henderson (2003, JMB). Dont use values much lower or higher than 10 Angstroms. If your map does not extend beyond 10 Angstroms, then instead of the automated procedure use your own B-factor.");
+	autobfac_group->end();
+	do_auto_bfac.cb_menu_i();
+
+	adhocbfac_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	adhocbfac_group->end();
+	do_adhoc_bfac.place(current_y,"Use your own B-factor?", false, "Instead of using the automated B-factor estimation, provide your own value. Use negative values for sharpening the map. \
+This option is useful if your map does not extend beyond the 10A needed for the automated procedure, or when the automated procedure does not give a suitable value (e.g. in more disordered parts of the map).",adhocbfac_group);
+
+	adhocbfac_group->begin();
+	adhoc_bfac.place(current_y,"User-provided B-factor:", -1000, -2000, 0, -50, "Use negative values for sharpening. Be careful: if you over-sharpen your map, you may end up interpreting noise for signal!");
+	adhocbfac_group->end();
+	do_adhoc_bfac.cb_menu_i();
+
+	tab3->end();
+	tab4->begin();
+	tab4->label("Filter");
+	resetHeight();
+	skipweight_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	skipweight_group->end();
+
+	do_skip_fsc_weighting.place(current_y, "Skip FSC-weighting?", false, "If set to No (the default), then the output map will be low-pass filtered according to the mask-corrected, gold-standard FSC-curve. \
+Sometimes, it is also useful to provide an ad-hoc low-pass filter (option below), as due to local resolution variations some parts of the map may be better and other parts may be worse than the overall resolution as measured by the FSC. \
+In such cases, set this option to Yes and provide an ad-hoc filter as described below.", skipweight_group);
+
+	skipweight_group->begin();
+	low_pass.place(current_y, "Ad-hoc low-pass filter (A):",5,1,40,1,"This option allows one to low-pass filter the map at a user-provided frequency (in Angstroms). When using a resolution that is higher than the gold-standard FSC-reported resolution, take care not to interpret noise in the map for signal...");
+	skipweight_group->end();
+	do_skip_fsc_weighting.cb_menu_i();
+
+	tab4->end();
+
+
+	// read settings if hidden file exists
+	read(".gui_post.settings", is_continue);
+}
+void PostJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_post.settings", fh);
+	fn_in.writeValue(fh);
+	fn_out.writeValue(fh);
+	do_automask.writeValue(fh);
+	inimask_threshold.writeValue(fh);
+	extend_inimask.writeValue(fh);
+	width_mask_edge.writeValue(fh);
+	do_usermask.writeValue(fh);
+	fn_mask.writeValue(fh);
+	do_auto_bfac.writeValue(fh);
+	autob_lowres.writeValue(fh);
+	do_adhoc_bfac.writeValue(fh);
+	adhoc_bfac.writeValue(fh);
+	fn_mtf.writeValue(fh);
+	do_skip_fsc_weighting.writeValue(fh);
+	low_pass.writeValue(fh);
+	closeWriteFile(fh);
+}
+void PostJobWindow::read(std::string fn, bool &_is_continue)
+{
+	std::ifstream fh;
+	// Only read things if the file exists
+	if (openReadFile(fn, fh))
+	{
+		fn_in.readValue(fh);
+		fn_out.readValue(fh);
+		do_automask.readValue(fh);
+		inimask_threshold.readValue(fh);
+		extend_inimask.readValue(fh);
+		width_mask_edge.readValue(fh);
+		do_usermask.readValue(fh);
+		fn_mask.readValue(fh);
+		do_auto_bfac.readValue(fh);
+		autob_lowres.readValue(fh);
+		do_adhoc_bfac.readValue(fh);
+		adhoc_bfac.readValue(fh);
+		fn_mtf.readValue(fh);
+		do_skip_fsc_weighting.readValue(fh);
+		low_pass.readValue(fh);
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+void PostJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+}
+void PostJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
+		double angpix)
+{
+	commands.clear();
+	std::string command;
+	command="`which relion_postprocess`";
+
+	// Get the input rootname from the half-map name
+	// run1_half1_class001_unfil.mrc -> run1
+	int pos_half = fn_in.getValue().rfind("_half");
+	if (pos_half < fn_in.getValue().size())
+		command += " --i " + fn_in.getValue().substr(0, pos_half);
+	else
+	{
+		std::cerr << "PostJobWindow::getCommands ERROR: cannot find _half substring in input filename: " << fn_in.getValue() << std::endl;
+		exit(1);
+	}
+
+	// Get the output name. If the specified fn_out contains a directory, then make this directory and use it for output
+	// If it doesn't contain a directory, then use the directory as in fn_in.
+	int last_slash_out = fn_out.getValue().rfind("/");
+	int last_slash_in = fn_in.getValue().rfind("/");
+	if (last_slash_out < fn_out.getValue().size())
+	{
+		// The output name contains a directory: use that one for output
+		outputname = fn_out.getValue();
+	}
+	else if  (last_slash_in < fn_in.getValue().size())
+	{
+		// Otherwise: the input name contains a directory: use that one for output
+		std::string dirs = fn_in.getValue().substr(0, last_slash_in + 1);
+		outputname = dirs + fn_out.getValue();
+	}
+	// The output name contains a directory: use it for output
+	command += " --o " + outputname;
+	command += "  --angpix " + floatToString(angpix);
+
+	// Masking
+	if (do_automask.getValue())
+	{
+		command += " --auto_mask ";
+		command += " --inimask_threshold " + floatToString(inimask_threshold.getValue());
+		command += " --extend_inimask " + floatToString(extend_inimask.getValue());
+		command += " --width_mask_edge " + floatToString(width_mask_edge.getValue());
+	}
+	if (do_usermask.getValue())
+		command += " --mask " + fn_mask.getValue();
+
+	// Sharpening
+	if (fn_mtf.getValue().length() > 0)
+	{
+		command += " --mtf " + fn_mtf.getValue();
+	}
+	if (do_auto_bfac.getValue())
+	{
+		command += " --auto_bfac ";
+		command += " --autob_lowres "  + floatToString(autob_lowres.getValue());
+	}
+	if (do_adhoc_bfac.getValue())
+	{
+		command += " --adhoc_bfac " + floatToString(adhoc_bfac.getValue());
+	}
+
+	// Filtering
+	if (do_skip_fsc_weighting.getValue())
+	{
+		command += " --skip_fsc_weighting ";
+		command += " --low_pass "  + floatToString(low_pass.getValue());
+	}
+
+	// Other arguments for extraction
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+	prepareFinalCommand(outputname, commands, final_command);
+}
+
+
+
+PolishJobWindow::PolishJobWindow() : RelionJobWindow(3, HAS_MPI, HAS_THREAD)
+{
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+
+	fn_in.place(current_y, "Input STAR file with aligned movies:", "", "STAR files (*_data.star)",  "Provide the data.star file that was output by the movie-processing option in the auto-refine job.");
+
+	fn_out.place(current_y, "Output rootname", "shiny", "Output rootname. Note that the program will write out ");
+
+	tab1->end();
+	tab2->begin();
+	tab2->label("Movement");
+	resetHeight();
+
+	fit_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	fit_group->end();
+
+
+	do_fit_movement.place(current_y, "Linear fit particle movements?", true, "If set to Yes, then the program will fit linear tracks (in X-Y and in time) through \
+the estimated movie tracks in the input STAR file. For small particles (e.g. < 1MDa) this will lead to more robust beam-induced movement modelling. Because particles that are close to each other on a \
+micrograph often move in similar directions, the estimated tracks from neighbouring particles may also be included in the fitting of each particle. Again, in particular for smaller particles \
+this may improve the robustness of the fits.", fit_group);
+
+	fit_group->begin();
+
+	movie_runavg_window.place(current_y, "Running average window:", 5, 1, 15, 1, "Provide the same value as the one that was used to estimate the movement tracks in the movie-processing tab of the auto-refine job.");
+
+	sigma_nb.place(current_y, "Stddev on particle distance (pix)", 100, 0, 1000, 50, "This value determines how much neighbouring particles contribute to the fit of the movements of each particle. \
+This value is the standard deviation of a Gaussian on the inter-particle distance. Larger values mean that particles that are further away still contribute more. Particles beyond 3 standard deviations are excluded \
+from the fit. Very large values will lead to all fitted tracks pointing in the same direction. A value of zero means that each particle is fitted independently.");
+	fit_group->end();
+	do_fit_movement.cb_menu_i();
+
+	tab2->end();
+	tab3->begin();
+	tab3->label("Damage");
+	resetHeight();
+
+	weight_group = new Fl_Group(WCOL0,  MENUHEIGHT, 550, 600-MENUHEIGHT, "");
+	weight_group->end();
+
+	do_bfactor_weighting.place(current_y, "Perform B-factor weighting?", true, "If set to Yes, then the program will estimate a resolution-dependent weight for each movie frames by calculating independent half-reconstructions for each movie frame separately. \
+Gold-standard FSCs between these are then converted into relative Guinier plots, through which straight lines are fitted. Linear fits are often suitable beyond 20A resolution. Small particles may not yield such high resolutions for the individual-frame reconstructions. \
+Therefore, in some cases it may be better to skip this step. It is however recommended to always try and perform B-factor weighting, and to inspect the output bfactors.star and guinier.star files, as adequate weighting may significantly improve resolution in the final map.", weight_group);
+
+	weight_group->begin();
+	perframe_highres.place(current_y, "Highres-limit per-frame maps (A)", 6, 1, 25, 1, "To estimate the resolution and dose dependency of the radiation damage, the program \
+will calculate reconstructions from all first movie frames, second movie frames, etc. These per-frame reconstructions will have lower resolution than the reconstruction from all-frames. \
+To speed up the calculations (and reduce memory requirements), the per-frame reconstructions may be limited in resolution using this parameter. One can inspect the output STAR files of the per-frame reconstructions \
+to check afterwards that this value was not chosen lower than the actual resolution of these reconstructions");
+
+	perframe_bfac_lowres.place(current_y, "Lowres-limit B-factor estimation (A)", 20 , 1, 40, 1, "This value describes the lowest resolution that is included in the B-factor estimation of the per-frame reconstructions. \
+Because the power spectrum of per-frame reconstructions is compared to the power spectrum of the reconstruction from all frames, a much lower value than the 10A described in the Rosenthal and Henderson (2003) paper in JMB can be used. Probably a value around 20A is still OK.");
+
+	weight_group->end();
+	do_bfactor_weighting.cb_menu_i();
+
+	current_y += STEPY/2;
+
+	fn_mask.place(current_y, "Mask for the reconstructions", "", "Image Files (*.{spi,vol,msk,mrc})", "A continuous mask with values between 0 (solvent) and 1 (protein). You may provide the same map that was obtained in the post-processing of the corresponding auto-refine jobs before the movie processing.");
+
+	sym_name.place(current_y, "Symmetry:", "C1", "If the molecule is asymmetric, \
+set Symmetry group to C1. Note their are multiple possibilities for icosahedral symmetry: \n \
+* I1: No-Crowther 222 (standard in Heymann, Chagoyen & Belnap, JSB, 151 (2005) 196–207) \n \
+* I2: Crowther 222 \n \
+* I3: 52-setting (as used in SPIDER?)\n \
+* I4: A different 52 setting \n \
+The command 'relion_refine --sym D2 --print_symmetry_ops' prints a list of all symmetry operators for symmetry group D2. \
+RELION uses XMIPP's libraries for symmetry operations. \
+Therefore, look at the XMIPP Wiki for more details:  http://xmipp.cnb.csic.es/twiki/bin/view/Xmipp/WebHome?topic=Symmetry");
+
+	tab3->end();
+	// read settings if hidden file exists
+	read(".gui_polish.settings", is_continue);
+}
+
+void PolishJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_polish.settings", fh);
+	fn_in.writeValue(fh);
+	fn_out.writeValue(fh);
+	movie_runavg_window.writeValue(fh);
+	do_fit_movement.writeValue(fh);
+	sigma_nb.writeValue(fh);
+	do_bfactor_weighting.writeValue(fh);
+	perframe_highres.writeValue(fh);
+	perframe_bfac_lowres.writeValue(fh);
+	fn_mask.writeValue(fh);
+	sym_name.writeValue(fh);
+
+	closeWriteFile(fh);
+}
+void PolishJobWindow::read(std::string fn, bool &_is_continue)
+{
+	std::ifstream fh;
+	// Only read things if the file exists
+	if (openReadFile(fn, fh))
+	{
+		fn_in.readValue(fh);
+		fn_out.readValue(fh);
+		movie_runavg_window.readValue(fh);
+		do_fit_movement.readValue(fh);
+		sigma_nb.readValue(fh);
+		do_bfactor_weighting.readValue(fh);
+		perframe_highres.readValue(fh);
+		perframe_bfac_lowres.readValue(fh);
+		fn_mask.readValue(fh);
+		sym_name.readValue(fh);
+
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+void PolishJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+}
+
+void PolishJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
+		double angpix, double particle_diameter, double black_dust, double white_dust)
+{
+	commands.clear();
+	std::string command;
+	if (nr_mpi.getValue() > 1)
+		command="`which relion_particle_polish_mpi`";
+	else
+		command="`which relion_particle_polish`";
+
+	// General
+	command += " --i " + fn_in.getValue();
+	command += " --o " + fn_out.getValue();
+	command += "  --angpix " + floatToString(angpix);
+	command += " --movie_frames_running_avg " + floatToString(movie_runavg_window.getValue());
+	// If this is not a continue job, then re-start from scratch....
+	if (!is_continue)
+		command += " --dont_read_old_files ";
+
+	// Beam-induced movement fitting options
+	if (do_fit_movement.getValue())
+		command += " --sigma_nb " + floatToString(sigma_nb.getValue());
+	else
+		command += " --no_fit ";
+
+	// Damage
+	if (do_bfactor_weighting.getValue())
+	{
+		command += " --perframe_highres " + floatToString(perframe_highres.getValue());
+		command += " --autob_lowres " + floatToString(perframe_bfac_lowres.getValue());
+	}
+	else
+	{
+		command += " --skip_bfactor_weighting ";
+	}
+
+	if (fn_mask.getValue().length() > 0)
+		command += " --mask " + fn_mask.getValue();
+
+	// Symmetry group
+	command += " --sym " + sym_name.getValue();
+
+	// Normalisation
+	double bg_rad = ROUND(particle_diameter / (2. * angpix));
+	command += " --bg_radius " + floatToString(bg_rad);
+	command += " --white_dust " + floatToString(white_dust);
+	command += " --black_dust " + floatToString(black_dust);
+
+	// Other arguments for extraction
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+
+	// Place the job submission script and the stdout and stderr files in the same directory as the input data.star
+
+	int last_slash = fn_in.getValue().rfind("/");
+	if (last_slash < fn_in.getValue().size())
+	{
+		std::string dirs = fn_in.getValue().substr(0, last_slash + 1); // +1 includes the slash
+		outputname = dirs + fn_out.getValue();
+	}
+	else
+	{
+		outputname = fn_out.getValue();
+	}
+	prepareFinalCommand(outputname, commands, final_command);
+}
+
+ResmapJobWindow::ResmapJobWindow() : RelionJobWindow(1, HAS_NOT_MPI, HAS_NOT_THREAD)
+{
+	tab1->begin();
+	tab1->label("I/O");
+	resetHeight();
+
+	fn_in.place(current_y, "One of the 2 unfiltered half-maps:", "", "MRC map files (*_unfil.mrc)",  "Provide one of the two unfiltered half-reconstructions that were output upon convergence of a 3D auto-refine run.");
+
+	current_y += STEPY /2 ;
+
+	pval.place(current_y, "P-value:", 0.05, 0., 1., 0.01, "This value is typically left at 0.05. If you change it, report the modified value in your paper!");
+	minres.place(current_y, "Highest resolution (A): ", 0., 0., 10., 0.1, "ResMaps minRes parameter. By default (0), the program will start at just above 2x the pixel size");
+	maxres.place(current_y, "Lowest resolution (A): ", 0., 0., 10., 0.1, "ResMaps maxRes parameter. By default (0), the program will stop at 4x the pixel size");
+	stepres.place(current_y, "Resolution step size (A)", 1., 0.1, 3, 0.1, "ResMaps stepSize parameter." );
+
+	current_y += STEPY /2 ;
+	fn_mask.place(current_y, "User-provided mask (optional):", "", "Image Files (*.{spi,vol,msk,mrc})", "A binary (!) mask with values 0 for solvent and 1 for protein. \
+Note that values larger than zero will be changed to 1 by ResMap, therefore the continuous masks from the postprocessing may be too wide. If left empty (default), then ResMap will determine its own mask");
+
+	current_y += STEPY /2 ;
+
+	// Check for environment variable RELION_RESMAP_TEMPLATE
+	char * default_location = getenv ("RELION_RESMAP_EXECUTABLE");
+	if (default_location == NULL)
+	{
+		char mydefault[] = DEFAULTRESMAPLOCATION;
+		default_location = mydefault;
+	}
+
+	fn_resmap.place(current_y, "ResMap executable:", default_location, "ResMap*", "Location of the ResMap executable. You can control the default of this field by setting environment variable RELION_RESMAP_EXECUTABLE, or by editing the first few lines in src/gui_jobwindow.h and recompile the code.");
+
+	tab1->end();
+
+	// read settings if hidden file exists
+	read(".gui_resmap.settings", is_continue);
+}
+
+void ResmapJobWindow::write(std::string fn)
+{
+	std::ofstream fh;
+	openWriteFile(fn + ".gui_resmap.settings", fh);
+	fn_resmap.writeValue(fh);
+	fn_in.writeValue(fh);
+	pval.writeValue(fh);
+	minres.writeValue(fh);
+	maxres.writeValue(fh);
+	stepres.writeValue(fh);
+	fn_mask.writeValue(fh);
+	closeWriteFile(fh);
+}
+
+void ResmapJobWindow::read(std::string fn, bool &_is_continue)
+{
+	std::ifstream fh;
+	// Only read things if the file exists
+	if (openReadFile(fn, fh))
+	{
+		fn_resmap.readValue(fh);
+		fn_in.readValue(fh);
+		pval.readValue(fh);
+		minres.readValue(fh);
+		maxres.readValue(fh);
+		stepres.readValue(fh);
+		fn_mask.readValue(fh);
+		closeReadFile(fh);
+		_is_continue = is_continue;
+	}
+}
+
+void ResmapJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+	// never submit this to queue, as ResMap needs user interaction
+	do_queue.deactivate(true);
+}
+
+void ResmapJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
+		double angpix)
+{
+	commands.clear();
+	std::string command;
+
+	if (fn_resmap.getValue().length() == 0)
+	{
+		std::cerr << "ResmapJobWindow::getCommands ERROR: please provide an executable for the ResMap program." << std::endl;
+		exit(1);
+	}
+
+	command = fn_resmap.getValue();
+
+	// Get the two half-reconstruction names from the single one
+	std::string fn_half1, fn_half2;
+	int pos_half = fn_in.getValue().rfind("_half");
+	if (pos_half < fn_in.getValue().size())
+	{
+		fn_half1 = fn_in.getValue().substr(0, pos_half) + "_half1_class001_unfil.mrc";
+		fn_half2 = fn_in.getValue().substr(0, pos_half) + "_half2_class001_unfil.mrc";
+	}
+	else
+	{
+		std::cerr << "ResMapJobWindow::getCommands ERROR: cannot find _half substring in input filename: " << fn_in.getValue() << std::endl;
+		exit(1);
+	}
+
+	command += " --vis2D --noguiSplit " + fn_half1 + " " + fn_half2;
+	command += " --vxSize=" + floatToString(angpix);
+	command += " --pVal=" + floatToString(pval.getValue());
+	command += " --minRes=" + floatToString(minres.getValue());
+	command += " --maxRes=" + floatToString(maxres.getValue());
+	command += " --stepRes=" + floatToString(stepres.getValue());
+	if (fn_mask.getValue().length() > 0)
+		command += " --maskVol=" + fn_mask.getValue();
+
+	// Other arguments for extraction
+	command += " " + other_args.getValue();
+
+	commands.push_back(command);
+
+	int last_slash = fn_in.getValue().rfind("/");
+	if (last_slash < fn_in.getValue().size())
+	{
+		// The output name contains a directory: use that one for output
+		outputname = fn_in.getValue().substr(0, last_slash + 1) + "run_resmap";
+	}
+	else
+	{
+		outputname = "run_resmap";
+	}
+
+	prepareFinalCommand(outputname, commands, final_command);
+}
+
+
+PublishJobWindow::PublishJobWindow() : RelionJobWindow(2, HAS_NOT_MPI, HAS_NOT_THREAD)
+{
+	tab1->begin();
+	tab1->label("cite RELION");
+	resetHeight();
+
+	cite_text.place(current_y, "\
+If RELION is useful in your work, please cite us. Relevant papers are:\n \n \
+ * The general Bayesian approach (and the first mention of RELION): \n \
+     Scheres (2012) J. Mol. Biol. (PMID: 22100448)	 \n \n\
+ * RELION implementation details and the 3D auto-refine procedure: \n \
+     Scheres (2012) J. Struct. Biol. (PMID: 23000701)	 \n \n\
+ * The gold-standard FSC and the relevance of the 0.143 criterion: \n \
+     Scheres & Chen (2012) Nat. Meth. (PMID: 22842542)	 \n \n\
+ * The movie-processing procedure: \n \
+     Bai et al. (2013) eLife (PMID: 23427024 )	 \n \n\
+ * The correction of mask effects on the FSC curve by randomised phases: \n \
+     Chen et al. (2013) Ultramicroscopy (PMID: 23872039)	 \n \n\
+ * The auto-picking, sorting and particle-polishing: \n \
+     Scheres (2014) in preparation"
+, GUIWIDTH - WCOL0 - 50, GUIHEIGHT - 150);
+
+	//cite_text.mydisp->textsize(12);
+
+	tab1->end();
+	tab2->begin();
+	tab2->label("cite others");
+	resetHeight();
+
+	cite_external_text.place(current_y, "\
+Please also cite the following EXTERNAL programs: \n \n \
+* CTFFIND3 for CTF-estimation: \n \
+    Mindell & Grigorieff (2003) J. Mol. Biol. (PMID: 12781660) \n \n\
+* ResMap for local-resolution estimation:  \n\
+    Kucukelbir et al. (2014) Nat. Meth. (PMID: 24213166)"
+, GUIWIDTH - WCOL0 - 50, GUIHEIGHT - 150);
+
+	tab2->end();
+
+}
+
+void PublishJobWindow::toggle_new_continue(bool _is_continue)
+{
+	is_continue = _is_continue;
+	// never submit this to queue, as ResMap needs user interaction
+	do_queue.deactivate(true);
+}
+
+void PublishJobWindow::getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command)
+{
+	commands.clear();
+	std::string command = " Sorry, you still need to write your own paper... ;-) ";
+
+	commands.push_back(command);
+	outputname = "run_publish";
+	prepareFinalCommand(outputname, commands, final_command);
+}
+
diff --git a/src/gui_jobwindow.h b/src/gui_jobwindow.h
new file mode 100644
index 0000000..8463dbd
--- /dev/null
+++ b/src/gui_jobwindow.h
@@ -0,0 +1,708 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef GUI_JOBWINDOW_H_
+#define GUI_JOBWINDOW_H_
+
+#define MENUHEIGHT 30
+#define TABHEIGHT 25
+#define HAS_MPI true
+#define HAS_NOT_MPI false
+#define HAS_THREAD true
+#define HAS_NOT_THREAD false
+#define HAS_RUN true
+#define HAS_NOT_RUN false
+
+#include "src/gui_entries.h"
+// Our own defaults at LMB are the hard-coded ones
+#define DEFAULTQSUBLOCATION "/public/EM/RELION/relion/bin/qsub.csh"
+#define DEFAULTCTFFINDLOCATION "/public/EM/CTFFIND/ctffind3.exe"
+#define DEFAULTRESMAPLOCATION "/public/EM/ResMap/ResMap-1.1.4-linux64"
+
+static Fl_Menu_Item sampling_options[] = {
+		      {"30 degrees"},
+		      {"15 degrees"},
+		      {"7.5 degrees"},
+		      {"3.7 degrees"},
+		      {"1.8 degrees"},
+		      {"0.9 degrees"},
+		      {"0.5 degrees"},
+		      {"0.2 degrees"},
+		      {"0.1 degrees"},
+		      {0} // this should be the last entry
+};
+
+class RelionJobWindow : public Fl_Box
+{
+public:
+	// Position of current cursor to place new elements
+	int start_y, current_y;
+
+	// Menu
+	Fl_Menu_Bar *menubar;
+
+	// Choice for new/continue
+	Fl_Choice *choice_continue;
+    Fl_Menu_ *menu_continue;
+
+	// Tabs
+    Fl_Tabs *tabs;
+	Fl_Group *tab1, *tab2, *tab3, *tab4, *tab5, *tab6, *runtab;
+
+	// Running
+	Fl_Group *queue_group;
+	SliderEntry nr_mpi;
+	SliderEntry nr_threads;
+	SliderEntry ram_per_thread;
+    BooleanEntry do_queue;
+	AnyEntry queuename;
+	AnyEntry qsub;
+	FileNameEntry qsubscript;
+	bool have_extra1, have_extra2;
+	AnyEntry qsub_extra1;
+	AnyEntry qsub_extra2;
+	AnyEntry other_args;
+
+    // Run buttons
+    Fl_Button *run_button, *print_CL_button, *cite_button;
+
+	// For the run tab
+	bool has_mpi;
+	bool has_thread;
+
+	bool is_continue;
+
+
+public:
+	// Constructor with x, y, w, h and a title
+	RelionJobWindow(int nr_tabs, bool _has_mpi, bool _has_thread, bool _has_run = true,
+			int x = WCOL0, int y = MENUHEIGHT+10, int w = GUIWIDTH - WCOL0 - 10, int h = GUIHEIGHT-70, const char* title = "");
+
+    // Destructor
+    ~RelionJobWindow() {};
+
+    void resetHeight();
+
+    void setupRunTab();
+
+    // by default nothing happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// write/read settings to disc
+	void openWriteFile(std::string fn, std::ofstream &fh);
+	bool openReadFile(std::string fn, std::ifstream &fh);
+	void closeWriteFile(std::ofstream& fh);
+	void closeReadFile(std::ifstream& fh);
+
+	// Write the job submission script
+	void saveJobSubmissionScript(std::string newfilename, std::string outputname, std::vector<std::string> commands);
+
+	// Prepare the final (job submission or combined (mpi) command of possibly multiple lines)
+	void prepareFinalCommand(std::string &outputname, std::vector<std::string> &commands, std::string &final_command);
+
+private:
+
+    static void cb_menu_continue(Fl_Widget*, void*);
+    inline void cb_menu_continue_i();
+
+};
+
+/*
+class XXXXJobWindow : public RelionJobWindow
+{
+public:
+
+	// I/O
+
+public:
+
+	// Constructor
+	XXXXJobWindow();
+
+	// Destructor
+	~XXXXJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command);
+
+};
+*/
+
+class GeneralJobWindow : public RelionJobWindow
+{
+public:
+
+	// I/O
+	SliderEntry angpix, particle_diameter;
+
+public:
+
+	// Constructor
+	GeneralJobWindow();
+
+	// Destructor
+	~GeneralJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command);
+
+};
+
+class CtffindJobWindow : public RelionJobWindow
+{
+public:
+
+	FileNameEntry mic_names;
+	AnyEntry output_star_ctf_mics;
+	FileNameEntry fn_ctffind3_exe;
+	SliderEntry ctf_win;
+	SliderEntry cs, kv, q0, angpix, dstep, dast;
+	SliderEntry box, resmin, resmax, dfmin, dfmax, dfstep;
+
+public:
+
+	// Constructor
+	CtffindJobWindow();
+
+	// Destructor
+	~CtffindJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	void getCommands(std::string &outputname, std::vector<std::string> &commands,
+			std::string &final_command, double angpix);
+
+};
+
+class AutopickJobWindow : public RelionJobWindow
+{
+public:
+
+	FileNameEntry fn_input_autopick;
+	FileNameEntry fn_refs_autopick;
+	AnyEntry autopick_rootname;
+	BooleanEntry do_invert_refs;
+	BooleanEntry do_ctf_autopick;
+	BooleanEntry do_ignore_first_ctfpeak_autopick;
+	SliderEntry lowpass_autopick;
+	SliderEntry psi_sampling_autopick;
+	BooleanEntry do_write_fom_maps, do_read_fom_maps;
+	SliderEntry threshold_autopick;
+	SliderEntry mindist_autopick;
+
+	Fl_Group *autopick_ctf_group;
+
+public:
+
+	// Constructor
+	AutopickJobWindow();
+
+	// Destructor
+	~AutopickJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	void getCommands(std::string &outputname, std::vector<std::string> &commands,
+			std::string &final_command, double angpix, double particle_diameter);
+
+};
+
+
+class ManualpickJobWindow : public RelionJobWindow
+{
+public:
+
+	FileNameEntry fn_in;
+	FileNameEntry fn_out;
+	AnyEntry manualpick_rootname;
+	SliderEntry lowpass;
+	SliderEntry micscale;
+	SliderEntry ctfscale;
+	SliderEntry sigma_contrast;
+	SliderEntry white_val;
+	SliderEntry black_val;
+	BooleanEntry do_color;
+	AnyEntry color_label;
+	FileNameEntry fn_color;
+	SliderEntry blue_value;
+	SliderEntry red_value;
+
+	Fl_Group *color_group;
+
+public:
+
+	// Constructor
+	ManualpickJobWindow();
+
+	// Destructor
+	~ManualpickJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	void getCommands(std::string &outputname, std::vector<std::string> &commands,
+			std::string &final_command, double angpix, double particle_diameter);
+
+};
+
+
+class ExtractJobWindow : public RelionJobWindow
+{
+public:
+
+	// I/O
+	FileNameEntry star_mics;
+	AnyEntry pick_suffix;
+	AnyEntry extract_rootname;
+
+	// extract
+	BooleanEntry do_extract;
+	SliderEntry extract_size;
+	BooleanEntry do_rescale;
+	SliderEntry rescale;
+	BooleanEntry do_norm;
+	SliderEntry white_dust;
+	SliderEntry black_dust;
+	BooleanEntry do_invert;
+
+	// movies
+	BooleanEntry do_movie_extract;
+	AnyEntry movie_rootname;
+	SliderEntry first_movie_frame;
+	SliderEntry last_movie_frame;
+
+	Fl_Group *extract_group, *rescale_group, *norm_group, *movie_extract_group;
+
+public:
+
+	// Constructor
+	ExtractJobWindow();
+
+	// Destructor
+	~ExtractJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands,
+			std::string &final_command, double angpix, double particle_diameter);
+
+};
+
+class SortJobWindow : public RelionJobWindow
+{
+public:
+
+	// I/O
+	FileNameEntry input_star;
+	FileNameEntry fn_refs;
+	BooleanEntry do_ctf;
+	BooleanEntry do_ignore_first_ctfpeak;
+
+	Fl_Group *ctf_group;
+
+public:
+
+	// Constructor
+	SortJobWindow();
+
+	// Destructor
+	~SortJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands,
+			std::string &final_command, double angpix, double particle_diameter);
+
+};
+
+
+
+class Class2DJobWindow : public RelionJobWindow
+{
+public:
+
+	// I/O
+	AnyEntry fn_out;
+	FileNameEntry fn_cont;
+	FileNameEntry fn_img;
+
+	// CTF
+	BooleanEntry do_ctf_correction;
+	BooleanEntry ctf_phase_flipped;
+	BooleanEntry ctf_intact_first_peak;
+
+	// Optimisation
+	SliderEntry nr_iter;
+	SliderEntry tau_fudge;
+	BooleanEntry do_zero_mask;
+	SliderEntry highres_limit;
+
+	// Sampling
+	SliderEntry nr_classes;
+	BooleanEntry dont_skip_align;
+	SliderEntry psi_sampling;
+	SliderEntry offset_range;
+	SliderEntry offset_step;
+
+	Fl_Group *ctf_group, *dont_skip_align_group;
+
+public:
+
+	// Constructor
+	Class2DJobWindow();
+
+	// Destructor
+	~Class2DJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands,
+			std::string &final_command, double angpix, double particle_diameter);
+
+};
+
+
+class Class3DJobWindow : public RelionJobWindow
+{
+public:
+
+	// I/O
+	AnyEntry fn_out;
+	FileNameEntry fn_cont;
+	FileNameEntry fn_img;
+	SliderEntry nr_classes;
+
+	// Reference
+	FileNameEntry fn_ref;
+	BooleanEntry ref_correct_greyscale;
+	SliderEntry ini_high;
+	AnyEntry sym_name;
+
+	// CTF
+	BooleanEntry do_ctf_correction;
+	BooleanEntry ctf_corrected_ref;
+	BooleanEntry ctf_phase_flipped;
+	BooleanEntry ctf_intact_first_peak;
+
+	// Optimisation
+	SliderEntry nr_iter;
+	SliderEntry tau_fudge;
+	BooleanEntry do_zero_mask;
+	FileNameEntry fn_mask;
+	SliderEntry highres_limit;
+
+	// Sampling
+	BooleanEntry dont_skip_align;
+	RadioEntry sampling;
+	SliderEntry offset_range;
+	SliderEntry offset_step;
+	BooleanEntry do_local_ang_searches;
+	SliderEntry sigma_angles;
+
+	Fl_Group *ctf_group, *dont_skip_align_group, *localsearch_group;
+
+public:
+
+	// Constructor
+	Class3DJobWindow();
+
+	// Destructor
+	~Class3DJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands,
+			std::string &final_command, double angpix, double particle_diameter);
+
+};
+
+
+class Auto3DJobWindow : public RelionJobWindow
+{
+public:
+
+	// I/O
+	AnyEntry fn_out;
+	FileNameEntry fn_cont;
+	FileNameEntry fn_img;
+
+	// Reference
+	FileNameEntry fn_ref;
+	BooleanEntry ref_correct_greyscale;
+	SliderEntry ini_high;
+	AnyEntry sym_name;
+
+	// CTF
+	BooleanEntry do_ctf_correction;
+	BooleanEntry ctf_corrected_ref;
+	BooleanEntry ctf_phase_flipped;
+	BooleanEntry ctf_intact_first_peak;
+
+	// Optimisation
+	BooleanEntry do_zero_mask;
+	FileNameEntry fn_mask;
+
+	// Sampling
+	textOnlyEntry autosample_text;
+	RadioEntry sampling;
+	SliderEntry offset_range;
+	SliderEntry offset_step;
+	RadioEntry auto_local_sampling;
+
+	// Movies
+	BooleanEntry do_movies;
+	FileNameEntry fn_movie_star;
+	SliderEntry movie_runavg_window;
+	SliderEntry movie_sigma_offset;
+	BooleanEntry do_alsorot_movies;
+	SliderEntry movie_sigma_angles;
+
+	Fl_Group *ctf_group, *movie_group, *alsorot_movie_group;
+
+public:
+
+	// Constructor
+	Auto3DJobWindow();
+
+	// Destructor
+	~Auto3DJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands,
+			std::string &final_command, double angpix, double particle_diameter);
+
+};
+
+class PostJobWindow : public RelionJobWindow
+{
+public:
+
+	// I/O
+	FileNameEntry fn_in;
+	AnyEntry fn_out;
+
+	// Masking
+	BooleanEntry do_automask;
+	SliderEntry inimask_threshold;
+	SliderEntry extend_inimask;
+	SliderEntry width_mask_edge;
+	BooleanEntry do_usermask;
+	FileNameEntry fn_mask;
+
+	// Sharpening
+	BooleanEntry do_auto_bfac;
+	SliderEntry autob_lowres;
+	BooleanEntry do_adhoc_bfac;
+	SliderEntry adhoc_bfac;
+	FileNameEntry fn_mtf;
+
+	// Filtering
+	BooleanEntry do_skip_fsc_weighting;
+	SliderEntry low_pass;
+
+	Fl_Group *automask_group, *usermask_group, *autobfac_group, *adhocbfac_group, *skipweight_group;
+
+public:
+
+	// Constructor
+	PostJobWindow();
+
+	// Destructor
+	~PostJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
+			double angpix);
+
+};
+
+class PolishJobWindow : public RelionJobWindow
+{
+
+public:
+	// I/O
+	FileNameEntry fn_in;
+	AnyEntry fn_out;
+
+	// Movements
+	SliderEntry movie_runavg_window;
+	BooleanEntry do_fit_movement;
+	SliderEntry sigma_nb;
+
+	// Damage-model
+	BooleanEntry do_bfactor_weighting;
+	SliderEntry perframe_highres;
+	SliderEntry perframe_bfac_lowres;
+	FileNameEntry fn_mask;
+	AnyEntry sym_name;
+
+	Fl_Group *fit_group, *weight_group;
+
+
+public:
+	// Constructor
+	PolishJobWindow();
+
+	// Destructor
+	~PolishJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
+			double angpix, double particle_diameter, double black_dust, double white_dust);
+};
+
+class ResmapJobWindow : public RelionJobWindow
+{
+public:
+
+	// I/O
+	FileNameEntry fn_resmap;
+
+	FileNameEntry fn_in;
+
+	// Params
+	SliderEntry pval;
+	SliderEntry minres;
+	SliderEntry maxres;
+	SliderEntry stepres;
+
+	FileNameEntry fn_mask;
+
+public:
+
+	// Constructor
+	ResmapJobWindow();
+
+	// Destructor
+	~ResmapJobWindow(){};
+
+	// write/read settings to disc
+	void write(std::string fn);
+	void read(std::string fn, bool &_is_continue);
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command,
+			double angpix);
+
+};
+
+
+class PublishJobWindow : public RelionJobWindow
+{
+public:
+
+	// I/O
+	textOnlyEntry cite_text;
+	textOnlyEntry cite_external_text;
+
+public:
+
+	// Constructor
+	PublishJobWindow();
+
+	// Destructor
+	~PublishJobWindow(){};
+
+	// what happens if you change continue old run radiobutton
+	void toggle_new_continue(bool is_continue);
+
+	// Generate the correct commands
+	void getCommands(std::string &outputname, std::vector<std::string> &commands, std::string &final_command);
+
+};
+
+
+#endif /* GUI_JOBWINDOW_H_ */
diff --git a/src/gui_mainwindow.cpp b/src/gui_mainwindow.cpp
new file mode 100644
index 0000000..67d350c
--- /dev/null
+++ b/src/gui_mainwindow.cpp
@@ -0,0 +1,583 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/gui_mainwindow.h"
+
+RelionMainWindow::RelionMainWindow(int w, int h, const char* title):Fl_Window(w,h,title)
+{
+
+	// Initialisation
+	run_button = NULL;
+	print_CL_button = NULL;
+	cite_button = NULL;
+
+    color(GUI_BACKGROUND_COLOR);
+    menubar = new Fl_Menu_Bar(0, 0, w, MENUHEIGHT);
+    menubar->add("File/Load settings",  FL_ALT+'l', cb_menubar_load, this);
+    menubar->add("File/Save settings",  FL_ALT+'s', cb_menubar_save, this);
+    menubar->add("File/Reactivate Run",  FL_ALT+'r', cb_menubar_reactivate_runbutton, this);
+    menubar->add("File/About",  FL_ALT+'a', cb_menubar_about, this);
+    menubar->add("File/Quit", FL_ALT+'q', cb_menubar_quit, this);
+    current_y = MENUHEIGHT + 10;
+
+    toggle_continue = new Fl_Toggle_Button(WCOL0, 4, 200, 22);
+    toggle_continue->labelsize(14);
+    toggle_continue->color(GUI_BACKGROUND_COLOR, GUI_BACKGROUND_COLOR);
+    toggle_continue->callback(cb_toggle_continue, this);
+
+    // Add run buttons on the menubar as well
+	print_CL_button = new Fl_Button(GUIWIDTH - 220, h-50, 100, 30, "Print command");
+	print_CL_button->color(GUI_RUNBUTTON_COLOR);
+	print_CL_button->labelsize(12);
+	print_CL_button->callback( cb_print_cl, this);
+
+	run_button = new Fl_Button(GUIWIDTH - 110 , h-50, 100, 30, "Run!");
+	run_button->color(GUI_RUNBUTTON_COLOR);
+	run_button->labelfont(FL_ITALIC);
+	run_button->labelsize(18);
+	run_button->callback( cb_run, this);
+
+
+    display_button = new Fl_Button(10, h-50, XCOL0-20, 30, "Display");
+	display_button->color(GUI_RUNBUTTON_COLOR);
+	display_button->callback( cb_display, this);
+
+    // Browser to act as "tab selector"
+    browser = new Fl_Hold_Browser(10,MENUHEIGHT+10,WCOL0-20,h-MENUHEIGHT-70);
+    browser->add("General");
+    browser->add("Micrograph inspection");
+    browser->add("CTF estimation");
+    browser->add("Auto-picking");
+    browser->add("Particle extraction");
+    browser->add("Particle sorting");
+    browser->add("2D classification");
+    browser->add("3D classification");
+    browser->add("3D auto-refine");
+    browser->add("Post-processing");
+    browser->add("Particle polishing");
+    browser->add("Local-resolution");
+    browser->add("Publish!");
+
+    // browse page
+    {
+        browse_grp[0] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_general = new GeneralJobWindow();
+    	browse_grp[0]->end();
+    }
+    // browse page
+    {
+        browse_grp[1] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_manualpick = new ManualpickJobWindow();
+       	browse_grp[1]->end();
+    }
+    // browse page
+    {
+        browse_grp[2] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_ctffind = new CtffindJobWindow();
+    	browse_grp[2]->end();
+    }
+    // browse page
+    {
+
+        browse_grp[3] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_autopick = new AutopickJobWindow();
+       	browse_grp[3]->end();
+    }
+    // browse page
+    {
+
+        browse_grp[4] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_extract = new ExtractJobWindow();
+       	browse_grp[4]->end();
+    }
+    // browse page
+    {
+
+        browse_grp[5] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_sort = new SortJobWindow();
+       	browse_grp[5]->end();
+    }
+    // browse page
+    {
+
+        browse_grp[6] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_class2d = new Class2DJobWindow();
+       	browse_grp[6]->end();
+    }
+    // browse page
+    {
+
+        browse_grp[7] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_class3d = new Class3DJobWindow();
+       	browse_grp[7]->end();
+    }
+    // browse page
+    {
+
+        browse_grp[8] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_auto3d = new Auto3DJobWindow();
+       	browse_grp[8]->end();
+    }
+    // browse page
+    {
+        browse_grp[9] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_post = new PostJobWindow();
+       	browse_grp[9]->end();
+    }
+    // browse page
+    {
+
+        browse_grp[10] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_polish = new PolishJobWindow();
+       	browse_grp[10]->end();
+    }
+    // browse page
+    {
+        browse_grp[11] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_resmap = new ResmapJobWindow();
+       	browse_grp[11]->end();
+    }
+    // browse page
+    {
+        browse_grp[12] = new Fl_Group(WCOL0, MENUHEIGHT, 550, 600-MENUHEIGHT);
+    	job_publish = new PublishJobWindow();
+       	browse_grp[12]->end();
+    }
+    browser->callback(cb_select_browsegroup);
+    browser->end();
+
+    // Set and activate current selection
+    browser->select(1); // just start from the beginning
+    cb_select_browsegroup_i(); // make default active
+    toggle_continue->value(0); // 0 = new run; 1 = continue
+    cb_toggle_continue_i(); // make default active
+
+    resizable();
+}
+
+void RelionMainWindow::jobCommunicate(bool do_write, bool do_read, bool do_toggle_continue, bool do_commandline, int this_job)
+{
+	int myval = (this_job > 0) ? this_job : browser->value();
+
+	// always write the general settings with the (hidden) empty name
+	if (do_write)
+		job_general->write("");
+
+	if (myval == 1)
+	{
+		if (do_write)
+			job_general->write(fn_settings);
+		if (do_read)
+			job_general->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_general->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_general->getCommands(outputname, commands, final_command);
+	}
+	else if (myval == 2)
+	{
+		if (do_write)
+			job_manualpick->write(fn_settings);
+		if (do_read)
+			job_manualpick->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_manualpick->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_manualpick->getCommands(outputname, commands, final_command,
+					job_general->angpix.getValue(), job_general->particle_diameter.getValue());
+	}
+	else if (myval == 3)
+	{
+		if (do_write)
+			job_ctffind->write(fn_settings);
+		if (do_read)
+			job_ctffind->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_ctffind->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_ctffind->getCommands(outputname, commands, final_command, job_general->angpix.getValue());
+	}
+	else if (myval == 4)
+	{
+		if (do_write)
+			job_autopick->write(fn_settings);
+		if (do_read)
+			job_autopick->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_autopick->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_autopick->getCommands(outputname, commands, final_command,
+					job_general->angpix.getValue(), job_general->particle_diameter.getValue());
+	}
+	else if (myval == 5)
+	{
+		if (do_write)
+			job_extract->write(fn_settings);
+		if (do_read)
+			job_extract->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_extract->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_extract->getCommands(outputname, commands, final_command,
+					job_general->angpix.getValue(), job_general->particle_diameter.getValue());
+	}
+	else if (myval == 6)
+	{
+		if (do_write)
+			job_sort->write(fn_settings);
+		if (do_read)
+			job_sort->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_sort->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_sort->getCommands(outputname, commands, final_command,
+					job_general->angpix.getValue(), job_general->particle_diameter.getValue());
+	}
+	else if (myval == 7)
+	{
+		if (do_write)
+			job_class2d->write(fn_settings);
+		if (do_read)
+			job_class2d->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_class2d->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_class2d->getCommands(outputname, commands, final_command,
+					job_general->angpix.getValue(), job_general->particle_diameter.getValue());
+	}
+	else if (myval == 8)
+	{
+		if (do_write)
+			job_class3d->write(fn_settings);
+		if (do_read)
+			job_class3d->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_class3d->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_class3d->getCommands(outputname, commands, final_command,
+					job_general->angpix.getValue(), job_general->particle_diameter.getValue());
+	}
+	else if (myval == 9)
+	{
+		if (do_write)
+			job_auto3d->write(fn_settings);
+		if (do_read)
+			job_auto3d->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_auto3d->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_auto3d->getCommands(outputname, commands, final_command,
+					job_general->angpix.getValue(), job_general->particle_diameter.getValue());
+	}
+	else if (myval == 10)
+	{
+		if (do_write)
+			job_post->write(fn_settings);
+		if (do_read)
+			job_post->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_post->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_post->getCommands(outputname, commands, final_command,
+					job_general->angpix.getValue());
+	}
+	else if (myval == 11)
+	{
+		if (do_write)
+			job_polish->write(fn_settings);
+		if (do_read)
+			job_polish->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_polish->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_polish->getCommands(outputname, commands, final_command,
+					job_general->angpix.getValue(), job_general->particle_diameter.getValue(),
+					job_extract->black_dust.getValue(), job_extract->white_dust.getValue());
+	}
+	else if (myval == 12)
+	{
+		if (do_write)
+			job_resmap->write(fn_settings);
+		if (do_read)
+			job_resmap->read(fn_settings, is_main_continue);
+		if (do_toggle_continue)
+			job_resmap->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_resmap->getCommands(outputname, commands, final_command,
+					job_general->angpix.getValue());
+	}
+	else if (myval == 13)
+	{
+		if (do_toggle_continue)
+			job_publish->toggle_new_continue(is_main_continue);
+		if (do_commandline)
+			job_publish->getCommands(outputname, commands, final_command);
+	}
+
+	// set the continue button correct upon reading of old settings
+	if (do_read)
+	{
+		if (is_main_continue)
+			toggle_continue->value(1);
+		else
+			toggle_continue->value(0);
+		// Make the choice active
+		cb_toggle_continue_i();
+	}
+
+
+}
+
+void RelionMainWindow::cb_select_browsegroup(Fl_Widget* o, void* v)
+{
+	RelionMainWindow* T=(RelionMainWindow*)v;
+	T->cb_select_browsegroup_i();
+	run_button->activate();
+
+}
+
+void RelionMainWindow::cb_select_browsegroup_i()
+{
+
+	// Show the 'selected' group, hide the others
+    for ( int t=1; t<=NR_BROWSE_TABS; t++ )
+    {
+    	if ( t == (browser->value()) )
+        {
+        	browse_grp[t-1]->show();
+        }
+        else
+        {
+        	browse_grp[t-1]->hide();
+        }
+    }
+
+    // Toggle the new tab according to the continue toggle button
+    jobCommunicate(DONT_WRITE, DONT_READ, DO_TOGGLE_CONT, DONT_GET_CL);
+
+}
+// Display button call-back functions
+void RelionMainWindow::cb_display(Fl_Widget* o, void* v) {
+
+    RelionMainWindow* T=(RelionMainWindow*)v;
+    T->cb_display_i();
+}
+
+
+void RelionMainWindow::cb_display_i()
+{
+	std::string command = " relion_display --gui &" ;
+	system(command.c_str());
+}
+
+void RelionMainWindow::cb_toggle_continue(Fl_Widget*, void* v)
+{
+    RelionMainWindow* T=(RelionMainWindow*)v;
+    T->cb_toggle_continue_i();
+}
+
+void RelionMainWindow::cb_toggle_continue_i()
+{
+
+	if (toggle_continue->value() == 1)
+	{
+		is_main_continue = true;
+		toggle_continue->label("Continue old run");
+	}
+	else
+	{
+		is_main_continue = false;
+		toggle_continue->label("Start new run");
+	}
+
+	jobCommunicate(DONT_WRITE, DONT_READ, DO_TOGGLE_CONT, DONT_GET_CL);
+
+}
+
+void RelionMainWindow::cb_print_cl(Fl_Widget* o, void* v) {
+
+    RelionMainWindow* T=(RelionMainWindow*)v;
+    T->cb_print_cl_i();
+}
+
+void RelionMainWindow::cb_print_cl_i()
+{
+	jobCommunicate(DONT_WRITE, DONT_READ, DONT_TOGGLE_CONT, DO_GET_CL);
+    std::cout << " *** The command is:" << std::endl;
+    for (int icom = 0; icom < commands.size(); icom++)
+    	std::cout << commands[icom] << std::endl;
+
+}
+
+// Run button call-back functions
+void RelionMainWindow::cb_run(Fl_Widget* o, void* v) {
+
+    RelionMainWindow* T=(RelionMainWindow*)v;
+    T->cb_run_i();
+}
+
+void RelionMainWindow::cb_run_i()
+{
+	// Save temporary hidden file with this jobs settings
+	fn_settings = "";
+	jobCommunicate(DO_WRITE, DONT_READ, DONT_TOGGLE_CONT, DONT_GET_CL);
+
+	// Get the command line arguments from the currently active jobwindow,
+	// save job submission script, and prepare the final command
+	jobCommunicate(DONT_WRITE, DONT_READ, DONT_TOGGLE_CONT, DO_GET_CL);
+
+	// Also save a copy of the GUI settings with the current output name
+	fn_settings = outputname;
+	jobCommunicate(DO_WRITE, DONT_READ, DONT_TOGGLE_CONT, DONT_GET_CL);
+
+	if (commands.size()==0)
+	{
+		std::cout << " Nothing to do..."<< std::endl;
+		return;
+	}
+
+	std::cerr << "Executing: " << final_command << std::endl;
+	system(final_command.c_str());
+
+	// Deactivate Run button to prevent the user from accidentally submitting many jobs
+	run_button->deactivate();
+
+}
+
+
+// call-back functions for the menubar
+void RelionMainWindow::cb_menubar_load(Fl_Widget* o, void* v) {
+
+    RelionMainWindow* T=(RelionMainWindow*)v;
+    T->cb_menubar_load_i();
+}
+
+void RelionMainWindow::cb_menubar_load_i()
+{
+    Fl_File_Chooser * G_chooser = new Fl_File_Chooser("", "*.settings", Fl_File_Chooser::SINGLE, "Choose a GUI settings file");
+
+    G_chooser->directory(NULL);
+    G_chooser->show();
+
+    // Block until user picks something.
+    //     (The other way to do this is to use a callback())
+    //
+    while(G_chooser->shown()) {
+        Fl::wait();
+    }
+
+    // Print the results
+    if ( G_chooser->value() == NULL ) {
+        //fprintf(stderr, "(User hit 'Cancel')\n");
+        return;
+    }
+    // Read in settings file with the chosen name
+    fn_settings = G_chooser->value();
+
+    // Set the jobtype to the correct one
+    // deduce from the settings name
+    int npos = fn_settings.length();
+    	if (fn_settings.rfind(".gui_general.") < npos)
+    		browser->value(1);
+    	else if  (fn_settings.rfind(".gui_manualpick.") < npos)
+    		browser->value(2);
+    	else if  (fn_settings.rfind(".gui_ctffind.") < npos)
+    		browser->value(3);
+    	else if  (fn_settings.rfind(".gui_autopick.") < npos)
+    		browser->value(4);
+    	else if  (fn_settings.rfind(".gui_extract.") < npos)
+    		browser->value(5);
+    	else if  (fn_settings.rfind(".gui_sort.") < npos)
+    		browser->value(6);
+    	else if  (fn_settings.rfind(".gui_class2d.") < npos)
+    		browser->value(7);
+    	else if  (fn_settings.rfind(".gui_class3d.") < npos)
+    		browser->value(8);
+    	else if  (fn_settings.rfind(".gui_auto3d.") < npos)
+    		browser->value(9);
+    	else if  (fn_settings.rfind(".gui_post.") < npos)
+    		browser->value(10);
+    	else if  (fn_settings.rfind(".gui_polish.") < npos)
+    		browser->value(11);
+    	else if  (fn_settings.rfind(".gui_resmap.") < npos)
+    		browser->value(12);
+    cb_select_browsegroup_i(); // change to the corresponding jobwindow
+    // Read in the settings file
+    jobCommunicate(DONT_WRITE, DO_READ, DONT_TOGGLE_CONT, DONT_GET_CL);
+
+}
+
+// Save button call-back function
+void RelionMainWindow::cb_menubar_save(Fl_Widget* o, void* v)
+{
+    RelionMainWindow* T=(RelionMainWindow*)v;
+    T->cb_menubar_save_i();
+}
+
+void RelionMainWindow::cb_menubar_save_i()
+{
+	fn_settings = "";
+	jobCommunicate(DO_WRITE, DONT_READ, DONT_TOGGLE_CONT, DONT_GET_CL);
+
+}
+
+void RelionMainWindow::cb_menubar_reactivate_runbutton(Fl_Widget* o, void* v)
+{
+
+    RelionMainWindow* T=(RelionMainWindow*)v;
+    T->cb_menubar_reactivate_runbutton_i();
+}
+
+void RelionMainWindow::cb_menubar_reactivate_runbutton_i()
+{
+	run_button->activate();
+}
+
+
+void RelionMainWindow::cb_menubar_about(Fl_Widget* o, void* v)
+{
+
+    RelionMainWindow* T=(RelionMainWindow*)v;
+    T->cb_menubar_about_i();
+}
+
+void RelionMainWindow::cb_menubar_about_i()
+{
+	ShowHelpText *help = new ShowHelpText("\
+RELION is written by Sjors Scheres at the MRC Laboratory of Molecular Biology (scheres at mrc-lmb.cam.ac.uk).\n \
+\n\
+If RELION is useful in your work, please cite us in the contexts as explained under the \"Publish!\" tab, or on the RELION wiki at http://www2.mrc-lmb.cam.ac.uk/relion. \n  \
+\n\
+Note that RELION is completely free, open-source software. You can redistribute it and/or modify it for your own purposes, but please do make sure \
+the contribution of Sjors Scheres is acknowledged appropriately. In order to maintain an overview of existing versions, he would also appreciate being \
+notified of any redistribution of (modified versions of) the code. \n \
+");
+}
+
+
+void RelionMainWindow::cb_menubar_quit(Fl_Widget* o, void* v)
+{
+	RelionMainWindow* T=(RelionMainWindow*)v;
+    T->cb_menubar_quit_i();
+}
+
+void RelionMainWindow::cb_menubar_quit_i()
+{
+	exit(0);
+}
diff --git a/src/gui_mainwindow.h b/src/gui_mainwindow.h
new file mode 100644
index 0000000..e41d78f
--- /dev/null
+++ b/src/gui_mainwindow.h
@@ -0,0 +1,134 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef GUI_MAINWINDOW_H_
+#define GUI_MAINWINDOW_H_
+#include "src/gui_jobwindow.h"
+#include "src/gui_entries.h"
+
+#define NR_BROWSE_TABS 13
+
+#define DO_WRITE true
+#define DONT_WRITE false
+#define DO_READ true
+#define DONT_READ false
+#define DO_TOGGLE_CONT true
+#define DONT_TOGGLE_CONT false
+#define DO_GET_CL true
+#define DONT_GET_CL false
+
+// This class organises the main winfow of the relion GUI
+static Fl_Hold_Browser *browser;
+static Fl_Group        *browse_grp[NR_BROWSE_TABS];
+static bool is_main_continue;
+static GeneralJobWindow *job_general;
+static CtffindJobWindow *job_ctffind;
+static ManualpickJobWindow *job_manualpick;
+static AutopickJobWindow *job_autopick;
+static ExtractJobWindow *job_extract;
+static SortJobWindow *job_sort;
+static Class2DJobWindow *job_class2d;
+static Class3DJobWindow *job_class3d;
+static Auto3DJobWindow *job_auto3d;
+static PostJobWindow *job_post;
+static PolishJobWindow *job_polish;
+static ResmapJobWindow *job_resmap;
+static PublishJobWindow *job_publish;
+//Toggle continue button
+static Fl_Toggle_Button *toggle_continue;
+// Run button
+static Fl_Button *run_button;
+
+class RelionMainWindow : public Fl_Window
+{
+
+public:
+
+	// For Tabs
+	Fl_Menu_Bar *menubar;
+	Fl_Tabs *tabs;
+	Fl_Group *tab0, *tab1, *tab2, *tab3, *tab4, *tab5;
+
+    // Run button
+    Fl_Button *print_CL_button, *cite_button, *display_button;
+
+    // For job submission
+    std::string outputname, final_command;
+    std::vector<std::string> commands;
+
+    //FileName for settings file
+    std::string fn_settings;
+
+	// Constructor with w x h size of the window and a title
+	RelionMainWindow(int w, int h, const char* title);
+
+    // Destructor
+    ~RelionMainWindow(){};
+
+    // Communicate with the different jobtype objects
+    void jobCommunicate(bool do_write, bool do_read, bool do_toggle_continue, bool do_commandline, int this_job = 0);
+
+private:
+
+
+    // Vertical distance from the top
+    int start_y;
+
+    // Current height
+    int current_y;
+
+
+    /** Call-back functions for the Run button
+     *  The method of using two functions of static void and inline void was copied from:
+     *  http://www3.telus.net/public/robark/
+     */
+
+    static void cb_select_browsegroup(Fl_Widget*, void*);
+    inline void cb_select_browsegroup_i();
+
+    static void cb_toggle_continue(Fl_Widget*, void*);
+    inline void cb_toggle_continue_i();
+
+    static void cb_display(Fl_Widget*, void*);
+    inline void cb_display_i();
+
+    static void cb_run(Fl_Widget*, void*);
+    inline void cb_run_i();
+
+    static void cb_print_cl(Fl_Widget*, void*);
+    inline void cb_print_cl_i();
+
+    static void cb_menubar_load(Fl_Widget*, void*);
+    inline void cb_menubar_load_i();
+
+    static void cb_menubar_save(Fl_Widget*, void*);
+    inline void cb_menubar_save_i();
+
+    static void cb_menubar_reactivate_runbutton(Fl_Widget*, void*);
+    inline void cb_menubar_reactivate_runbutton_i();
+
+    static void cb_menubar_about(Fl_Widget*, void*);
+    inline void cb_menubar_about_i();
+
+    static void cb_menubar_quit(Fl_Widget*, void*);
+    inline void cb_menubar_quit_i();
+};
+
+#endif /* GUI_MAINWINDOW_H_ */
diff --git a/src/healpix_sampling.cpp b/src/healpix_sampling.cpp
new file mode 100644
index 0000000..25af0a8
--- /dev/null
+++ b/src/healpix_sampling.cpp
@@ -0,0 +1,1964 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/healpix_sampling.h"
+//#define DEBUG_SAMPLING
+
+void HealpixSampling::clear()
+{
+	is_3D = false;
+	fn_sym = "C1";
+	limit_tilt = psi_step = offset_range = offset_step = 0.;
+	orientational_prior_mode = NOPRIOR;
+	directions_ipix.clear();
+	directions_angles.clear();
+	psi_angles.clear();
+	translations.clear();
+	pointer_dir_nonzeroprior.clear();
+	pointer_psi_nonzeroprior.clear();
+	directions_prior.clear();
+	psi_prior.clear();
+	L_repository.clear();
+	R_repository.clear();
+	pgGroup = pgOrder = 0;
+
+}
+
+void HealpixSampling::initialise(int prior_mode, int ref_dim, bool _do_3d_trans)
+{
+
+	// Set the prior mode (belongs to mlmodel, but very useful inside this object)
+	orientational_prior_mode = prior_mode;
+
+	if (ref_dim != -1)
+		is_3D = (ref_dim == 3);
+
+	// Set flag for x,y,z-translations
+	is_3d_trans = _do_3d_trans;
+
+	// By default psi_step is approximate sampling of rot,tilt in 3D; and 10 degrees in 2D
+	if (psi_step < 0)
+	{
+		if (is_3D)
+			psi_step = 360. / (6 * ROUND(std::pow(2., healpix_order)));
+		else
+			psi_step = 10.;
+	}
+
+	if (perturbation_factor < 0. || perturbation_factor > 1.)
+		REPORT_ERROR("HealpixSampling::initialise: random perturbation factor should be between 0 and 1.");
+
+	if (is_3D)
+	{
+		healpix_base.Set(healpix_order, NEST);
+
+		// Set up symmetry
+		SymList SL;
+		SL.isSymmetryGroup(fn_sym, pgGroup, pgOrder);
+		SL.read_sym_file(fn_sym);
+
+		// Precalculate (3x3) symmetry matrices
+		Matrix2D<double>  L(4, 4), R(4, 4);
+		Matrix2D<double>  Identity(3,3);
+		Identity.initIdentity();
+		R_repository.clear();
+		L_repository.clear();
+		R_repository.push_back(Identity);
+		L_repository.push_back(Identity);
+		for (int isym = 0; isym < SL.SymsNo(); isym++)
+		{
+			SL.get_matrices(isym, L, R);
+			R.resize(3, 3);
+			L.resize(3, 3);
+			R_repository.push_back(R);
+			L_repository.push_back(L);
+		}
+	}
+	else
+	{
+		fn_sym = "C1"; // This may not be set yet if restarting a 2D run....
+	}
+
+
+	// Store the not-oversampled translations, and make sure oversampled sampling is 1 pixel
+	setTranslations();
+
+	// Store the non-oversampled projection directions
+	setOrientations();
+
+	// Random perturbation and filling of the directions, psi_angles and translations vectors
+	resetRandomlyPerturbedSampling();
+
+}
+
+void HealpixSampling::resetRandomlyPerturbedSampling()
+{
+
+	// Actual instance of random perturbation
+	// Add to the random perturbation from the last iteration, so it keeps changing strongly...
+	random_perturbation += rnd_unif(0.5*perturbation_factor, perturbation_factor);
+	random_perturbation = realWRAP(random_perturbation, -perturbation_factor, perturbation_factor);
+
+}
+
+void HealpixSampling::read(FileName fn_in)
+{
+
+    // Open input file
+    std::ifstream in(fn_in.data(), std::ios_base::in);
+    if (in.fail())
+        REPORT_ERROR( (std::string) "HealpixSampling::readStar: File " + fn_in + " cannot be read." );
+
+    MetaDataTable MD;
+
+    // Read general stuff
+    MD.readStar(in, "sampling_general");
+    in.close();
+
+    if (!MD.getValue(EMDL_SAMPLING_IS_3D, is_3D) ||
+    	!MD.getValue(EMDL_SAMPLING_IS_3D_TRANS, is_3d_trans) ||
+		!MD.getValue(EMDL_SAMPLING_PSI_STEP, psi_step) ||
+		!MD.getValue(EMDL_SAMPLING_OFFSET_RANGE, offset_range) ||
+		!MD.getValue(EMDL_SAMPLING_OFFSET_STEP, offset_step) ||
+		!MD.getValue(EMDL_SAMPLING_PERTURBATION_FACTOR, perturbation_factor))
+		REPORT_ERROR("HealpixSampling::readStar: incorrect sampling_general table");
+	if (is_3D)
+	{
+		if (!MD.getValue(EMDL_SAMPLING_HEALPIX_ORDER, healpix_order) ||
+			!MD.getValue(EMDL_SAMPLING_SYMMETRY, fn_sym) ||
+			!MD.getValue(EMDL_SAMPLING_LIMIT_TILT, limit_tilt) )
+			REPORT_ERROR("HealpixSampling::readStar: incorrect sampling_general table for 3D sampling");
+
+		// For 3D samplings reset psi_step to -1:
+		// By default it will then be set to the healpix sampling
+		// Only if the --psi_step option is given on the command line it will be set to something different!
+		psi_step = -1.;
+	}
+	else
+	{
+		fn_sym = "irrelevant";
+		limit_tilt = 0.;
+		healpix_order = 0;
+	}
+
+}
+
+void HealpixSampling::write(FileName fn_out)
+{
+	MetaDataTable MD;
+	std::ofstream  fh;
+	FileName fn_tmp;
+
+    fn_tmp = fn_out + "_sampling.star";
+    fh.open((fn_tmp).c_str(), std::ios::out);
+    if (!fh)
+        REPORT_ERROR( (std::string)"HealpixSampling::write: Cannot write file: " + fn_tmp);
+
+    MD.setIsList(true);
+    MD.addObject();
+	MD.setName("sampling_general");
+	MD.setValue(EMDL_SAMPLING_IS_3D, is_3D);
+	MD.setValue(EMDL_SAMPLING_IS_3D_TRANS, is_3d_trans);
+	if (is_3D)
+	{
+		MD.setValue(EMDL_SAMPLING_HEALPIX_ORDER, healpix_order);
+		MD.setValue(EMDL_SAMPLING_SYMMETRY, fn_sym);
+		MD.setValue(EMDL_SAMPLING_LIMIT_TILT, limit_tilt);
+	}
+	MD.setValue(EMDL_SAMPLING_PSI_STEP, psi_step);
+	MD.setValue(EMDL_SAMPLING_OFFSET_RANGE, offset_range);
+	MD.setValue(EMDL_SAMPLING_OFFSET_STEP, offset_step);
+	MD.setValue(EMDL_SAMPLING_PERTURB, random_perturbation);
+	MD.setValue(EMDL_SAMPLING_PERTURBATION_FACTOR, perturbation_factor);
+	MD.write(fh);
+
+	// In the 3D case, also write a table with the sampled rot, tilt angles
+	if (is_3D)
+	{
+		MD.clear();
+		MD.setIsList(false);
+		MD.setName("sampling_directions");
+		for (long int idir = 0; idir < NrDirections(0, true); idir++)
+		{
+			double rot, tilt;
+			getDirection(idir, rot, tilt);
+			MD.addObject();
+			MD.setValue(EMDL_ORIENT_ROT, rot);
+			MD.setValue(EMDL_ORIENT_TILT, tilt);
+		}
+		MD.write(fh);
+	}
+
+	// Close the file
+	fh.close();
+
+
+
+}
+
+void HealpixSampling::setTranslations(double _offset_step, double _offset_range)
+{
+	translations.clear();
+	if (_offset_step > 0. && _offset_range >= 0.)
+	{
+		offset_step = _offset_step;
+		offset_range = _offset_range;
+	}
+
+	int maxr = CEIL(offset_range / offset_step);
+	for (long int ix = -maxr; ix <= maxr; ix++)
+	{
+		double xoff = ix * offset_step;
+		for (long int iy = -maxr; iy <= maxr; iy++)
+		{
+			double yoff = iy * offset_step;
+
+			if (is_3d_trans)
+			{
+				for (long int iz = -maxr; iz <= maxr; iz++)
+				{
+					double zoff = iz * offset_step;
+					if (xoff*xoff + yoff*yoff + zoff*zoff <= offset_range * offset_range)
+						translations.push_back(vectorR3(xoff, yoff, zoff));
+
+				}
+			}
+			else
+			{
+				if (xoff*xoff + yoff*yoff <= offset_range * offset_range)
+					translations.push_back(vectorR2(xoff, yoff));
+			}
+		}
+	}
+
+#ifdef DEBUG_SETTRANS
+	std::cerr << " is_3d_trans= " << is_3d_trans << std::endl;
+	for (int i = 0; i < translations.size(); i++)
+		std::cerr << " translations[i]= " << translations[i] << std::endl;
+#endif
+
+}
+/* Set only a single translation */
+void HealpixSampling::setOneTranslation(Matrix1D<double> offset)
+{
+
+	translations.clear();
+	translations.push_back(offset);
+
+}
+
+
+
+void HealpixSampling::setOrientations(int _order, double _psi_step)
+{
+
+	// Initialise
+	directions_angles.clear();
+	directions_ipix.clear();
+	psi_angles.clear();
+
+	// Setup the HealPix object
+	// For adaptive oversampling only precalculate the COARSE sampling!
+	if (_order >= 0)
+	{
+		healpix_base.Set(_order, NEST);
+		healpix_order = _order;
+	}
+
+	// 3D directions
+	if (is_3D)
+	{
+		double rot, tilt;
+		for (long int ipix = 0; ipix < healpix_base.Npix(); ipix++)
+		{
+			getDirectionFromHealPix(ipix, rot, tilt);
+
+			// Push back as Matrix1D's in the vectors
+			directions_angles.push_back(vectorR2(rot, tilt));
+			directions_ipix.push_back(ipix);
+
+
+		}
+//#define DEBUG_SAMPLING
+#ifdef  DEBUG_SAMPLING
+		writeAllOrientationsToBild("orients_all.bild", "1 0 0", 0.020);
+#endif
+		// Now remove symmetry-related pixels
+		// TODO check size of healpix_base.max_pixrad
+		removeSymmetryEquivalentPoints(0.5 * RAD2DEG(healpix_base.max_pixrad()));
+
+#ifdef  DEBUG_SAMPLING
+		writeAllOrientationsToBild("orients_sym.bild", "0 1 0", 0.021);
+#endif
+
+		// Also remove limited tilt angles
+		removePointsOutsideLimitedTiltAngles();
+
+		#ifdef  DEBUG_SAMPLING
+		if (ABS(limit_tilt) < 90.)
+			writeAllOrientationsToBild("orients_tilt.bild", "1 1 0", 0.022);
+#endif
+
+
+	}
+	else
+	{
+		directions_angles.push_back(vectorR2(0., 0.));
+		directions_ipix.push_back(-1);
+	}
+
+	// 2D in-plane angles
+	// By default in 3D case: use more-or-less same psi-sampling as the 3D healpix object
+	// By default in 2D case: use 5 degree
+	if (_psi_step > 0.)
+		psi_step = _psi_step;
+
+	int nr_psi = CEIL(360./psi_step);
+	double psi;
+	psi_step = 360./(double)nr_psi;
+	for (int ipsi = 0; ipsi < nr_psi; ipsi++)
+	{
+		psi = ipsi * psi_step;
+		psi_angles.push_back(psi);
+	}
+}
+
+/* Set only a single orientation */
+void HealpixSampling::setOneOrientation(double rot, double tilt, double psi)
+{
+	// Initialise
+	directions_angles.clear();
+	directions_ipix.clear();
+	psi_angles.clear();
+
+	// 3D directions
+	if (is_3D)
+	{
+		directions_angles.push_back(vectorR2(rot, tilt));
+		directions_ipix.push_back(-1);
+	}
+	else
+	{
+		directions_angles.push_back(vectorR2(0., 0.));
+		directions_ipix.push_back(-1);
+	}
+
+	// in-plane rotation
+	psi_angles.push_back(psi);
+
+
+}
+
+
+void HealpixSampling::writeAllOrientationsToBild(FileName fn_bild, std::string rgb, double size)
+{
+    std::ofstream out;
+    out.open (fn_bild.c_str());
+    if (!out)
+        REPORT_ERROR( (std::string)"HealpixSampling::writeAllOrientationsToBild: Cannot write file: " + fn_bild);
+
+
+    out << ".color 1 0 0 \n";
+    out << ".arrow 0 0 0 1 0 0 0.01 \n";
+    out << ".color 0 1 0 \n";
+    out << ".arrow 0 0 0  0 1 0 0.01 \n";
+    out << ".color 0 0 1 \n";
+    out << ".arrow 0 0 0 0 0 1 0.01 \n";
+
+
+    Matrix1D<double> v(3);
+	out << ".color " << rgb << std::endl;
+
+	for (unsigned long int ipix = 0; ipix < directions_angles.size(); ipix++)
+	{
+		Euler_angles2direction(XX(directions_angles[ipix]), YY(directions_angles[ipix]), v);
+		out <<  ".sphere " << XX(v) << " " << YY(v) << " " << ZZ(v) <<  floatToString(size) << std::endl;
+	}
+
+	out.close();
+
+}
+
+void HealpixSampling::writeNonZeroPriorOrientationsToBild(FileName fn_bild, double rot_prior, double tilt_prior, std::string rgb, double size)
+{
+    std::ofstream out;
+    out.open (fn_bild.c_str());
+    if (!out)
+        REPORT_ERROR( (std::string)"HealpixSampling::writeNonZeroOrientationsToBild: Cannot write file: " + fn_bild);
+
+
+    out << ".color 1 0 0 \n";
+    out << ".arrow 0 0 0 1 0 0 0.01 \n";
+    out << ".color 0 1 0 \n";
+    out << ".arrow 0 0 0  0 1 0 0.01 \n";
+    out << ".color 0 0 1 \n";
+    out << ".arrow 0 0 0 0 0 1 0.01 \n";
+
+    Matrix1D<double> v(3);
+
+	Euler_angles2direction(rot_prior, tilt_prior, v);
+	out << ".color 0 0 0 \n";
+	out <<  ".sphere " << XX(v) << " " << YY(v) << " " << ZZ(v) <<  floatToString(size) << std::endl;
+
+	out << ".color " << rgb << std::endl;
+	for (unsigned long int ipix = 0; ipix < pointer_dir_nonzeroprior.size(); ipix++)
+	{
+		long int idir = pointer_dir_nonzeroprior[ipix];
+		Euler_angles2direction(XX(directions_angles[idir]), YY(directions_angles[idir]), v);
+		out <<  ".sphere " << XX(v) << " " << YY(v) << " " << ZZ(v) <<  floatToString(size) << std::endl;
+	}
+
+	out.close();
+
+}
+
+void HealpixSampling::selectOrientationsWithNonZeroPriorProbability(
+		double prior_rot, double prior_tilt, double prior_psi,
+		double sigma_rot, double sigma_tilt, double sigma_psi,
+		double sigma_cutoff)
+{
+	pointer_dir_nonzeroprior.clear();
+	directions_prior.clear();
+
+	if (is_3D)
+	{
+
+		// Loop over all directions
+		double sumprior = 0.;
+		// Keep track of the closest distance to prevent 0 orientations
+		double best_ang = 9999.;
+		long int best_idir = -999;
+		for (long int idir = 0; idir < directions_angles.size(); idir++)
+		{
+
+			// Any prior involving rot and/or tilt.
+			if (sigma_rot > 0. || sigma_tilt > 0. )
+			{
+
+				Matrix1D<double> prior_direction, my_direction, sym_direction, best_direction;
+				// Get the direction of the prior
+				Euler_angles2direction(prior_rot, prior_tilt, prior_direction);
+
+				// Get the current direction in the loop
+				Euler_angles2direction(XX(directions_angles[idir]), YY(directions_angles[idir]), my_direction);
+
+				// Loop over all symmetry operators to find the operator that brings this direction nearest to the prior
+				double best_dotProduct = dotProduct(prior_direction, my_direction);
+				best_direction = my_direction;
+				for (int j = 0; j < R_repository.size(); j++)
+				{
+					sym_direction =  L_repository[j] * (my_direction.transpose() * R_repository[j]).transpose();
+					double my_dotProduct = dotProduct(prior_direction, sym_direction);
+					if (my_dotProduct > best_dotProduct)
+					{
+						best_direction = sym_direction;
+						best_dotProduct = my_dotProduct;
+					}
+				}
+
+				if (sigma_rot > 0. && sigma_tilt > 0.)
+				{
+
+					double diffang = ACOSD( dotProduct(best_direction, prior_direction) );
+					if (diffang > 180.) diffang = ABS(diffang - 360.);
+
+					// Only consider differences within sigma_cutoff * sigma_rot
+					if (diffang < sigma_cutoff * sigma_rot)
+					{
+						// TODO!!! If tilt is zero then any rot will be OK!!!!!
+						double prior = gaussian1D(diffang, sigma_rot, 0.);
+						pointer_dir_nonzeroprior.push_back(idir);
+						directions_prior.push_back(prior);
+						sumprior += prior;
+					}
+
+					// Keep track of the nearest direction
+					if (diffang < best_ang)
+					{
+						best_idir = idir;
+						best_ang = diffang;
+					}
+				}
+				else if (sigma_rot > 0.)
+				{
+					double best_rot, best_tilt;
+
+					Euler_direction2angles(best_direction, best_rot, best_tilt);
+					double diffrot = ABS(best_rot - prior_rot);
+					if (diffrot > 180.) diffrot = ABS(diffrot - 360.);
+
+					// Only consider differences within sigma_cutoff * sigma_rot
+					if (diffrot < sigma_cutoff * sigma_rot)
+					{
+						double prior = gaussian1D(diffrot, sigma_rot, 0.);
+						pointer_dir_nonzeroprior.push_back(idir);
+						directions_prior.push_back(prior);
+						sumprior += prior;
+					}
+
+					// Keep track of the nearest direction
+					if (diffrot < best_ang)
+					{
+						best_idir = idir;
+						best_ang = diffrot;
+					}
+
+				}
+				else if (sigma_tilt > 0.)
+				{
+
+					double best_rot, best_tilt;
+
+					Euler_direction2angles(best_direction, best_rot, best_tilt);
+					double difftilt = ABS(best_tilt - prior_tilt);
+					if (difftilt > 180.) difftilt = ABS(difftilt - 360.);
+
+					// Only consider differences within sigma_cutoff * sigma_tilt
+					if (difftilt < sigma_cutoff * sigma_tilt)
+					{
+						double prior = gaussian1D(difftilt, sigma_tilt, 0.);
+						pointer_dir_nonzeroprior.push_back(idir);
+						directions_prior.push_back(prior);
+						sumprior += prior;
+					}
+
+					// Keep track of the nearest direction
+					if (difftilt < best_ang)
+					{
+						best_idir = idir;
+						best_ang = difftilt;
+					}
+
+				}
+
+			} // end if any prior involving rot and/or tilt
+			else
+			{
+				// If no prior on the directions: just add all of them
+				pointer_dir_nonzeroprior.push_back(idir);
+				directions_prior.push_back(1.);
+				sumprior += 1.;
+			}
+
+		} // end for idir
+
+
+		//Normalise the prior probability distribution to have sum 1 over all psi-angles
+		for (long int idir = 0; idir < directions_prior.size(); idir++)
+			directions_prior[idir] /= sumprior;
+
+		// If there were no directions at all, just select the single nearest one:
+		if (directions_prior.size() == 0)
+		{
+			if (best_idir < 0)
+				REPORT_ERROR("HealpixSampling::selectOrientationsWithNonZeroPriorProbability BUG: best_idir < 0");
+			pointer_dir_nonzeroprior.push_back(best_idir);
+			directions_prior.push_back(1.);
+		}
+
+#ifdef  DEBUG_SAMPLING
+		writeNonZeroPriorOrientationsToBild("orients_local.bild", prior_rot, prior_tilt, "0 0 1", 0.023);
+		std::cerr << " directions_prior.size()= " << directions_prior.size() << " pointer_dir_nonzeroprior.size()= " << pointer_dir_nonzeroprior.size() << std::endl;
+		std::cerr << " sumprior= " << sumprior << std::endl;
+		char c;
+		std::cerr << "Written orients_local.bild for prior on angles ("<<prior_rot<<","<<prior_tilt<<") Press any key to continue.." << std::endl;
+		std::cin >> c;
+#endif
+
+
+	}
+	else
+	{
+		pointer_dir_nonzeroprior.push_back(0);
+		directions_prior.push_back(1.);
+	}
+
+
+	// Psi-angles
+	pointer_psi_nonzeroprior.clear();
+	psi_prior.clear();
+
+	double sumprior = 0.;
+	double best_diff = 9999.;
+	long int best_ipsi = -999;
+	for (long int ipsi = 0; ipsi < psi_angles.size(); ipsi++)
+	{
+		if (sigma_psi > 0.)
+		{
+			double diffpsi = ABS(psi_angles[ipsi] - prior_psi);
+			if (diffpsi > 180.) diffpsi = ABS(diffpsi - 360.);
+
+			// Only consider differences within sigma_cutoff * sigma_psi
+			if (diffpsi < sigma_cutoff * sigma_psi)
+			{
+				double prior = gaussian1D(diffpsi, sigma_psi, 0.);
+				pointer_psi_nonzeroprior.push_back(ipsi);
+				psi_prior.push_back(prior);
+				sumprior += prior;
+
+				// TMP DEBUGGING
+				if (prior == 0.)
+				{
+					std::cerr << " psi_angles[ipsi]= " << psi_angles[ipsi] << " prior_psi= " << prior_psi << " orientational_prior_mode= " << orientational_prior_mode << std::endl;
+					std::cerr << " diffpsi= " << diffpsi << " sigma_cutoff= " << sigma_cutoff << " sigma_psi= " << sigma_psi << std::endl;
+					REPORT_ERROR("prior on psi is zero!");
+				}
+
+			}
+			// Keep track of the nearest sampling point
+			if (diffpsi < best_diff)
+			{
+				best_ipsi = ipsi;
+				best_diff = diffpsi;
+			}
+		}
+		else
+		{
+			pointer_psi_nonzeroprior.push_back(ipsi);
+			psi_prior.push_back(1.);
+			sumprior += 1.;
+		}
+	}
+	// Normalise the prior probability distribution to have sum 1 over all psi-angles
+	for (long int ipsi = 0; ipsi < psi_prior.size(); ipsi++)
+		psi_prior[ipsi] /= sumprior;
+
+	// If there were no directions at all, just select the single nearest one:
+	if (psi_prior.size() == 0)
+	{
+		if (best_ipsi < 0)
+			REPORT_ERROR("HealpixSampling::selectOrientationsWithNonZeroPriorProbability BUG: best_ipsi < 0");
+		pointer_psi_nonzeroprior.push_back(best_ipsi);
+		psi_prior.push_back(1.);
+	}
+
+
+#ifdef  DEBUG_SAMPLING
+	std::cerr << " psi_angles.size()= " << psi_angles.size() << " psi_step= " << psi_step << std::endl;
+	std::cerr << " psi_prior.size()= " << psi_prior.size() << " pointer_psi_nonzeroprior.size()= " << pointer_psi_nonzeroprior.size() << " sumprior= " << sumprior << std::endl;
+#endif
+
+
+}
+
+void HealpixSampling::randomSelectionNonZeroPriorProbability(double fraction_to_keep)
+{
+
+    // If we had not yet determined the prior probability vectors, just fill them with an even distribution
+    if (is_3D)
+    {
+		if (directions_prior.size() == 0)
+		{
+			for (long int idir = 0; idir < directions_angles.size(); idir++)
+			{
+				pointer_dir_nonzeroprior.push_back(idir);
+				directions_prior.push_back(1.);
+			} // this will be re-normalised below!
+		}
+    }
+    if (psi_prior.size() == 0)
+    {
+    	for (long int ipsi = 0; ipsi < psi_angles.size(); ipsi++)
+		{
+			pointer_psi_nonzeroprior.push_back(ipsi);
+			psi_prior.push_back(1.);
+		} // this will be re-normalised below!
+    }
+
+
+
+	// Act on directions
+    double sum_prior;
+    if (is_3D)
+    {
+		std::vector<double> copy_directions_prior;
+		std::vector<int> copy_pointer_dir_nonzeroprior;
+		sum_prior = 0.;
+		for (long int i = 0; i < directions_prior.size(); i++)
+		{
+			double aux = rnd_unif();
+			if (aux < fraction_to_keep)
+			{
+				copy_directions_prior.push_back(directions_prior[i]);
+				copy_pointer_dir_nonzeroprior.push_back(pointer_dir_nonzeroprior[i]);
+				sum_prior += directions_prior[i];
+			}
+		}
+		directions_prior = copy_directions_prior;
+		pointer_dir_nonzeroprior = copy_pointer_dir_nonzeroprior;
+		// renormalise
+		for (long int idir = 0; idir < directions_prior.size(); idir++)
+			directions_prior[idir] /= sum_prior;
+    }
+
+    // And act on psi-angles
+    std::vector<double> copy_psi_prior;
+    std::vector<int> copy_pointer_psi_nonzeroprior;
+    sum_prior = 0.;
+    for (long int i = 0; i < psi_prior.size(); i++)
+    {
+		double aux = rnd_unif();
+		if (aux < fraction_to_keep)
+    	{
+    		copy_psi_prior.push_back(psi_prior[i]);
+    		copy_pointer_psi_nonzeroprior.push_back(pointer_psi_nonzeroprior[i]);
+    		sum_prior += psi_prior[i];
+    	}
+    }
+    psi_prior = copy_psi_prior;
+    pointer_psi_nonzeroprior = copy_pointer_psi_nonzeroprior;
+    // renormalise
+    for (long int ipsi = 0; ipsi < psi_prior.size(); ipsi++)
+		psi_prior[ipsi] /= sum_prior;
+
+}
+
+
+FileName HealpixSampling::symmetryGroup()
+{
+	return fn_sym;
+}
+
+long int HealpixSampling::getHealPixIndex(long int idir)
+{
+#ifdef DEBUG_CHECKSIZES
+	if (idir >= directions_ipix.size())
+	{
+		std::cerr<< "idir= "<<idir<<" directions_ipix.size()= "<< directions_ipix.size() <<std::endl;
+		REPORT_ERROR("idir >= directions_ipix.size()");
+	}
+#endif
+	return directions_ipix[idir];
+}
+
+void HealpixSampling::checkDirection(double &rot, double &tilt)
+{
+
+	// The geometrical considerations about the symmetry below require that rot = [-180,180] and tilt [0,180]
+
+	// The following was incorrect?!
+	if (tilt < 0.)
+	{
+		tilt = -tilt;
+		rot += 180.;
+	}
+
+	bool is_ok = false;
+	while (!is_ok)
+	{
+		if (rot > 180.)
+			rot -= 360.;
+		else if (rot < -180.)
+			rot += 360.;
+		else
+			is_ok = true;
+	}
+
+}
+
+void HealpixSampling::getDirectionFromHealPix(long int ipix, double &rot, double &tilt)
+{
+	double zz, phi;
+	healpix_base.pix2ang_z_phi(ipix, zz, phi);
+	rot = RAD2DEG(phi);
+	tilt = ACOSD(zz);
+
+	// The geometrical considerations about the symmetry below require that rot = [-180,180] and tilt [0,180]
+	checkDirection(rot, tilt);
+
+}
+
+double HealpixSampling::getTranslationalSampling(int adaptive_oversampling)
+{
+	return offset_step / std::pow(2., adaptive_oversampling);
+}
+
+double HealpixSampling::getAngularSampling(int adaptive_oversampling)
+{
+	if (is_3D)
+	{
+		int order =  healpix_order + adaptive_oversampling;
+		return 360. / (6 * ROUND(std::pow(2., order)));
+	}
+	else
+		return psi_step / std::pow(2., adaptive_oversampling);
+}
+
+long int HealpixSampling::NrDirections(int oversampling_order, bool include_zeroprior)
+{
+	long int mysize = (orientational_prior_mode == NOPRIOR || include_zeroprior) ? directions_angles.size() : pointer_dir_nonzeroprior.size();
+	if (oversampling_order == 0)
+		return mysize;
+	else
+		return ROUND(std::pow(2., oversampling_order * 2)) * mysize;
+}
+
+long int HealpixSampling::NrPsiSamplings(int oversampling_order, bool include_zeroprior)
+{
+
+	long int mysize = (orientational_prior_mode == NOPRIOR || include_zeroprior) ? psi_angles.size() : pointer_psi_nonzeroprior.size();
+	if (oversampling_order == 0)
+		return mysize;
+	else
+		return ROUND(std::pow(2., oversampling_order)) * mysize;
+}
+
+long int HealpixSampling::NrTranslationalSamplings(int oversampling_order)
+{
+	if (oversampling_order == 0)
+		return translations.size();
+	else
+	{
+		if (is_3d_trans)
+			return ROUND(std::pow(2., oversampling_order * 3)) * translations.size();
+		else
+			return ROUND(std::pow(2., oversampling_order * 2)) * translations.size();
+	}
+}
+
+long int HealpixSampling::NrSamplingPoints(int oversampling_order, bool include_zeroprior)
+{
+	return NrDirections(oversampling_order, include_zeroprior) *
+		   NrPsiSamplings(oversampling_order, include_zeroprior) *
+		   NrTranslationalSamplings(oversampling_order);
+}
+
+/* How often is each orientation oversampled? */
+int HealpixSampling::oversamplingFactorOrientations(int oversampling_order)
+{
+	if (is_3D)
+		return ROUND(std::pow(2., oversampling_order * 3));
+	else
+		return ROUND(std::pow(2., oversampling_order));
+}
+
+/* How often is each translation oversampled? */
+int HealpixSampling::oversamplingFactorTranslations(int oversampling_order)
+{
+	if (is_3d_trans)
+		return ROUND(std::pow(2., oversampling_order * 3));
+	else
+		return ROUND(std::pow(2., oversampling_order * 2));
+}
+
+
+void HealpixSampling::getDirection(long int idir, double &rot, double &tilt)
+{
+#ifdef DEBUG_CHECKSIZES
+	if (idir >= directions_angles.size())
+	{
+		std::cerr<< "idir= "<<idir<<" directions_angles.size()= "<< directions_angles.size() <<std::endl;
+		REPORT_ERROR("idir >= directions_angles.size()");
+	}
+#endif
+
+	rot  = XX(directions_angles[idir]);
+	tilt = YY(directions_angles[idir]);
+}
+
+void HealpixSampling::getPsiAngle(long int ipsi, double &psi)
+{
+#ifdef DEBUG_CHECKSIZES
+	if (ipsi >= psi_angles.size())
+	{
+		std::cerr<< "ipsi= "<<ipsi<<" psi_angles.size()= "<< psi_angles.size() <<std::endl;
+		REPORT_ERROR("ipsi >= psi_angles.size()");
+	}
+#endif
+	psi = psi_angles[ipsi];
+}
+
+void HealpixSampling::getTranslation(long int itrans, Matrix1D<double> &trans)
+{
+#ifdef DEBUG_CHECKSIZES
+if (itrans >= translations.size())
+{
+	std::cerr<< "itrans= "<<itrans<<" translations.size()= "<< translations.size() <<std::endl;
+	REPORT_ERROR("itrans >= translations.size()");
+}
+#endif
+	trans = translations[itrans];
+}
+
+long int HealpixSampling::getPositionSamplingPoint(int iclass, long int idir, long int ipsi, long int itrans)
+{
+	return iclass * directions_angles.size() * psi_angles.size() * translations.size()
+		+ idir * psi_angles.size() * translations.size()
+		+ ipsi * translations.size() + itrans;
+}
+
+long int HealpixSampling::getPositionOversampledSamplingPoint(long int ipos, int oversampling_order, int iover_rot, int iover_trans)
+{
+	if (oversampling_order == 0)
+		return ipos;
+	else
+	{
+		int nr_over_orient = oversamplingFactorOrientations(oversampling_order);
+		int nr_over_trans = oversamplingFactorTranslations(oversampling_order);
+		return ipos * nr_over_orient * nr_over_trans + nr_over_trans * iover_rot + iover_trans;
+	}
+
+}
+
+void HealpixSampling::getTranslations(long int itrans, int oversampling_order,
+		std::vector<Matrix1D<double> > &my_translations)
+{
+
+#ifdef DEBUG_CHECKSIZES
+	if (itrans >= translations.size())
+	{
+		std::cerr<< "itrans= "<<itrans<<" translations.size()= "<< translations.size() <<std::endl;
+		REPORT_ERROR("itrans >= translations.size()");
+	}
+#endif
+	my_translations.clear();
+	if (oversampling_order == 0)
+	{
+		my_translations.push_back(translations[itrans]);
+	}
+	else
+	{
+		int nr_oversamples = ROUND(std::pow(2., oversampling_order));
+
+		for (int itrans_overy = 0; itrans_overy < nr_oversamples; itrans_overy++)
+		{
+			double over_yoff = YY(translations[itrans]) - 0.5 * offset_step + (0.5 + itrans_overy) * offset_step / nr_oversamples;
+			for (int itrans_overx = 0; itrans_overx < nr_oversamples; itrans_overx++)
+			{
+				double over_xoff = XX(translations[itrans]) - 0.5 * offset_step + (0.5 + itrans_overx) * offset_step / nr_oversamples;
+				if (is_3d_trans)
+				{
+					for (int itrans_overz = 0; itrans_overz < nr_oversamples; itrans_overz++)
+					{
+						double over_zoff = ZZ(translations[itrans]) - 0.5 * offset_step + (0.5 + itrans_overz) * offset_step / nr_oversamples;
+						my_translations.push_back(vectorR3(over_xoff, over_yoff, over_zoff));
+					}
+				}
+				else
+				{
+					my_translations.push_back(vectorR2(over_xoff, over_yoff));
+				}
+			}
+		}
+	}
+
+	if (ABS(random_perturbation) > 0.)
+	{
+		double myperturb = random_perturbation * offset_step;
+		for (int iover = 0; iover < my_translations.size(); iover++)
+		{
+			XX(my_translations[iover]) += myperturb;
+			YY(my_translations[iover]) += myperturb;
+			if (is_3d_trans)
+				ZZ(my_translations[iover]) += myperturb;
+		}
+	}
+
+}
+
+void HealpixSampling::getOrientations(long int idir, long int ipsi, int oversampling_order,
+		std::vector<Matrix1D<double> > &my_orientations)
+{
+	my_orientations.clear();
+	long int my_idir, my_ipsi;
+	if (orientational_prior_mode == NOPRIOR)
+	{
+		my_idir = idir;
+		my_ipsi = ipsi;
+	}
+	else
+	{
+#ifdef DEBUG_CHECKSIZES
+	if (idir >= pointer_dir_nonzeroprior.size())
+	{
+		std::cerr<< "idir= "<<idir<<" pointer_dir_nonzeroprior.size()= "<< pointer_dir_nonzeroprior.size() <<std::endl;
+		REPORT_ERROR("idir >= pointer_dir_nonzeroprior.size()");
+	}
+	if (ipsi >= pointer_psi_nonzeroprior.size())
+	{
+		std::cerr<< "ipsi= "<<ipsi<<" pointer_psi_nonzeroprior.size()= "<< pointer_psi_nonzeroprior.size() <<std::endl;
+		REPORT_ERROR("ipsi >= pointer_psi_nonzeroprior.size()");
+	}
+#endif
+		my_idir = pointer_dir_nonzeroprior[idir];
+		my_ipsi = pointer_psi_nonzeroprior[ipsi];
+	}
+
+#ifdef DEBUG_CHECKSIZES
+		if (my_idir >= directions_angles.size())
+		{
+			std::cerr<< "my_idir= "<<my_idir<<" directions_angles.size()= "<< directions_angles.size() <<std::endl;
+			REPORT_ERROR("my_idir >= directions_angles.size()");
+		}
+		if (my_ipsi >= psi_angles.size())
+		{
+			std::cerr<< "my_ipsi= "<<my_ipsi<<" psi_angles.size()= "<< psi_angles.size() <<std::endl;
+			REPORT_ERROR("my_ipsi >= psi_angles.size()");
+		}
+#endif
+
+	if (oversampling_order == 0)
+	{
+		my_orientations.push_back(vectorR3(XX(directions_angles[my_idir]),
+										   YY(directions_angles[my_idir]),
+										   psi_angles[my_ipsi]));
+	}
+	else if (!is_3D)
+	{
+		// for 2D sampling, only push back oversampled psi rotations
+		pushbackOversampledPsiAngles(my_ipsi, oversampling_order, 0., 0., my_orientations);
+	}
+	else
+	{
+		// Set up oversampled grid for 3D sampling
+		Healpix_Base HealPixOver(oversampling_order + healpix_order, NEST);
+		int fact = HealPixOver.Nside()/healpix_base.Nside();
+		int x, y, face;
+		double rot, tilt;
+		// Get x, y and face for the original, coarse grid
+		long int ipix = directions_ipix[my_idir];
+		healpix_base.nest2xyf(ipix, x, y, face);
+		// Loop over the oversampled Healpix pixels on the fine grid
+		for (int j = fact * y; j < fact * (y+1); ++j)
+		{
+			for (int i = fact * x; i < fact * (x+1); ++i)
+			{
+				long int overpix = HealPixOver.xyf2nest(i, j, face);
+				double zz, phi;
+				HealPixOver.pix2ang_z_phi(overpix, zz, phi);
+				rot = RAD2DEG(phi);
+				tilt = ACOSD(zz);
+
+				// The geometrical considerations about the symmetry below require that rot = [-180,180] and tilt [0,180]
+				checkDirection(rot, tilt);
+
+				pushbackOversampledPsiAngles(my_ipsi, oversampling_order, rot, tilt, my_orientations);
+			}
+		}
+	}
+
+
+	// Random perturbation
+	if (ABS(random_perturbation) > 0.)
+	{
+		double myperturb = random_perturbation * getAngularSampling();
+		for (int iover = 0; iover < my_orientations.size(); iover++)
+		{
+			if (is_3D)
+			{
+				Matrix2D<double> A, R;
+				Euler_angles2matrix(XX(my_orientations[iover]),
+									YY(my_orientations[iover]),
+									ZZ(my_orientations[iover]),
+									A);
+				Euler_angles2matrix(myperturb, myperturb, myperturb, R);
+				A = A * R;
+				Euler_matrix2angles(A,
+									XX(my_orientations[iover]),
+									YY(my_orientations[iover]),
+									ZZ(my_orientations[iover]));
+			}
+			else
+			{
+				ZZ(my_orientations[iover]) += myperturb;
+			}
+		}
+	}
+
+
+
+}
+
+double HealpixSampling::getPriorProbability(long int idir, long int ipsi)
+{
+
+#ifdef DEBUG_CHECKSIZES
+	if (idir >= directions_prior.size())
+	{
+		std::cerr<< "idir= "<<idir<<" directions_prior.size()= "<< directions_prior.size() <<std::endl;
+		REPORT_ERROR("idir >= directions_prior.size()");
+	}
+	if (ipsi >= psi_prior.size())
+	{
+		std::cerr<< "ipsi= "<<ipsi<<" psi_prior.size()= "<< psi_prior.size() <<std::endl;
+		REPORT_ERROR("ipsi >= psi_prior.size()");
+	}
+#endif
+	return directions_prior[idir] * psi_prior[ipsi];
+}
+
+
+long int HealpixSampling::getDirectionNumberAlsoZeroPrior(long int idir)
+{
+#ifdef DEBUG_CHECKSIZES
+	if (idir >= pointer_dir_nonzeroprior.size())
+	{
+		std::cerr<< "idir= "<<idir<<" pointer_dir_nonzeroprior.size()= "<< pointer_dir_nonzeroprior.size() <<std::endl;
+		REPORT_ERROR("idir >= pointer_dir_nonzeroprior.size()");
+	}
+#endif
+	return pointer_dir_nonzeroprior[idir];
+}
+
+long int HealpixSampling::getPsiNumberAlsoZeroPrior(long int ipsi)
+{
+#ifdef DEBUG_CHECKSIZES
+	if (ipsi >= pointer_psi_nonzeroprior.size())
+	{
+		std::cerr<< "ipsi= "<<ipsi<<" pointer_psi_nonzeroprior.size()= "<< pointer_psi_nonzeroprior.size() <<std::endl;
+		REPORT_ERROR("ipsi >= pointer_psi_nonzeroprior.size()");
+	}
+#endif
+
+	return pointer_psi_nonzeroprior[ipsi];
+}
+
+void HealpixSampling::pushbackOversampledPsiAngles(long int ipsi, int oversampling_order,
+		double rot, double tilt, std::vector<Matrix1D<double> > &oversampled_orientations)
+{
+
+	if (oversampling_order == 0)
+	{
+		oversampled_orientations.push_back(vectorR3(rot, tilt, psi_angles[ipsi]));
+	}
+	else
+	{
+		int nr_ipsi_over = ROUND(std::pow(2., oversampling_order));
+		for (int ipsi_over = 0; ipsi_over < nr_ipsi_over; ipsi_over++)
+		{
+			double overpsi = psi_angles[ipsi] - 0.5 * psi_step + (0.5 + ipsi_over) * psi_step / nr_ipsi_over;
+			oversampled_orientations.push_back(vectorR3(rot, tilt, overpsi));
+		}
+	}
+
+}
+
+/* Calculate an angular distance between two sets of Euler angles */
+double HealpixSampling::calculateAngularDistance(double rot1, double tilt1, double psi1,
+		double rot2, double tilt2, double psi2)
+{
+	Matrix1D<double>  direction1(3), direction1p(3), direction2(3);
+	Euler_angles2direction(rot1, tilt1, direction1);
+	Euler_angles2direction(rot2, tilt2, direction2);
+
+	// Find the symmetry operation where the Distance based on Euler axes is minimal
+	double min_axes_dist = 3600.;
+	double rot2p, tilt2p, psi2p;
+	Matrix2D<double> E1, E2;
+	Matrix1D<double> v1, v2;
+	for (int j = 0; j < R_repository.size(); j++)
+	{
+
+        Euler_apply_transf(L_repository[j], R_repository[j], rot2, tilt2, psi2, rot2p, tilt2p, psi2p);
+
+	    // Distance based on Euler axes
+	    Euler_angles2matrix(rot1, tilt1, psi1, E1);
+	    Euler_angles2matrix(rot2p, tilt2p, psi2p, E2);
+	    double axes_dist = 0;
+	    for (int i = 0; i < 3; i++)
+	    {
+	        E1.getRow(i, v1);
+	        E2.getRow(i, v2);
+	        axes_dist += ACOSD(CLIP(dotProduct(v1, v2), -1., 1.));
+	    }
+	    axes_dist /= 3.;
+
+	    if (axes_dist < min_axes_dist)
+	    	min_axes_dist = axes_dist;
+
+	}// for all symmetry operations j
+
+	return min_axes_dist;
+}
+
+void HealpixSampling::writeBildFileOrientationalDistribution(MultidimArray<double> &pdf_direction,
+		FileName &fn_bild, double R, double offset, double Rmax_frac, double width_frac)
+{
+	if (!is_3D)
+		return;
+
+	if (XSIZE(pdf_direction) != directions_angles.size())
+		REPORT_ERROR("HealpixSampling::writeBildFileOrientationalDistribution XSIZE(pdf_direction) != directions_angles.size()!");
+
+
+	double pdfmax, pdfmin, pdfmean, pdfsigma;
+	pdf_direction.computeStats(pdfmean, pdfsigma, pdfmin, pdfmax);
+
+	std::ofstream fh_bild;
+    fh_bild.open(fn_bild.c_str(), std::ios::out);
+    if (!fh_bild)
+    	REPORT_ERROR("HealpixSampling::writeBildFileOrientationalDistribution: cannot open " + fn_bild);
+
+    // 2 * PI * R = 360 degrees, 2*radius should cover angular sampling at width_frac=1
+    double width = width_frac * PI*R*(getAngularSampling()/360.);
+    Matrix1D<double> v(3);
+
+    for (long int iang = 0; iang < directions_angles.size(); iang++)
+    {
+     	double pdf = DIRECT_A1D_ELEM(pdf_direction, iang);
+
+     	// Don't make a cylinder for pdf==0
+     	if (pdf > 0.)
+     	{
+			// Colour from blue to red according to deviations from sigma_pdf
+			double colscale = (pdf - pdfmean) / pdfsigma;
+			colscale = XMIPP_MIN(colscale, 5.);
+			colscale = XMIPP_MAX(colscale, -1.);
+			colscale /= 6.;
+			colscale += 1./6.; // colscale ranges from 0 (-5 sigma) to 1 (+5 sigma)
+
+			// The length of the cylinder will depend on the pdf_direction
+			double Rp = R + Rmax_frac * R * pdf / pdfmax;
+
+			Euler_angles2direction(XX(directions_angles[iang]), YY(directions_angles[iang]), v);
+
+			// Don't include cylinders with zero length, as chimera will complain about that....
+			if (ABS((R - Rp) * XX(v)) > 0.01 ||
+					ABS((R - Rp) * YY(v)) > 0.01 ||
+					ABS((R - Rp) * ZZ(v)) > 0.01)
+			{
+				// The width of the cylinders will be determined by the sampling:
+				fh_bild << ".color " << colscale << " 0 " << 1. - colscale << std::endl;
+				fh_bild << ".cylinder "
+						<< R  * XX(v) + offset << " "
+						<< R  * YY(v) + offset << " "
+						<< R  * ZZ(v) + offset << " "
+						<< Rp * XX(v) + offset << " "
+						<< Rp * YY(v) + offset << " "
+						<< Rp * ZZ(v) + offset << " "
+						<< width
+						<<"\n";
+			}
+     	}
+
+    }
+
+    // Close and write file to disc
+    fh_bild.close();
+
+}
+
+
+///////// PRIVATE STUFF
+
+void HealpixSampling::removePointsOutsideLimitedTiltAngles()
+{
+
+    if (ABS(limit_tilt) < 90.)
+    {
+    	std::vector<Matrix1D<double> > pruned_directions_angles;
+		std::vector<int>               pruned_directions_ipix;
+		pruned_directions_angles.clear();
+		pruned_directions_ipix.clear();
+
+		for (long int i = 0; i < directions_angles.size(); i++)
+		{
+			double tilt = YY(directions_angles[i]);
+			// Let tilt angle range from -90 to 90.
+			if (tilt > 90.) tilt -= 180.;
+
+			// Keep side views || keep top views
+			if ( (limit_tilt > 0. && ABS(tilt) >= ABS(limit_tilt)) || (limit_tilt < 0. && ABS(tilt) <= ABS(limit_tilt)) )
+			{
+				pruned_directions_angles.push_back(directions_angles[i]);
+				pruned_directions_ipix.push_back(directions_ipix[i]);
+			}
+		}
+		directions_angles = pruned_directions_angles;
+		directions_ipix   = pruned_directions_ipix;
+    }
+
+}
+
+
+// The way symmetry is handled was copied from Xmipp.
+// The original disclaimer is copied below
+/***************************************************************************
+ *
+ * Authors:     Roberto Marabini
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+void HealpixSampling::removeSymmetryEquivalentPoints(double max_ang)
+{
+    // Maximum distance
+    double cos_max_ang = cos(DEG2RAD(max_ang));
+    double my_dotProduct;
+    Matrix1D<double>  direction(3), direction1(3);
+    std::vector<Matrix1D<double> > directions_vector;
+
+    // Calculate all vectors and fill directions_vector
+    for (long int i = 0; i < directions_angles.size(); i++)
+    {
+    	Euler_angles2direction(XX(directions_angles[i]), YY(directions_angles[i]), direction);
+    	directions_vector.push_back(direction);
+    }
+
+    // First call to conventional remove_redundant_points
+    removeSymmetryEquivalentPointsGeometric(pgGroup, pgOrder, directions_vector);
+
+#ifdef  DEBUG_SAMPLING
+    writeAllOrientationsToBild("orients_sym0.bild", "0 1 0", 0.021);
+#endif
+
+	// Only correct the seams (i.e. the borders of the asymmetric units) for small numbers of directions
+    // For large numbers, the sampling is very fine and the probability distributions are probably delta functions anyway
+    // Large numbers take long times to calculate...
+    // Only a small fraction of the points at the border of the AU is thrown away anyway...
+    if (directions_angles.size() < 4000)
+    {
+    	// Create no_redundant vectors
+		std::vector <Matrix1D<double> > no_redundant_directions_vector;
+		std::vector <Matrix1D<double> > no_redundant_directions_angles;
+		std::vector <int> no_redundant_directions_ipix;
+
+		// Then check all points versus each other
+		for (long int i = 0; i < directions_angles.size(); i++)
+		{
+
+			//if (i%1000==0)
+			//	std::cerr << " i= " << i << " directions_angles.size()= " << directions_angles.size() << " no_redundant_directions_vector.size()= " << no_redundant_directions_vector.size() << std::endl;
+
+			//direction1=(sampling_point_vector[i]).transpose();
+			direction1=directions_vector[i];
+			bool uniq = true;
+
+			//for (long int k = 0; k < no_redundant_directions_vector.size(); k++)
+			// i is probably closer to latest additions: loop backwards over k....
+			for (long int k = no_redundant_directions_vector.size() -1; k >= 0; k--)
+			{
+				for (int j = 0; j < R_repository.size(); j++)
+				{
+					direction =  L_repository[j] *
+						(no_redundant_directions_vector[k].transpose() *
+						 R_repository[j]).transpose();
+					//Calculate distance
+					my_dotProduct = dotProduct(direction,direction1);
+					if (my_dotProduct > cos_max_ang)
+					{
+						uniq = false;
+						break;
+					}
+				}// for j
+				if (!uniq) break;
+			} // for k
+
+			if (uniq)
+			{
+				no_redundant_directions_vector.push_back(directions_vector[i]);
+				no_redundant_directions_angles.push_back(directions_angles[i]);
+				no_redundant_directions_ipix.push_back(directions_ipix[i]);
+			}
+		} // for i
+
+		// Now overwrite the directions_angles and directions_vectors with their no_redundant counterparts
+		directions_angles = no_redundant_directions_angles;
+		directions_ipix = no_redundant_directions_ipix;
+    }
+}
+
+void HealpixSampling::removeSymmetryEquivalentPointsGeometric(const int symmetry,
+        int sym_order, std::vector <Matrix1D<double> >  &directions_vector)
+{
+    Matrix2D<double>  L(4, 4), R(4, 4);
+    Matrix2D<double>  aux(3, 3);
+    Matrix1D<double>  row1(3), row2(3), row(3);
+
+    std::vector <Matrix1D<double> > no_redundant_directions_vector;
+    std::vector <Matrix1D<double> > no_redundant_directions_angles;
+    std::vector <int> no_redundant_directions_ipix;
+
+    double my_dotProduct;
+    if (symmetry == pg_CN)
+    {//OK
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (XX(directions_angles[i]) >= (-180. / sym_order) &&
+                XX(directions_angles[i]) <= (180. / sym_order))
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry == pg_CI  ||
+             symmetry == pg_CS )
+    {//OK
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (YY(directions_angles[i]) <= 90)
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_CNV )
+    {//OK
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (XX(directions_angles[i]) >=    0. / sym_order &&
+                XX(directions_angles[i]) <=  180. / sym_order)
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_CNH )
+    {//OK
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (XX(directions_angles[i]) >= -180. / sym_order &&
+                XX(directions_angles[i]) <=  180. / sym_order &&
+                YY(directions_angles[i]) <=    90.
+               )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_SN )
+    {//OK
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (XX(directions_angles[i]) >= -180.*2. / sym_order &&
+                XX(directions_angles[i]) <=  180.*2. / sym_order &&
+                YY(directions_angles[i]) <=    90.
+               )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_DN )
+    {
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (XX(directions_angles[i]) >= -180. / (sym_order) + 90. &&
+                XX(directions_angles[i]) <=  180. / (sym_order) + 90. &&
+                YY(directions_angles[i]) <=    90.
+               )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_DNV )
+    {
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (XX(directions_angles[i]) >=   90.  &&
+                XX(directions_angles[i]) <=  180. / (sym_order) + 90. &&
+                YY(directions_angles[i]) <=    90.
+               )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_DNH )
+    {
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (XX(directions_angles[i]) >=   90. &&
+                XX(directions_angles[i]) <=  180. / (sym_order) + 90. &&
+                YY(directions_angles[i]) <=   90.
+               )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_T )
+    {//OK
+        Matrix1D<double>  _3_fold_axis_1_by_3_fold_axis_2(3);
+        _3_fold_axis_1_by_3_fold_axis_2 = vectorR3(-0.942809, 0., 0.);
+        _3_fold_axis_1_by_3_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_2_by_3_fold_axis_3(3);
+        _3_fold_axis_2_by_3_fold_axis_3 = vectorR3(0.471405, 0.272165, 0.7698);
+        _3_fold_axis_2_by_3_fold_axis_3.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_3_by_3_fold_axis_1(3);
+        _3_fold_axis_3_by_3_fold_axis_1 = vectorR3(0.471404, 0.816497, 0.);
+        _3_fold_axis_3_by_3_fold_axis_1.selfNormalize();
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (XX(directions_angles[i]) >=     90. &&
+                XX(directions_angles[i]) <=   150. ||
+                XX(directions_angles[i]) ==     0
+               )
+                if (
+                    dotProduct(directions_vector[i], _3_fold_axis_1_by_3_fold_axis_2) >= 0 &&
+                    dotProduct(directions_vector[i], _3_fold_axis_2_by_3_fold_axis_3) >= 0 &&
+                    dotProduct(directions_vector[i], _3_fold_axis_3_by_3_fold_axis_1) >= 0
+                )
+                {
+                    no_redundant_directions_angles.push_back(directions_angles[i]);
+                    no_redundant_directions_vector.push_back(directions_vector[i]);
+                    no_redundant_directions_ipix.push_back(directions_ipix[i]);
+                }
+        }// for i
+    }
+    else if (symmetry  == pg_TD )
+    {//OK
+        Matrix1D<double>  _2_fold_axis_1_by_3_fold_axis_2(3);
+        _2_fold_axis_1_by_3_fold_axis_2 = vectorR3(-0.942809, 0., 0.);
+        _2_fold_axis_1_by_3_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_2_by_3_fold_axis_5(3);
+        _3_fold_axis_2_by_3_fold_axis_5 = vectorR3(0.471405, 0.272165, 0.7698);
+        _3_fold_axis_2_by_3_fold_axis_5.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_5_by_2_fold_axis_1(3);
+        _3_fold_axis_5_by_2_fold_axis_1 = vectorR3(0., 0.471405, -0.666667);
+        _3_fold_axis_5_by_2_fold_axis_1.selfNormalize();
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+//           if ( XX(directions_angles[i])>=     120. &&
+//                 XX(directions_angles[i])<=   150. ||
+//                 XX(directions_angles[i])==     0
+//              )
+            if (
+                dotProduct(directions_vector[i], _2_fold_axis_1_by_3_fold_axis_2) >= 0 &&
+                dotProduct(directions_vector[i], _3_fold_axis_2_by_3_fold_axis_5) >= 0 &&
+                dotProduct(directions_vector[i], _3_fold_axis_5_by_2_fold_axis_1) >= 0
+            )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_TH )
+    {//OK
+        Matrix1D<double>  _3_fold_axis_1_by_2_fold_axis_1(3);
+        _3_fold_axis_1_by_2_fold_axis_1 = vectorR3(-0.816496, 0., 0.);
+        _3_fold_axis_1_by_2_fold_axis_1.selfNormalize();
+        Matrix1D<double>  _2_fold_axis_1_by_2_fold_axis_2(3);
+        _2_fold_axis_1_by_2_fold_axis_2 = vectorR3(0.707107, 0.408248, -0.57735);
+        _2_fold_axis_1_by_2_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _2_fold_axis_2_by_3_fold_axis_1(3);
+        _2_fold_axis_2_by_3_fold_axis_1 = vectorR3(-0.408248, -0.707107, 0.);
+        _2_fold_axis_2_by_3_fold_axis_1.selfNormalize();
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+//           if ( XX(directions_angles[i])>=     120. &&
+//                 XX(directions_angles[i])<=   150. ||
+//                 XX(directions_angles[i])==     0
+//              )
+            if (
+                dotProduct(directions_vector[i], _3_fold_axis_1_by_2_fold_axis_1) >= 0 &&
+                dotProduct(directions_vector[i], _2_fold_axis_1_by_2_fold_axis_2) >= 0 &&
+                dotProduct(directions_vector[i], _2_fold_axis_2_by_3_fold_axis_1) >= 0
+            )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_O )
+    {//OK
+        Matrix1D<double>  _3_fold_axis_1_by_3_fold_axis_2(3);
+        _3_fold_axis_1_by_3_fold_axis_2 = vectorR3(0., -1., 1.);
+        _3_fold_axis_1_by_3_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_2_by_4_fold_axis(3);
+        _3_fold_axis_2_by_4_fold_axis = vectorR3(1., 1., 0.);
+        _3_fold_axis_2_by_4_fold_axis.selfNormalize();
+        Matrix1D<double>  _4_fold_axis_by_3_fold_axis_1(3);
+        _4_fold_axis_by_3_fold_axis_1 = vectorR3(-1., 1., 0.);
+        _4_fold_axis_by_3_fold_axis_1.selfNormalize();
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if ((XX(directions_angles[i]) >=   45. &&
+                 XX(directions_angles[i]) <=  135. &&
+                 YY(directions_angles[i]) <=  90.) ||
+                XX(directions_angles[i]) ==  0.
+               )
+                if (
+                    dotProduct(directions_vector[i], _3_fold_axis_1_by_3_fold_axis_2) >= 0 &&
+                    dotProduct(directions_vector[i], _3_fold_axis_2_by_4_fold_axis) >= 0 &&
+                    dotProduct(directions_vector[i], _4_fold_axis_by_3_fold_axis_1) >= 0
+                )
+                {
+                    no_redundant_directions_angles.push_back(directions_angles[i]);
+                    no_redundant_directions_vector.push_back(directions_vector[i]);
+                    no_redundant_directions_ipix.push_back(directions_ipix[i]);
+                }
+        }// for i
+    }
+    else if (symmetry  == pg_OH )
+    {//OK
+        Matrix1D<double>  _3_fold_axis_1_by_3_fold_axis_2(3);
+        _3_fold_axis_1_by_3_fold_axis_2 = vectorR3(0., -1., 1.);
+        _3_fold_axis_1_by_3_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_2_by_4_fold_axis(3);
+        _3_fold_axis_2_by_4_fold_axis = vectorR3(1., 1., 0.);
+        _3_fold_axis_2_by_4_fold_axis.selfNormalize();
+        Matrix1D<double>  _4_fold_axis_by_3_fold_axis_1(3);
+        _4_fold_axis_by_3_fold_axis_1 = vectorR3(-1., 1., 0.);
+        _4_fold_axis_by_3_fold_axis_1.selfNormalize();
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (XX(directions_angles[i]) >=   90. &&
+                XX(directions_angles[i]) <=  135. &&
+                YY(directions_angles[i]) <=  90.)
+                if (
+                    dotProduct(directions_vector[i], _3_fold_axis_1_by_3_fold_axis_2) >= 0 &&
+                    dotProduct(directions_vector[i], _3_fold_axis_2_by_4_fold_axis) >= 0 &&
+                    dotProduct(directions_vector[i], _4_fold_axis_by_3_fold_axis_1) >= 0
+                )
+                {
+                    no_redundant_directions_angles.push_back(directions_angles[i]);
+                    no_redundant_directions_vector.push_back(directions_vector[i]);
+                    no_redundant_directions_ipix.push_back(directions_ipix[i]);
+                }
+        }// for i
+    }
+    else if (symmetry  == pg_I || symmetry  == pg_I2)
+    {//OK
+        Matrix1D<double>  _5_fold_axis_1_by_5_fold_axis_2(3);
+        _5_fold_axis_1_by_5_fold_axis_2 = vectorR3(0., 1., 0.);
+        _5_fold_axis_1_by_5_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _5_fold_axis_2_by_3_fold_axis(3);
+        _5_fold_axis_2_by_3_fold_axis = vectorR3(-0.4999999839058737,
+                                                 -0.8090170074556163,
+                                                  0.3090169861701543);
+        _5_fold_axis_2_by_3_fold_axis.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_5_fold_axis_1(3);
+        _3_fold_axis_by_5_fold_axis_1 = vectorR3(0.4999999839058737,
+                                                -0.8090170074556163,
+                                                 0.3090169861701543);
+        _3_fold_axis_by_5_fold_axis_1.selfNormalize();
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (
+                    dotProduct(directions_vector[i], _5_fold_axis_1_by_5_fold_axis_2) >= 0 &&
+                    dotProduct(directions_vector[i], _5_fold_axis_2_by_3_fold_axis) >= 0 &&
+                    dotProduct(directions_vector[i], _3_fold_axis_by_5_fold_axis_1) >= 0
+               )
+                {
+                    no_redundant_directions_angles.push_back(directions_angles[i]);
+                    no_redundant_directions_vector.push_back(directions_vector[i]);
+                    no_redundant_directions_ipix.push_back(directions_ipix[i]);
+                }
+        }// for i
+    }
+    else if (symmetry  == pg_I1)
+    {//OK
+        Matrix2D<double>  A(3, 3);
+	    Euler_angles2matrix(0, 90, 0, A);
+        Matrix1D<double>  _5_fold_axis_1_by_5_fold_axis_2(3);
+        _5_fold_axis_1_by_5_fold_axis_2 = A * vectorR3(0., 1., 0.);
+        _5_fold_axis_1_by_5_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _5_fold_axis_2_by_3_fold_axis(3);
+        _5_fold_axis_2_by_3_fold_axis = A * vectorR3(-0.4999999839058737,
+                                                 -0.8090170074556163,
+                                                  0.3090169861701543);
+        _5_fold_axis_2_by_3_fold_axis.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_5_fold_axis_1(3);
+        _3_fold_axis_by_5_fold_axis_1 = A * vectorR3(0.4999999839058737,
+                                                -0.8090170074556163,
+                                                 0.3090169861701543);
+        _3_fold_axis_by_5_fold_axis_1.selfNormalize();
+
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (
+                    dotProduct(directions_vector[i], _5_fold_axis_1_by_5_fold_axis_2) >= 0 &&
+                    dotProduct(directions_vector[i], _5_fold_axis_2_by_3_fold_axis) >= 0 &&
+                    dotProduct(directions_vector[i], _3_fold_axis_by_5_fold_axis_1) >= 0
+            )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_I3)
+    {//OK
+        Matrix2D<double>  A(3, 3);
+	    Euler_angles2matrix(0,31.7174745559,0, A);
+        Matrix1D<double>  _5_fold_axis_1_by_5_fold_axis_2(3);
+        _5_fold_axis_1_by_5_fold_axis_2 = A * vectorR3(0., 1., 0.);
+        _5_fold_axis_1_by_5_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _5_fold_axis_2_by_3_fold_axis(3);
+        _5_fold_axis_2_by_3_fold_axis = A * vectorR3(-0.4999999839058737,
+                                                 -0.8090170074556163,
+                                                  0.3090169861701543);
+        _5_fold_axis_2_by_3_fold_axis.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_5_fold_axis_1(3);
+        _3_fold_axis_by_5_fold_axis_1 = A * vectorR3(0.4999999839058737,
+                                                -0.8090170074556163,
+                                                 0.3090169861701543);
+        _3_fold_axis_by_5_fold_axis_1.selfNormalize();
+
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (
+                    dotProduct(directions_vector[i], _5_fold_axis_1_by_5_fold_axis_2) >= 0 &&
+                    dotProduct(directions_vector[i], _5_fold_axis_2_by_3_fold_axis) >= 0 &&
+                    dotProduct(directions_vector[i], _3_fold_axis_by_5_fold_axis_1) >= 0
+            )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_I4)
+    {//OK
+        Matrix2D<double>  A(3, 3);
+	    Euler_angles2matrix(0,-31.7174745559,0, A);
+        Matrix1D<double>  _5_fold_axis_1_by_5_fold_axis_2(3);
+        _5_fold_axis_1_by_5_fold_axis_2 = A * vectorR3(0., 0., 1.);
+        _5_fold_axis_1_by_5_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _5_fold_axis_2_by_3_fold_axis(3);
+        _5_fold_axis_2_by_3_fold_axis = A * vectorR3(0.187592467856686,
+                                        -0.303530987314591,
+                                        -0.491123477863004);
+        _5_fold_axis_2_by_3_fold_axis.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_5_fold_axis_1(3);
+        _3_fold_axis_by_5_fold_axis_1 = A * vectorR3(0.187592467856686,
+                                        0.303530987314591,
+                                        -0.491123477863004);
+        _3_fold_axis_by_5_fold_axis_1.selfNormalize();
+
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (
+                dotProduct(directions_vector[i],
+		           _5_fold_axis_2_by_3_fold_axis)   <= 0 &&
+                dotProduct(directions_vector[i],
+		           _3_fold_axis_by_5_fold_axis_1)   <= 0 &&
+		dotProduct(directions_vector[i],
+		           _5_fold_axis_1_by_5_fold_axis_2) <= 0
+            )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_I5)
+    {//OK
+        std::cerr << "ERROR: Symmetry pg_I5 not implemented" << std::endl;
+        exit(0);
+    }
+    else if (symmetry  == pg_IH || symmetry  == pg_I2H)
+    {//OK
+        Matrix1D<double>  _5_fold_axis_1_by_5_fold_axis_2(3);
+        _5_fold_axis_1_by_5_fold_axis_2 = vectorR3(0., 1., 0.);
+        _5_fold_axis_1_by_5_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _5_fold_axis_2_by_3_fold_axis(3);
+        _5_fold_axis_2_by_3_fold_axis = vectorR3(-0.4999999839058737,
+                                                 -0.8090170074556163,
+                                                  0.3090169861701543);
+        _5_fold_axis_2_by_3_fold_axis.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_5_fold_axis_1(3);
+        _3_fold_axis_by_5_fold_axis_1 = vectorR3(0.4999999839058737,
+                                                -0.8090170074556163,
+                                                 0.3090169861701543);
+        _3_fold_axis_by_5_fold_axis_1.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_2_fold_axis(3);
+        _3_fold_axis_by_2_fold_axis =  vectorR3(1.,0.,0.);
+        _3_fold_axis_by_2_fold_axis.selfNormalize();
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (
+                    dotProduct(directions_vector[i], _5_fold_axis_1_by_5_fold_axis_2) >= 0 &&
+                    dotProduct(directions_vector[i], _5_fold_axis_2_by_3_fold_axis) >= 0 &&
+                    dotProduct(directions_vector[i], _3_fold_axis_by_2_fold_axis) >= 0
+               )
+                {
+                    no_redundant_directions_angles.push_back(directions_angles[i]);
+                    no_redundant_directions_vector.push_back(directions_vector[i]);
+                    no_redundant_directions_ipix.push_back(directions_ipix[i]);
+                }
+        }// for i
+    }
+    else if (symmetry  == pg_I1H)
+    {//OK
+        Matrix2D<double>  A(3, 3);
+	    Euler_angles2matrix(0, 90, 0, A);
+        Matrix1D<double>  _5_fold_axis_1_by_5_fold_axis_2(3);
+        _5_fold_axis_1_by_5_fold_axis_2 = A * vectorR3(0., 1., 0.);
+        _5_fold_axis_1_by_5_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _5_fold_axis_2_by_3_fold_axis(3);
+        _5_fold_axis_2_by_3_fold_axis = A * vectorR3(-0.4999999839058737,
+                                                 -0.8090170074556163,
+                                                  0.3090169861701543);
+        _5_fold_axis_2_by_3_fold_axis.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_5_fold_axis_1(3);
+        _3_fold_axis_by_5_fold_axis_1 = A * vectorR3(0.4999999839058737,
+                                                -0.8090170074556163,
+                                                 0.3090169861701543);
+        _3_fold_axis_by_5_fold_axis_1.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_2_fold_axis(3);
+        _3_fold_axis_by_2_fold_axis =  A * vectorR3(1.,0.,0.);
+        _3_fold_axis_by_2_fold_axis.selfNormalize();
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (
+                    dotProduct(directions_vector[i], _5_fold_axis_1_by_5_fold_axis_2) >= 0 &&
+                    dotProduct(directions_vector[i], _5_fold_axis_2_by_3_fold_axis) >= 0 &&
+                    dotProduct(directions_vector[i], _3_fold_axis_by_2_fold_axis) >= 0
+               )
+                {
+                    no_redundant_directions_angles.push_back(directions_angles[i]);
+                    no_redundant_directions_vector.push_back(directions_vector[i]);
+                    no_redundant_directions_ipix.push_back(directions_ipix[i]);
+                }
+        }// for i
+    }
+    else if (symmetry  == pg_I3H)
+    {//OK
+        Matrix2D<double>  A(3, 3);
+	    Euler_angles2matrix(0,31.7174745559,0, A);
+        Matrix1D<double>  _5_fold_axis_1_by_5_fold_axis_2(3);
+        _5_fold_axis_1_by_5_fold_axis_2 = A * vectorR3(0., 0., 1.);
+        _5_fold_axis_1_by_5_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _5_fold_axis_2_by_3_fold_axis(3);
+        _5_fold_axis_2_by_3_fold_axis = A * vectorR3(0.187592467856686,
+                                        -0.303530987314591,
+                                        -0.491123477863004);
+        _5_fold_axis_2_by_3_fold_axis.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_5_fold_axis_1(3);
+        _3_fold_axis_by_5_fold_axis_1 = A * vectorR3(0.187592467856686,
+                                        0.303530987314591,
+                                        -0.491123477863004);
+        _3_fold_axis_by_5_fold_axis_1.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_2_fold_axis(3);
+        _3_fold_axis_by_2_fold_axis = vectorR3(0.,1.,0.);
+        _3_fold_axis_by_2_fold_axis.selfNormalize();
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (
+                dotProduct(directions_vector[i],
+		           _5_fold_axis_2_by_3_fold_axis)   >= 0 &&
+                dotProduct(directions_vector[i],
+		           _3_fold_axis_by_5_fold_axis_1)   >= 0 &&
+		        dotProduct(directions_vector[i],
+		           _5_fold_axis_1_by_5_fold_axis_2) >= 0 &&
+                dotProduct(directions_vector[i],
+                   _3_fold_axis_by_2_fold_axis)     >= 0
+            )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_I4H)
+    {//OK
+        Matrix2D<double>  A(3, 3);
+	Euler_angles2matrix(0,-31.7174745559,0, A);
+        Matrix1D<double>  _5_fold_axis_1_by_5_fold_axis_2(3);
+        _5_fold_axis_1_by_5_fold_axis_2 = A * vectorR3(0., 0., 1.);
+        _5_fold_axis_1_by_5_fold_axis_2.selfNormalize();
+        Matrix1D<double>  _5_fold_axis_2_by_3_fold_axis(3);
+        _5_fold_axis_2_by_3_fold_axis = A * vectorR3(0.187592467856686,
+                                        -0.303530987314591,
+                                        -0.491123477863004);
+        _5_fold_axis_2_by_3_fold_axis.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_5_fold_axis_1(3);
+        _3_fold_axis_by_5_fold_axis_1 = A * vectorR3(0.187592467856686,
+                                        0.303530987314591,
+                                        -0.491123477863004);
+        _3_fold_axis_by_5_fold_axis_1.selfNormalize();
+        Matrix1D<double>  _3_fold_axis_by_2_fold_axis(3);
+        _3_fold_axis_by_2_fold_axis = vectorR3(0.,1.,0.);
+        _3_fold_axis_by_2_fold_axis.selfNormalize();
+        for (long int i = 0; i < directions_angles.size(); i++)
+        {
+            if (
+                dotProduct(directions_vector[i],
+		           _5_fold_axis_2_by_3_fold_axis)   <= 0 &&
+                dotProduct(directions_vector[i],
+		           _3_fold_axis_by_5_fold_axis_1)   <= 0 &&
+		        dotProduct(directions_vector[i],
+		           _5_fold_axis_1_by_5_fold_axis_2) <= 0 &&
+                dotProduct(directions_vector[i],
+                   _3_fold_axis_by_2_fold_axis)     >= 0
+            )
+            {
+                no_redundant_directions_angles.push_back(directions_angles[i]);
+                no_redundant_directions_vector.push_back(directions_vector[i]);
+                no_redundant_directions_ipix.push_back(directions_ipix[i]);
+            }
+        }// for i
+    }
+    else if (symmetry  == pg_I5H)
+    {//OK
+        std::cerr << "ERROR: pg_I5H Symmetry not implemented" << std::endl;
+        exit(0);
+    }
+    else
+    {
+        std::cerr << "ERROR: Symmetry " << symmetry  << "is not known" << std::endl;
+        exit(0);
+    }
+
+
+    // Now overwrite the directions_angles and directions_vectors with their no_redundant counterparts
+    directions_angles = no_redundant_directions_angles;
+    directions_vector = no_redundant_directions_vector;
+    directions_ipix = no_redundant_directions_ipix;
+
+
+}
+
+
+#undef DEBUG_SAMPLING
diff --git a/src/healpix_sampling.h b/src/healpix_sampling.h
new file mode 100644
index 0000000..9d5d873
--- /dev/null
+++ b/src/healpix_sampling.h
@@ -0,0 +1,362 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef _HEALPIX_SAMPLING_HH
+#define _HEALPIX_SAMPLING_HH
+
+#include "src/Healpix_2.15a/healpix_base.h"
+#include "src/metadata_table.h"
+#include "src/macros.h"
+#include "src/multidim_array.h"
+#include "src/symmetries.h"
+#include "src/euler.h"
+
+// For the angular searches
+#define NOPRIOR 0
+#define PRIOR_ROTTILT_PSI 1
+
+
+class HealpixSampling
+{
+
+public:
+	/** Healpix sampling object */
+    Healpix_Base healpix_base;
+
+    /** Random perturbation */
+    double random_perturbation;
+
+    /** Amount of random perturbation */
+    double perturbation_factor;
+
+    /** In-plane (psi-angle) sampling rate
+     */
+    double psi_step;
+
+    /** Healpix order */
+    int healpix_order;
+
+    /** Mode for orientational prior distribution
+     * Note this option is not written to the STAR file, as it really belongs to mlmodel.
+     * It is included here for convenience, and always needs to be set in initialise
+     */
+    int orientational_prior_mode;
+
+    /* Translational search range and sampling rate
+     */
+    double offset_range, offset_step;
+
+    /** Flag whether this is a real 3D sampling */
+    bool is_3D;
+
+    /** Flag whether the translations are 3D (for volume refinement) */
+    bool is_3d_trans;
+
+    /** Name of the Symmetry group */
+    FileName fn_sym;
+
+    /** List of symmetry operators */
+    std::vector <Matrix2D<double> > R_repository, L_repository;
+
+    /** Two numbers that describe the symmetry group */
+    int pgGroup;
+    int pgOrder;
+
+    /** Limited tilt angle range */
+    double limit_tilt;
+
+    /** vector with the original pixel number in the healpix object */
+    std::vector<int> directions_ipix;
+
+    /** vector with sampling points described by angles */
+    std::vector<Matrix1D<double> > directions_angles;
+
+    /** vector with the psi-samples */
+    std::vector<double> psi_angles;
+
+    /** vector with the X,Y(,Z)-translations */
+    std::vector<Matrix1D<double> > translations;
+
+    /** vector with pointers to the (rot,tilt) pairs (directions) that have non-zero prior probability */
+    std::vector<int> pointer_dir_nonzeroprior;
+
+    /** vector with pointers to the psi-samples that have non-zero prior probability */
+    std::vector<int> pointer_psi_nonzeroprior;
+
+//TMP DEBUGGING: normally protected!
+public:
+    /** vector with the prior probabilities for those directions that have non-zero prior probability*/
+    std::vector<double> directions_prior;
+
+    /** vector with the prior probabilities for those psi-angles that have non-zero prior probability*/
+    std::vector<double> psi_prior;
+
+
+
+public:
+
+    // Empty constructor
+    HealpixSampling() {}
+
+    // Destructor
+    ~HealpixSampling()
+    {
+    	directions_ipix.clear();
+    	directions_angles.clear();
+    	psi_angles.clear();
+    	pointer_dir_nonzeroprior.clear();
+    	pointer_psi_nonzeroprior.clear();
+    	directions_prior.clear();
+    	psi_prior.clear();
+    	translations.clear();
+
+    }
+
+    // Start from all empty vectors and meaningless parameters
+    void clear();
+
+    /** Set up the entire sampling object
+     *
+     * The in-plane (psi-angle) sampling is linear,
+     * input_psi_sampling is modified to contain an integer number of equally-sized sampling points
+     * For the 3D-case, a negative input_psi_sampling will result in a psi-sampling similar to the sqrt of a HealPix pixel area.
+	 *
+     * The HEALPix sampling is implemented as described by Gorski et al (2005), The Astrophysical Journal, 622:759-771
+     * The order defines the number of sampling points, and thereby the angular sampling rate
+     * From this paper is the following table:
+     *
+     * order	Npix	Theta-sampling
+     * 0		12		58.6
+     * 1		48		29.3
+     * 2		192		14.7
+     * 3		768		7.33
+     * 4		3072	3.66
+     * 5		12288	1.83
+     * 6		49152	0.55
+     * 7		196608	0.28
+     * 8		786432	0.14
+     * etc...
+     *
+     * */
+    void initialise(int prior_mode, int ref_dim = -1, bool do_3d_trans = false);
+
+    // Reset the random perturbation
+    void resetRandomlyPerturbedSampling();
+
+    // Read in all information from the command line to build the sampling object
+    void read(IOParser &parser, int ori_size, int ref_dim);
+
+    // Read CL options after a -continue statement.
+    void readContinue(int argc, char **argv, bool &directions_have_changed);
+
+    // Read in all information from a STAR file (for restarting)
+    void read(FileName fn_in);
+
+    // Write the sampling information to a STAR file
+    void write(FileName fn_out);
+
+    /* Set the non-oversampled list of translations */
+    void setTranslations(double offset_step = -1., double offset_range = -1.);
+
+    /* Set only a single translation */
+    void setOneTranslation(Matrix1D<double> offset);
+
+    /* Set the non-oversampled lists of directions and in-plane rotations */
+    void setOrientations(int _order = -1, double _psi_step = -1.);
+
+    /* Set only a single orientation */
+    void setOneOrientation(double rot, double tilt, double psi);
+
+
+    /* Write all orientations as a sphere in a bild file
+     * Mainly useful for debugging */
+    void writeAllOrientationsToBild(FileName fn_bild, std::string rgb = "1 0 0", double size = 0.025);
+    void writeNonZeroPriorOrientationsToBild(FileName fn_bild, double rot_prior, double tilt_prior, std::string rgb = "0 0 1", double size = 0.025);
+
+    /* Select all orientations with zero prior probabilities
+     * store all these in the vectors pointer_dir_nonzeroprior and pointer_psi_nonzeroprior
+     * Also precalculate their prior probabilities and store in directions_prior and psi_prior
+     */
+    void selectOrientationsWithNonZeroPriorProbability(
+    		double prior_rot, double prior_tilt, double prior_psi,
+    		double sigma_rot, double sigma_tilt, double sigma_psi,
+    		double sigma_cutoff = 3.);
+
+    /* Randomly reject part of te non-zero prior probabilities, so that the optimization no longer follows the steepest downward gradient
+     * This procedure was inspired by Hans Elmlund's PRIME algorithm.
+     */
+    void randomSelectionNonZeroPriorProbability(double fraction_to_keep);
+
+
+    /** Get the symmetry group of this sampling object
+     */
+    FileName symmetryGroup();
+
+    /* Get the original HEALPix index for this direction
+     * Note that because of symmetry-equivalence removal idir no longer corresponds to the HEALPix pixel number
+     *
+     */
+    long int getHealPixIndex(long int idir);
+
+    /** The geometrical considerations about the symmetry below require that rot = [-180,180] and tilt [0,180]
+     */
+    void checkDirection(double &rot, double &tilt);
+
+    /* Get the rot and tilt angles in the center of the ipix'th HEALPix sampling pixel
+     * This involves calculations in the HEALPix library
+     */
+    void getDirectionFromHealPix(long int ipix, double &rot, double &tilt);
+
+    /* Get the translational sampling step in pixels */
+    double getTranslationalSampling(int adaptive_oversampling = 0);
+
+    /* Get approximate angular sampling in degrees for any adaptive oversampling
+     */
+    double getAngularSampling(int adaptive_oversampling = 0);
+
+    /* Get the number of symmetry-unique sampling points
+     * Note that because of symmetry-equivalence removal this number is not the number of original HEALPix pixels
+     * In the case of orientational priors, the number of directions with non-zero prior probability is returned
+     */
+    long int NrDirections(int oversampling_order = 0, bool include_zeroprior = false);
+
+    /* Get the number of in-plane (psi-angle) sampling points
+     */
+    long int NrPsiSamplings(int oversampling_order = 0, bool include_zeroprior = false);
+
+    /* Get the number of in-plane translational sampling points
+     */
+    long int NrTranslationalSamplings(int oversampling_order = 0);
+
+    /* Get the total number of (oversampled) sampling points, i.e. all (rot, tilt, psi, xoff, yoff) quintets
+    */
+    long int NrSamplingPoints(int oversampling_order = 0, bool include_zeroprior = false);
+
+    /* How often is each orientation oversampled? */
+    int oversamplingFactorOrientations(int oversampling_order);
+
+    /* How often is each translation oversampled? */
+    int oversamplingFactorTranslations(int oversampling_order);
+
+    /* Get the rot and tilt angles from the precalculated sampling_points_angles vector
+     * This does not involve calculations in the HEALPix library
+     * Note that because of symmetry-equivalence removal idir no longer corresponds to the HEALPix pixel number
+     */
+    void getDirection(long int idir, double &rot, double &tilt);
+
+    /* Get the value for the ipsi'th precalculated psi angle
+     */
+    void getPsiAngle(long int ipsi, double &psi);
+
+    /* Get the value for the itrans'th precalculated translations
+     */
+    void getTranslation(long int itrans, Matrix1D<double> &trans);
+
+    /* Get the position of this sampling point in the original array */
+    long int getPositionSamplingPoint(int iclass, long int idir, long int ipsi, long int itrans);
+
+    /* Get the position of this sampling point in the oversampled array */
+    long int getPositionOversampledSamplingPoint(long int ipos, int oversampling_order, int iover_rot, int iover_trans);
+
+    /* Get the vectors of (xx, yy) for a more finely (oversampled) translational sampling
+     * The oversampling_order is the difference in order of the original (coarse) and the oversampled (fine) sampling
+     * An oversampling_order == 0  will give rise to the same (xx, yy) pair as the original itrans.
+     * An oversampling_order == 1 will give rise to 2*2 new (rot, tilt) pairs.
+     * An oversampling_order == 2 will give rise to 4*4 new (rot, tilt) pairs.
+     * etc.
+     */
+    void getTranslations(long int itrans, int oversampling_order,
+								    std::vector<Matrix1D<double> > &my_translations);
+
+    /* Get the vectors of (rot, tilt, psi) angle triplets for a more finely (oversampled) sampling
+     * The oversampling_order is the difference in order of the original (coarse) and the oversampled (fine) sampling
+     * An oversampling_order == 0  will give rise to the same (rot, tilt, psi) triplet as the original ipix.
+     * An oversampling_order == 1 will give rise to 2*2*2 new (rot, tilt, psi) triplets.
+     * An oversampling_order == 2 will give rise to 4*4*4 new (rot, tilt, psi) triplets.
+     * etc.
+     *
+     * If only_nonzero_prior is true, then only the orientations with non-zero prior probabilities will be returned
+     * This is for local angular searches
+     */
+    void getOrientations(long int idir, long int ipsi, int oversampling_order, std::vector<Matrix1D<double> > &my_orientations);
+
+    /** Get the prior probability for this orientation
+     */
+    double getPriorProbability(long int idir, long int ipsi);
+
+    /** Get the number of the original direction from the ones with also non-zero prior probability
+     */
+    long int getDirectionNumberAlsoZeroPrior(long int idir);
+
+    /** Get the number of the original direction from the ones with also non-zero prior probability
+     */
+    long int getPsiNumberAlsoZeroPrior(long int ipsi);
+
+    /* Gets the vector of psi angles for a more finely (oversampled) sampling and
+     * pushes each instance back into the oversampled_orientations vector with the given rot and tilt
+     * The oversampling_order is the difference in order of the original (coarse) and the oversampled (fine) sampling
+     * An oversampling_order == 0  will give rise to the same psi angle as the original ipsi.
+     * An oversampling_order == 1 will give rise to 2 new psi angles
+     * An oversampling_order == 2 will give rise to 4 new psi angles
+     * etc.
+     */
+    void pushbackOversampledPsiAngles(long int ipsi, int oversampling_order,
+    		double rot, double tilt, std::vector<Matrix1D<double> > &oversampled_orientations);
+
+    /* Calculate an angular distance between two sets of Euler angles */
+    double calculateAngularDistance(double rot1, double tilt1, double psi1,
+    		double rot2, double tilt2, double psi2);
+
+    /* Write a BILD file describing the angular distribution
+     *  R determines the radius of the sphere on which cylinders will be placed
+     *  Rmax_frac determines the length of the longest cylinder (relative to R, 0.2 + +20%)
+     *  width_frac determines how broad each cylinder is. frac=1 means they touch each other
+     * */
+    void writeBildFileOrientationalDistribution(MultidimArray<double> &pdf_direction,
+    		FileName &fn_bild, double R, double offset = 0., double Rmax_frac = 0.3, double width_frac = 0.5);
+
+private:
+
+    /* Eliminate points from the sampling_points_vector and sampling_points_angles vectors
+     * that are outside the allowed tilt range.
+     * Let tilt angles range from -90 to 90, then:
+     * if (limit_tilt > 0) then top views (that is with ABS(tilt) > limit_tilt) are removed and side views are kept
+     * if (limit_tilt < 0) then side views (that is with ABS(tilt) < limit_tilt) are removed and top views are kept
+    */
+    void removePointsOutsideLimitedTiltAngles();
+
+    /* Eliminate symmetry-equivalent points from the sampling_points_vector and sampling_points_angles vectors
+        This function first calls removeSymmetryEquivalentPointsGeometric,
+        and then checks each point versus all others to calculate an angular distance
+        If this distance is less than 0.8 times the angular sampling, the point is deleted
+        This cares care of sampling points near the edge of the geometrical considerations
+    */
+    void removeSymmetryEquivalentPoints(double max_ang);
+
+    /* eliminate symmetry-related points based on simple geometrical considerations,
+        symmetry group, symmetry order */
+    void removeSymmetryEquivalentPointsGeometric(const int symmetry, int sym_order,
+												 std::vector <Matrix1D<double> >  &sampling_points_vector);
+
+
+
+};
+//@}
+#endif
diff --git a/src/image.cpp b/src/image.cpp
new file mode 100644
index 0000000..96cf559
--- /dev/null
+++ b/src/image.cpp
@@ -0,0 +1,199 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/image.h"
+
+
+// Get size of datatype
+unsigned long  gettypesize(DataType type)
+{
+    unsigned long   size;
+
+    switch ( type ) {
+        case UChar: case SChar:  size = sizeof(char); break;
+        case UShort: case Short: size = sizeof(short); break;
+        case UInt:	 case Int:   size = sizeof(int); break;
+        case Float:              size = sizeof(float); break;
+        case Double:             size = sizeof(double); break;
+        case Bool:				  size = sizeof(bool); break;
+        default: size = 0;
+    }
+
+    return(size);
+}
+
+int datatypeString2Int(std::string s)
+{
+  toLower(s);
+  if (!strcmp(s.c_str(),"uchar"))
+  {
+       return UChar;
+  }
+  else if (!strcmp(s.c_str(),"ushort"))
+  {
+    return UShort;
+  }
+  else if (!strcmp(s.c_str(),"short"))
+  {
+    return Short;
+  }
+  else if (!strcmp(s.c_str(),"uint"))
+  {
+    return UInt;
+  }
+  else if (!strcmp(s.c_str(),"int"))
+  {
+    return Int;
+  }
+  else if (!strcmp(s.c_str(),"float"))
+  {
+    return Float;
+  }
+  else REPORT_ERROR("datatypeString2int; unknown datatype");
+
+
+}
+
+// Some image-specific operations
+void normalise(Image<double> &I, int bg_radius, double white_dust_stddev, double black_dust_stddev)
+{
+	int bg_radius2 = bg_radius * bg_radius;
+	double avg, stddev;
+
+	if (2*bg_radius > XSIZE(I()))
+		REPORT_ERROR("normalise ERROR: 2*bg_radius is larger than image size!");
+
+	// Calculate initial avg and stddev values
+	calculateBackgroundAvgStddev(I, avg, stddev, bg_radius);
+
+	// Remove white and black noise
+	if (white_dust_stddev > 0.)
+		removeDust(I, true, white_dust_stddev, avg, stddev);
+	if (black_dust_stddev > 0.)
+		removeDust(I, false, black_dust_stddev, avg, stddev);
+
+	// If some dust was removed: recalculate avg and stddev
+	if (white_dust_stddev > 0. || black_dust_stddev > 0.)
+		calculateBackgroundAvgStddev(I, avg, stddev, bg_radius);
+
+
+	if (stddev < 1e-10)
+	{
+		std::cerr << " WARNING! Stddev of image " << I.name() << " is zero! Skipping normalisation..." << std::endl;
+	}
+	else
+	{
+		// Subtract avg and divide by stddev for all pixels
+		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(I())
+			DIRECT_MULTIDIM_ELEM(I(), n) = (DIRECT_MULTIDIM_ELEM(I(), n) - avg) / stddev;
+	}
+}
+
+void calculateBackgroundAvgStddev(Image<double> &I, double &avg, double &stddev, int bg_radius)
+{
+	int bg_radius2 = bg_radius * bg_radius;
+	double n = 0.;
+	avg = 0.;
+	stddev = 0.;
+
+	// Calculate avg in the background pixels
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(I())
+	{
+		if (k*k + i*i + j*j > bg_radius2)
+		{
+			avg += A3D_ELEM(I(), k, i, j);
+			n += 1.;
+		}
+	}
+	avg /= n;
+
+	// Calculate stddev in the background pixels
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(I())
+	{
+		if (k*k + i*i + j*j > bg_radius2)
+		{
+			double aux = A3D_ELEM(I(), k, i, j) - avg;
+			stddev += aux * aux;
+		}
+	}
+	stddev = sqrt(stddev/n);
+}
+
+void removeDust(Image<double> &I, bool is_white, double thresh, double avg, double stddev)
+{
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(I())
+	{
+		double aux =  A3D_ELEM(I(), k, i, j);
+		if (is_white && aux - avg > thresh * stddev)
+			A3D_ELEM(I(), k, i, j) = rnd_gaus(avg, stddev);
+		else if (!is_white && aux - avg < -thresh * stddev)
+			A3D_ELEM(I(), k, i, j) = rnd_gaus(avg, stddev);
+	}
+}
+
+void invert_contrast(Image<double> &I)
+{
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(I())
+	{
+		DIRECT_MULTIDIM_ELEM(I(), n) *= -1;
+	}
+}
+
+void rescale(Image<double> &I, int mysize)
+{
+	int olddim = XSIZE(I());
+
+	resizeMap(I(), mysize);
+
+	// Also modify the scale in the MDmainheader (if present)
+	double oldscale, newscale;
+    if (I.MDMainHeader.getValue(EMDL_IMAGE_SAMPLINGRATE_X, oldscale))
+    {
+    	newscale = oldscale * (double)olddim / (double)mysize;
+    	I.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_X, newscale);
+    }
+    if (I.MDMainHeader.getValue(EMDL_IMAGE_SAMPLINGRATE_Y, oldscale))
+    {
+    	newscale = oldscale * (double)olddim / (double)mysize;
+    	I.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Y, newscale);
+    }
+    if (I().getDim() == 3 && I.MDMainHeader.getValue(EMDL_IMAGE_SAMPLINGRATE_Z, oldscale) )
+    {
+    	newscale = oldscale * (double)olddim / (double)mysize;
+    	I.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Z, newscale);
+    }
+
+}
+
+void rewindow(Image<double> &I, int mysize)
+{
+	// Check 2D or 3D dimensionality
+	if (I().getDim() == 2)
+	{
+		I().window(FIRST_XMIPP_INDEX(mysize), FIRST_XMIPP_INDEX(mysize),
+				   LAST_XMIPP_INDEX(mysize),  LAST_XMIPP_INDEX(mysize));
+	}
+	else if (I().getDim() == 3)
+	{
+		I().window(FIRST_XMIPP_INDEX(mysize), FIRST_XMIPP_INDEX(mysize), FIRST_XMIPP_INDEX(mysize),
+				   LAST_XMIPP_INDEX(mysize),  LAST_XMIPP_INDEX(mysize),  LAST_XMIPP_INDEX(mysize));
+	}
+
+}
+
diff --git a/src/image.h b/src/image.h
new file mode 100644
index 0000000..d0318e6
--- /dev/null
+++ b/src/image.h
@@ -0,0 +1,1329 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors: Sjors H.W. Scheres (scheres at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * Part of this module has been developed by Lorenzo Zampighi and Nelson Tang
+ * Dept. Physiology of the David Geffen School of Medicine
+ * Univ. of California, Los Angeles.
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef IMAGE_H
+#define IMAGE_H
+
+#include <typeinfo>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "src/funcs.h"
+#include "src/memory.h"
+#include "src/filename.h"
+#include "src/multidim_array.h"
+#include "src/transformations.h"
+#include "src/metadata_table.h"
+#include "src/fftw.h"
+
+/// @defgroup Images Images
+//@{
+
+/** Data type.
+ * This class defines the datatype of the data inside this image.
+ */
+typedef enum
+{
+    Unknown_Type = 0,       // Undefined data type
+    UChar = 1,              // Unsigned character or byte type
+    SChar = 2,              // Signed character (for CCP4)
+    UShort = 3,             // Unsigned integer (2-byte)
+    Short = 4,              // Signed integer (2-byte)
+    UInt = 5,               // Unsigned integer (4-byte)
+    Int = 6,                // Signed integer (4-byte)
+    Long = 7,               // Signed integer (4 or 8 byte, depending on system)
+    Float = 8,              // Floating point (4-byte)
+    Double = 9,             // Double precision floating point (8-byte)
+    Bool = 10,              // Boolean (1-byte?)
+    LastEntry = 15          // This must be the last entry
+} DataType;
+
+/** Write mode
+ * This class defines the writing behavior.
+ */
+typedef enum
+{
+    WRITE_OVERWRITE, //forget about the old file and overwrite it
+    WRITE_APPEND,    //append and object at the end of a stack, so far can not append stacks
+    WRITE_REPLACE,   //replace a particular object by another
+    WRITE_READONLY   //only can read the file
+} WriteMode;
+
+
+/** Open File struct
+ * This struct is used to share the File handlers with Image Collection class
+ */
+struct fImageHandler
+{
+    FILE*     fimg;       // Image File handler
+    FILE*     fhed;       // Image File header handler
+    FileName  ext_name;   // Filename extension
+    bool     exist;       // Shows if the file exists
+};
+
+/** Returns memory size of datatype
+ */
+unsigned long gettypesize(DataType type);
+
+/** Convert datatype string to datatypr enun */
+int datatypeString2Int(std::string s);
+
+/** Swapping trigger.
+ * Threshold file z size above which bytes are swapped.
+ */
+#define SWAPTRIG     65535
+
+/** Template class for images.
+ * The image class is the general image handling class.
+ */
+template<typename T>
+class Image
+{
+public:
+    MultidimArray<T>    data;        // The image data array
+    MetaDataTable MDMainHeader;      // metadata for the file
+
+private:
+    FileName            filename;    // File name
+    FILE*                fimg;       // Image File handler
+    FILE*                fhed;       // Image File header handler
+    bool                stayOpen;    // To maintain the image file open after read/write
+    int                 dataflag;    // Flag to force reading of the data
+    unsigned long       i;           // Current image number (may be > NSIZE)
+    unsigned long       offset;      // Data offset
+    int                 swap;        // Perform byte swapping upon reading
+    long int            replaceNsize;// Stack size in the replace case
+    bool                _exists;     // does target file exists?
+    // equal 0 is not exists or not a stack
+    bool                mmapOn;      // Mapping when loading from file
+    int                 mFd;         // Handle the file in reading method and mmap
+    size_t              mappedSize;  // Size of the mapped file
+
+public:
+    /** Empty constructor
+     *
+     * An empty image is created.
+     *
+     * @code
+     * Image<double> I;
+     * @endcode
+     */
+    Image()
+    {
+        mmapOn = false;
+        clear();
+        MDMainHeader.addObject();
+    }
+
+    /** Constructor with size
+     *
+     * A blank image (0.0 filled) is created with the given size. Pay attention
+     * to the dimension order: Y and then X.
+     *
+     * @code
+     * Image I(64,64);
+     * @endcode
+     */
+    Image(long int Xdim, long int Ydim, long int Zdim=1, long int Ndim=1)
+    {
+        mmapOn = false;
+        clear();
+        data.resize(Ndim, Zdim, Ydim, Xdim);
+        MDMainHeader.addObject();
+    }
+
+    /** Clear.
+     * Initialize everything to 0
+     */
+    void clear()
+    {
+        if (mmapOn)
+        {
+            munmap(data.data-offset,mappedSize);
+            close(mFd);
+            data.data = NULL;
+        }
+        else
+            data.clear();
+
+        dataflag = -1;
+        i = 0;
+        filename = "";
+        offset = 0;
+        swap = 0;
+        clearHeader();
+        replaceNsize=0;
+        mmapOn = false;
+    }
+
+    /** Clear the header of the image
+     */
+    void clearHeader()
+    {
+        MDMainHeader.clear();
+    }
+
+    /** Destructor.
+     */
+    ~Image()
+    {
+        clear();
+    }
+
+
+    /** Specific read functions for different file formats
+      */
+#include "src/rwSPIDER.h"
+#include "src/rwMRC.h"
+#include "src/rwIMAGIC.h"
+
+    /** Is this file an image
+     *
+     *  Check whether a real-space image can be read
+     *
+     */
+    bool isImage(const FileName &name)
+    {
+        return !read(name, false);
+    }
+
+    /** Rename the image
+      */
+    void rename (const FileName &name)
+    {
+        filename = name;
+    }
+
+    /** General read function
+     * you can read a single image from a single image file
+     * or a single image file from an stack, in the second case
+     * the select slide may come in the image name or in the select_img parameter
+     * file name takes precedence over select_img
+     * If -1 is given the whole object is read
+     *
+     */
+    int read(const FileName &name, bool readdata=true, long int select_img=-1, bool mapData = false, bool is_2D = false)
+    {
+
+        int err = 0;
+        fImageHandler* hFile = openFile(name);
+        err = _read(name, hFile, readdata, select_img, mapData, is_2D);
+        closeFile(hFile);
+
+        // Negative errors are bad
+        return err;
+    }
+
+    /** Read function from a file that has already been opened
+     *
+     */
+    int readFromOpenFile(const FileName &name, fImageHandler* hFile, long int select_img, bool is_2D = false)
+    {
+    	int err = 0;
+    	err = _read(name, hFile, true, select_img, false, is_2D);
+    	// Reposition file pointer for a next read
+    	rewind(fimg);
+    	return err;
+    }
+
+    /** General write function
+     * select_img= which slice should I replace
+     * overwrite = 0, append slice
+     * overwrite = 1 overwrite slice
+     */
+    void write(FileName name="",
+               long int select_img=-1,
+               bool isStack=false,
+               int mode=WRITE_OVERWRITE)
+    {
+
+        const FileName &fname = (name == "") ? filename : name;
+        fImageHandler* hFile = openFile(fname, mode);
+        _write(fname, hFile, select_img, isStack, mode);
+        closeFile(hFile);
+
+    }
+
+    /** Cast a page of data from type dataType to type Tdest
+     *    input pointer  char *
+     */
+    void castPage2T(char * page, T * ptrDest, DataType datatype, size_t pageSize )
+    {
+        switch (datatype)
+        {
+        case Unknown_Type:
+            REPORT_ERROR("ERROR: datatype is Unknown_Type");
+        case UChar:
+            {
+                if (typeid(T) == typeid(unsigned char))
+                    memcpy(ptrDest, page, pageSize*sizeof(T));
+                else
+                {
+                    unsigned char * ptr = (unsigned char *) page;
+                    for(int i=0; i<pageSize; i++)
+                        ptrDest[i]=(T) ptr[i];
+                }
+                break;
+            }
+        case SChar:
+                {
+                    if (typeid(T) == typeid(signed char))
+                {
+                    memcpy(ptrDest, page, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        signed char * ptr = (signed char *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptrDest[i]=(T) ptr[i];
+                    }
+                break;
+            }
+        case UShort:
+                {
+                    if (typeid(T) == typeid(unsigned short))
+                {
+                    memcpy(ptrDest, page, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        unsigned short * ptr = (unsigned short *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptrDest[i]=(T) ptr[i];
+                    }
+                break;
+            }
+        case Short:
+                {
+                    if (typeid(T) == typeid(short))
+                {
+                    memcpy(ptrDest, page, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        short * ptr = (short *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptrDest[i]=(T) ptr[i];
+                    }
+                break;
+            }
+        case UInt:
+                {
+                    if (typeid(T) == typeid(unsigned int))
+                {
+                    memcpy(ptrDest, page, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        unsigned int * ptr = (unsigned int *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptrDest[i]=(T) ptr[i];
+                    }
+                break;
+            }
+        case Int:
+                {
+                    if (typeid(T) == typeid(int))
+                {
+                    memcpy(ptrDest, page, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        int * ptr = (int *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptrDest[i]=(T) ptr[i];
+                    }
+                break;
+            }
+        case Long:
+                {
+                    if (typeid(T) == typeid(long))
+                {
+                    memcpy(ptrDest, page, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        long * ptr = (long *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptrDest[i]=(T) ptr[i];
+                    }
+                break;
+            }
+        case Float:
+                {
+                    if (typeid(T) == typeid(float))
+                {
+                    memcpy(ptrDest, page, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        float * ptr = (float *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptrDest[i]=(T) ptr[i];
+                    }
+                break;
+            }
+        case Double:
+                {
+                    if (typeid(T) == typeid(double))
+                {
+                    memcpy(ptrDest, page, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        double * ptr = (double *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptrDest[i]=(T) ptr[i];
+                    }
+                break;
+            }
+        default:
+                {
+                    std::cerr<<"Datatype= "<<datatype<<std::endl;
+                    REPORT_ERROR(" ERROR: cannot cast datatype to T");
+                    break;
+                }
+            }
+
+    }
+
+    /** Cast page from T to datatype
+     *  input pointer char *
+     */
+    void castPage2Datatype(T * srcPtr, char * page, DataType datatype, size_t pageSize )
+    {
+        switch (datatype)
+        {
+        case Float:
+            {
+                if (typeid(T) == typeid(float))
+                {
+                    memcpy(page, srcPtr, pageSize*sizeof(T));
+                }
+                else
+                {
+                    float * ptr = (float *) page;
+                    for(int i=0; i<pageSize; i++)
+                        ptr[i] = (float)srcPtr[i];
+                }
+                break;
+            }
+        case Double:
+                {
+                    if (typeid(T) == typeid(double))
+                {
+                    memcpy(page, srcPtr, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        double * ptr = (double *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptr[i] = (double)srcPtr[i];
+                    }
+                break;
+            }
+       case UShort:
+                {
+                    if (typeid(T) == typeid(unsigned short))
+                {
+                    memcpy(page, srcPtr, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        unsigned short * ptr = (unsigned short *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptr[i] = (unsigned short)srcPtr[i];
+                    }
+                break;
+            }
+        case UChar:
+                {
+                    if (typeid(T) == typeid(unsigned char))
+                {
+                    memcpy(page, srcPtr, pageSize*sizeof(T));
+                    }
+                    else
+                    {
+                        unsigned char * ptr = (unsigned char *) page;
+                        for(int i=0; i<pageSize; i++)
+                            ptr[i] = (unsigned char)srcPtr[i];
+                    }
+                break;
+            }
+        default:
+                {
+                    std::cerr<<"outputDatatype= "<<datatype<<std::endl;
+                    REPORT_ERROR(" ERROR: cannot cast T to outputDatatype");
+                    break;
+                }
+            }
+    }
+
+    /** Check file Datatype is same as T type to use mmap.
+     */
+    bool checkMmapT(DataType datatype)
+    {
+
+        switch (datatype)
+        {
+        case Unknown_Type:
+            REPORT_ERROR("ERROR: datatype is Unknown_Type");
+        case UChar:
+            {
+                if (typeid(T) == typeid(unsigned char))
+                    return 1;
+                else
+                    return 0;
+                break;
+            }
+        case SChar:
+            {
+                if (typeid(T) == typeid(signed char))
+                    return 1;
+                else
+                    return 0;
+                break;
+            }
+        case UShort:
+            {
+                if (typeid(T) == typeid(unsigned short))
+                    return 1;
+                else
+                    return 0;
+                break;
+            }
+        case Short:
+            {
+                if (typeid(T) == typeid(short))
+                    return 1;
+                else
+                    return 0;
+                break;
+            }
+        case UInt:
+            {
+                if (typeid(T) == typeid(unsigned int))
+                    return 1;
+                else
+                    return 0;
+                break;
+            }
+        case Int:
+            {
+                if (typeid(T) == typeid(int))
+                    return 1;
+                else
+                    return 0;
+                break;
+            }
+        case Long:
+            {
+                if (typeid(T) == typeid(long))
+                    return 1;
+                else
+                    return 0;
+                break;
+            }
+        case Float:
+            {
+                if (typeid(T) == typeid(float))
+                    return 1;
+                else
+                    return 0;
+                break;
+            }
+        case Double:
+            {
+                if (typeid(T) == typeid(double))
+                    return 1;
+                else
+                    return 0;
+                break;
+            }
+        default:
+            {
+                std::cerr<<"Datatype= "<<datatype<<std::endl;
+                REPORT_ERROR(" ERROR: cannot cast datatype to T");
+                break;
+            }
+        }
+        //               int * iTemp = (int*) map;
+        //                ptrDest = reinterpret_cast<T*> (iTemp);
+    }
+
+    /** Write an entire page as datatype
+     *
+     * A page of datasize_n elements T is cast to datatype and written to fimg
+     * The memory for the casted page is allocated and freed internally.
+     */
+    void writePageAsDatatype(FILE * fimg, DataType datatype, size_t datasize_n )
+    {
+        size_t datasize = datasize_n * gettypesize(datatype);
+        char * fdata = (char *) askMemory(datasize);
+        castPage2Datatype(MULTIDIM_ARRAY(data), fdata, datatype, datasize_n);
+        fwrite( fdata, datasize, 1, fimg );
+        freeMemory(fdata, datasize);
+    }
+
+    /** Swap an entire page
+      * input pointer char *
+      */
+    void swapPage(char * page, size_t pageNrElements, DataType datatype)
+    {
+        unsigned long datatypesize = gettypesize(datatype);
+#ifdef DEBUG
+
+        std::cerr<<"DEBUG swapPage: Swapping image data with swap= "
+        << swap<<" datatypesize= "<<datatypesize
+        << " pageNrElements " << pageNrElements
+        << " datatype " << datatype
+        <<std::endl;
+        ;
+#endif
+
+        // Swap bytes if required
+        if ( swap == 1 )
+        {
+            for ( unsigned long i=0; i<pageNrElements; i+=datatypesize )
+                swapbytes(page+i, datatypesize);
+        }
+        else if ( swap > 1 )
+        {
+            for ( unsigned long i=0; i<pageNrElements; i+=swap )
+                swapbytes(page+i, swap);
+        }
+    }
+
+    /** Read the raw data
+      */
+    int readData(FILE* fimg, long int select_img, DataType datatype, unsigned long pad)
+    {
+        //#define DEBUG
+#ifdef DEBUG
+        std::cerr<<"entering readdata"<<std::endl;
+        std::cerr<<" readData flag= "<<dataflag<<std::endl;
+#endif
+
+        if ( dataflag < 1 )
+            return 0;
+
+        size_t myoffset, readsize, readsize_n, pagemax = 1073741824; //1Gb
+        size_t datatypesize=gettypesize(datatype);
+        size_t pagesize  =ZYXSIZE(data)*datatypesize;
+        size_t haveread_n=0;
+
+        //Multidimarray mmapOn is priority over image mmapOn
+        if(data.mmapOn)
+            mmapOn = false;
+
+        // Flag to know that data is not going to be mapped although mmapOn is true
+        if (mmapOn && !checkMmapT(datatype))
+        {
+            std::cout << "WARNING: Image Class. File datatype and image declaration not compatible with mmap. Loading into memory." <<std::endl;
+            mmapOn = false;
+            mFd = -1;
+        }
+
+        if (mmapOn)
+        {
+            if ( NSIZE(data) > 1 )
+            {
+                REPORT_ERROR("Image Class::ReadData: mmap with multiple \
+                             images file not compatible. Try selecting a unique image.");
+            }
+
+            fclose(fimg);
+
+            //if ( ( mFd = open(filename.c_str(), O_RDWR, S_IREAD | S_IWRITE) ) == -1 )
+            if ( ( mFd = open(filename.c_str(), O_RDWR, S_IRUSR | S_IWUSR) ) == -1 )
+                REPORT_ERROR("Image Class::ReadData: Error opening the image file.");
+
+            char * map;
+            mappedSize = pagesize+offset;
+
+            if ( (map = (char*) mmap(0,mappedSize, PROT_READ | PROT_WRITE, MAP_SHARED, mFd, 0)) == (void*) -1 )
+                REPORT_ERROR("Image Class::ReadData: mmap of image file failed.");
+            data.data = reinterpret_cast<T*> (map+offset);
+        }
+        else
+        {
+            // Reset select to get the correct offset
+            if ( select_img < 0 )
+                select_img = 0;
+
+            char* page = NULL;
+
+            // Allocate memory for image data (Assume xdim, ydim, zdim and ndim are already set
+            //if memory already allocated use it (no resize allowed)
+            data.coreAllocateReuse();
+            myoffset = offset + select_img*(pagesize + pad);
+            //#define DEBUG
+
+#ifdef DEBUG
+
+            data.printShape();
+            printf("DEBUG: Page size: %ld offset= %d \n", pagesize, offset);
+            printf("DEBUG: Swap = %d  Pad = %ld  Offset = %ld\n", swap, pad, offset);
+            printf("DEBUG: myoffset = %d select_img= %d \n", myoffset, select_img);
+#endif
+
+            if (pagesize > pagemax)
+                page = (char *) askMemory(pagemax*sizeof(char));
+            else
+                page = (char *) askMemory(pagesize*sizeof(char));
+
+            int error_fseek = fseek( fimg, myoffset, SEEK_SET );
+            if (error_fseek != 0)
+            	return -1;
+
+            for ( size_t myn=0; myn<NSIZE(data); myn++ )
+            {
+                for (size_t myj=0; myj<pagesize; myj+=pagemax )//pagesize size of object
+                {
+                    // Read next page. Divide pages larger than pagemax
+                    readsize = pagesize - myj;
+                    if ( readsize > pagemax )
+                        readsize = pagemax;
+                    readsize_n = readsize/datatypesize;
+
+                    //Read page from disc
+                    size_t result = fread( page, readsize, 1, fimg );
+                    if (result != 1)
+                    	return -2;
+
+                    //swap per page
+                    if (swap)
+                        swapPage(page, readsize, datatype);
+                    // cast to T per page
+                    castPage2T(page, MULTIDIM_ARRAY(data) + haveread_n, datatype, readsize_n);
+                    haveread_n += readsize_n;
+                }
+                if ( pad > 0 )
+                {
+                    //fread( padpage, pad, 1, fimg);
+                	error_fseek = fseek( fimg, pad, SEEK_CUR );
+                    if (error_fseek != 0)
+                    	return -1;
+                }
+            }
+            //if ( pad > 0 )
+            //    freeMemory(padpage, pad*sizeof(char));
+            if ( page > 0 )
+                freeMemory(page, pagesize*sizeof(char));
+
+#ifdef DEBUG
+
+            printf("DEBUG img_read_data: Finished reading and converting data\n");
+#endif
+
+        }
+        return 0;
+    }
+
+    /** Data access
+     *
+     * This operator can be used to access the data multidimarray.
+     * In this way we could resize an image just by
+     * resizing its associated matrix or we could add two images by adding their
+     * matrices.
+     * @code
+     * I().resize(128, 128);
+     * I2() = I1() + I2();
+     * @endcode
+     */
+    MultidimArray<T>& operator()()
+    {
+        return data;
+    }
+    const MultidimArray<T>& operator()() const
+    {
+        return data;
+    }
+
+    /** Pixel access
+    *
+    * This operator is used to access a pixel within a 2D image. This is a
+    * logical access, so you could access to negative positions if the image
+    * has been defined so (see the general explanation for the class).
+    *
+    * @code
+    * std::cout << "Grey level of pixel (-3,-3) of the image = " << I(-3, -3)
+    * << std::endl;
+    *
+    * I(-3, -3) = I(-3, -2);
+    * @endcode
+    */
+    T& operator()(int i, int j) const
+    {
+        return A2D_ELEM(data, i, j);
+    }
+    /** Set pixel
+     * (direct access) needed by swig
+     */
+    void setPixel(int i, int j, T v)
+    {
+        IMGPIXEL(*this,i,j)=v;
+    }
+
+    /** Get pixel
+     * (direct acces) needed by swig
+     */
+    T getPixel(int i, int j) const
+    {
+        return IMGPIXEL(*this,i,j);
+    }
+
+    /** Voxel access
+     *
+     * This operator is used to access a voxel within a 3D image. This is a
+     * logical access, so you could access to negative positions if the image
+     * has been defined so (see the general explanation for the class).
+     *
+     * @code
+     * std::cout << "Grey level of pixel (-3,-3, 1) of the volume = " << I(-3, -3, 1)
+     * << std::endl;
+     *
+     * I(-3, -3, 1) = I(-3, -2, 0);
+     * @endcode
+     */
+    T& operator()(int k, int i, int j) const
+    {
+        return A3D_ELEM(data, k, i, j);
+    }
+
+    /** Get file name
+     *
+     * @code
+     * std::cout << "Image name = " << I.name() << std::endl;
+     * @endcode
+     */
+    const FileName & name() const
+    {
+        return filename;
+    }
+
+    /** Get Image dimensions
+     */
+    void getDimensions(int &Xdim, int &Ydim, int &Zdim, long int &Ndim) const
+    {
+        Xdim = XSIZE(data);
+        Ydim = YSIZE(data);
+        Zdim = ZSIZE(data);
+        Ndim = NSIZE(data);
+    }
+
+    long unsigned int getSize() const
+    {
+        return NZYXSIZE(data);
+    }
+
+    /* Is there label in the main header */
+    bool mainContainsLabel(EMDLabel label) const
+    {
+        return MDMainHeader.containsLabel(label);
+    }
+
+    /** Data type
+        *
+        * @code
+        * std::cout << "datatype= " << dataType() << std::endl;
+        * @endcode
+        */
+    int dataType() const
+    {
+        int dummy;
+        MDMainHeader.getValue(EMDL_IMAGE_DATATYPE, dummy);
+        return dummy;
+    }
+
+    /** Sampling RateX
+    *
+    * @code
+    * std::cout << "sampling= " << samplingRateX() << std::endl;
+    * @endcode
+    */
+    double samplingRateX(const long int n = 0) const
+    {
+        double dummy = 1.;
+        MDMainHeader.getValue(EMDL_IMAGE_SAMPLINGRATE_X, dummy);
+        return dummy;
+    }
+
+    /** Sampling RateY
+    *
+    * @code
+    * std::cout << "sampling= " << samplingRateY() << std::endl;
+    * @endcode
+    */
+    double samplingRateY(const long int n = 0) const
+    {
+        double dummy = 1.;
+        MDMainHeader.getValue(EMDL_IMAGE_SAMPLINGRATE_Y, dummy);
+        return dummy;
+    }
+
+    /** Set file name
+     */
+    void setName(const FileName &_filename)
+    {
+        filename = _filename;
+    }
+
+    /* Set image statistics in the main header
+     *
+     */
+    void setStatisticsInHeader()
+    {
+    	double avg,stddev,minval,maxval;
+    	data.computeStats(avg, stddev, minval, maxval);
+    	MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG, avg);
+    	MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV, stddev);
+    	MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN, minval);
+    	MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX, maxval);
+    }
+
+    void setSamplingRateInHeader(double rate_x, double rate_y = -1., double rate_z = -1.)
+    {
+    	MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_X, rate_x);
+    	if (rate_y < 0.)
+    		rate_y = rate_x;
+    	MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Y, rate_y);
+    	if (ZSIZE(data)>1)
+    	{
+    	   	if (rate_z < 0.)
+    	    	rate_z = rate_x;
+    	   	MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Z, rate_z);
+    	}
+    }
+
+    /** Show image properties
+      */
+    friend std::ostream& operator<<(std::ostream& o, const Image<T>& I)
+    {
+        o << "Image type   : ";
+            o << "Real-space image" << std::endl;
+
+        o << "Reversed     : ";
+        if (I.swap)
+            o << "TRUE"  << std::endl;
+        else
+            o << "FALSE" << std::endl;
+
+        o << "Data type    : ";
+        switch (I.dataType())
+        {
+        case Unknown_Type:
+            o << "Undefined data type";
+            break;
+        case UChar:
+            o << "Unsigned character or byte type";
+            break;
+        case SChar:
+            o << "Signed character (for CCP4)";
+            break;
+        case UShort:
+            o << "Unsigned integer (2-byte)";
+            break;
+        case Short:
+            o << "Signed integer (2-byte)";
+            break;
+        case UInt:
+            o << "Unsigned integer (4-byte)";
+            break;
+        case Int:
+            o << "Signed integer (4-byte)";
+            break;
+        case Long:
+            o << "Signed integer (4 or 8 byte, depending on system)";
+            break;
+        case Float:
+            o << "Floating point (4-byte)";
+            break;
+        case Double:
+            o << "Double precision floating point (8-byte)";
+            break;
+        case Bool:
+            o << "Boolean (1-byte?)";
+            break;
+        }
+        o << std::endl;
+
+        o << "dimensions   : " << NSIZE(I()) << " x " << ZSIZE(I()) << " x " << YSIZE(I()) << " x " << XSIZE(I());
+        o << "  (noObjects x slices x rows x columns)" << std::endl;
+        return o;
+    }
+
+    /** Sum this object with other file and keep in this object
+      */
+    void sumWithFile(const FileName &fn)
+    {
+        Image<T> aux;
+        aux.read(fn);
+        (*this)()+=aux();
+    }
+
+    /** Open file function
+      * Open the image file and returns its file hander.
+      */
+    fImageHandler* openFile(const FileName &name, int mode = WRITE_READONLY)
+    {
+        fImageHandler* hFile = new fImageHandler;
+        FileName fileName, headName = "";
+        FileName ext_name = name.getFileFormat();
+
+        long int dump;
+        name.decompose(dump, fileName);
+        // Subtract 1 to have numbering 0...N-1 instead of 1...N
+        if (dump > 0)
+        	dump--;
+
+        fileName = fileName.removeFileFormat();
+
+        size_t found = fileName.find_first_of("%");
+        if (found!=std::string::npos)
+          fileName = fileName.substr(0, found) ;
+
+        hFile->exist = exists(fileName);
+
+        std::string wmChar;
+
+        switch (mode)
+        {
+        case WRITE_READONLY:
+            if (!hFile->exist)
+                REPORT_ERROR((std::string) "Cannot read file " + fileName + " It does not exist" );
+            wmChar = "r";
+            break;
+        case WRITE_OVERWRITE:
+            wmChar = "w";
+            break;
+        case WRITE_APPEND:
+            if (_exists = exists(fileName))
+                wmChar = "r+";
+            else
+                wmChar = "w+";
+            break;
+        case WRITE_REPLACE:
+            wmChar = "r+";
+            break;
+        }
+
+
+        if (ext_name.contains("img") || ext_name.contains("hed"))
+        {
+            fileName = fileName.withoutExtension();
+            headName = fileName.addExtension("hed");
+            fileName = fileName.addExtension("img");
+        }
+
+        // Open image file
+        if ( ( hFile->fimg = fopen(fileName.c_str(), wmChar.c_str()) ) == NULL )
+            REPORT_ERROR((std::string)"Image::openFile cannot open: " + name);
+
+        if (headName != "")
+        {
+            if ( ( hFile->fhed = fopen(headName.c_str(), wmChar.c_str()) ) == NULL )
+                REPORT_ERROR((std::string)"Image::openFile cannot open: " + headName);
+        }
+        else
+            hFile->fhed = NULL;
+
+        hFile->ext_name =ext_name;
+
+        return hFile;
+    }
+
+    /** Close file function.
+      * Close the image file according to its name and file handler.
+      */
+    void closeFile(fImageHandler* hFile = NULL)
+    {
+        FileName ext_name;
+        FILE* fimg, *fhed;
+
+        if (hFile != NULL)
+        {
+            ext_name = hFile->ext_name;
+            fimg = hFile->fimg;
+            fhed = hFile->fhed;
+        }
+        else
+        {
+            ext_name = filename.getFileFormat();
+            fimg = this->fimg;
+            fhed = this->fhed;
+        }
+
+        if (fclose(fimg) != 0 )
+            REPORT_ERROR((std::string)"Can not close image file "+ filename);
+
+        if (fhed != NULL &&  fclose(fhed) != 0 )
+            REPORT_ERROR((std::string)"Can not close header file of "
+                         + filename);
+
+        delete hFile;
+    }
+
+private:
+    int _read(const FileName &name, fImageHandler* hFile, bool readdata=true, long int select_img = -1,
+              bool mapData = false, bool is_2D = false)
+    {
+        int err = 0;
+
+        // Check whether to read the data or only the header
+        dataflag = ( readdata ) ? 1 : -1;
+
+        // Check whether to map the data or not
+        mmapOn = mapData;
+
+        FileName ext_name = hFile->ext_name;
+        fimg = hFile->fimg;
+        fhed = hFile->fhed;
+
+        long int dump;
+        name.decompose(dump, filename);
+        // Subtract 1 to have numbering 0...N-1 instead of 1...N
+        if (dump > 0)
+        	dump--;
+        filename = name;
+
+        if (select_img == -1)
+            select_img = dump;
+
+#undef DEBUG
+        //#define DEBUG
+#ifdef DEBUG
+
+        std::cerr << "READ\n" <<
+        "name="<<name <<std::endl;
+        std::cerr << "ext= "<<ext_name <<std::endl;
+        std::cerr << " now reading: "<< filename <<" dataflag= "<<dataflag
+        << " select_img "  << select_img << std::endl;
+#endif
+#undef DEBUG
+
+        //Just clear the header before reading
+        MDMainHeader.clear();
+        MDMainHeader.addObject();
+
+        if (ext_name.contains("spi") || ext_name.contains("xmp")  ||
+            ext_name.contains("stk") || ext_name.contains("vol"))//mrc stack MUST go BEFORE plain MRC
+            err = readSPIDER(select_img);
+        else if (ext_name.contains("mrcs") || (is_2D && ext_name.contains("mrc")) )//mrc stack MUST go BEFORE plain MRC
+            err = readMRC(select_img, true);
+        else if (select_img >= 0 && ext_name.contains("mrc"))
+        	REPORT_ERROR("Image::read ERROR: stacks of images in MRC-format should have extension .mrcs; .mrc extensions are reserved for 3D maps.");
+        else if (ext_name.contains("mrc")) // mrc 3D map
+            err = readMRC(select_img, false);
+        else if (ext_name.contains("img") || ext_name.contains("hed"))//
+            err = readIMAGIC(select_img);//imagic is always an stack
+        else
+            err = readSPIDER(select_img);
+
+        // Negative errors are bad.
+        return err;
+    }
+
+
+
+
+    void _write(const FileName &name, fImageHandler* hFile, long int select_img=-1,
+                bool isStack=false, int mode=WRITE_OVERWRITE)
+    {
+        int err = 0;
+
+        FileName ext_name = hFile->ext_name;
+        fimg = hFile->fimg;
+        fhed = hFile->fhed;
+        _exists = hFile->exist;
+
+        filename = name;
+
+        long int aux;
+        FileName filNamePlusExt(name);
+        name.decompose(aux, filNamePlusExt);
+        // Subtract 1 to have numbering 0...N-1 instead of 1...N
+        if (aux > 0)
+        	aux--;
+
+        if (select_img == -1)
+            select_img = aux;
+
+        size_t found = filNamePlusExt.find_first_of("%");
+
+        std::string imParam = "";
+
+        if (found!=std::string::npos)
+        {
+            imParam =  filNamePlusExt.substr(found+1).c_str();
+            filNamePlusExt = filNamePlusExt.substr(0, found) ;
+        }
+
+        found = filNamePlusExt.find_first_of(":");
+        if ( found!=std::string::npos)
+            filNamePlusExt   = filNamePlusExt.substr(0, found);
+
+//#define DEBUG
+#ifdef DEBUG
+
+        std::cerr << "write" <<std::endl;
+        std::cerr<<"extension for write= "<<ext_name<<std::endl;
+        std::cerr<<"filename= "<<filename<<std::endl;
+        std::cerr<<"mode= "<<mode<<std::endl;
+        std::cerr<<"isStack= "<<isStack<<std::endl;
+        std::cerr<<"select_img= "<<select_img<<std::endl;
+#endif
+#undef DEBUG
+        // Check that image is not empty
+        if (getSize() < 1)
+            REPORT_ERROR("write Image ERROR: image is empty!");
+
+        // CHECK FOR INCONSISTENCIES BETWEEN data.xdim and x, etc???
+        int Xdim, Ydim, Zdim;
+        long int Ndim;
+        this->getDimensions(Xdim,Ydim, Zdim, Ndim);
+
+        Image<T> auxI;
+        replaceNsize=0;//reset replaceNsize in case image is reused
+        if(select_img == -1 && mode == WRITE_REPLACE)
+            REPORT_ERROR("write: Please specify object to be replaced");
+        else if(!_exists && mode == WRITE_REPLACE)
+        {
+            std:: stringstream replace_number;
+            replace_number << select_img;
+            REPORT_ERROR((std::string)"Cannot replace object number: "
+                         + replace_number.str()
+                         + " in file " +filename
+                         + ". It does not exist");
+        }
+        else if (_exists && (mode == WRITE_REPLACE || mode == WRITE_APPEND))
+        {
+            auxI.dataflag = -2;
+            auxI.read(filNamePlusExt,false);
+            int _Xdim, _Ydim, _Zdim;
+            long int _Ndim;
+            auxI.getDimensions(_Xdim,_Ydim, _Zdim, _Ndim);
+            replaceNsize=_Ndim;
+            if(Xdim!=_Xdim ||
+               Ydim!=_Ydim ||
+               Zdim!=_Zdim
+              )
+            	REPORT_ERROR("write: target and source objects have different size");
+            if(mode==WRITE_REPLACE && select_img>_Ndim)
+                REPORT_ERROR("write: cannot replace image stack is not large enough");
+            if(auxI.replaceNsize <1 &&
+               (mode==WRITE_REPLACE || mode==WRITE_APPEND))
+                REPORT_ERROR("write: output file is not an stack");
+        }
+        else if(!_exists && mode==WRITE_APPEND)
+        {
+            ;
+        }
+        else if (mode == WRITE_READONLY)//If new file we are in the WRITE_OVERWRITE mode
+        {
+            REPORT_ERROR( (std::string) "File " + name
+                         + " opened in read-only mode. Cannot write.");
+        }
+
+        /*
+         * SELECT FORMAT
+         */
+        if(ext_name.contains("spi") || ext_name.contains("xmp") ||
+           ext_name.contains("stk") || ext_name.contains("vol"))
+            err = writeSPIDER(select_img,isStack,mode);
+        else if (ext_name.contains("mrcs"))
+            writeMRC(select_img,true,mode);
+        else if (ext_name.contains("mrc"))
+            writeMRC(select_img,false,mode);
+        else if (ext_name.contains("img") || ext_name.contains("hed"))
+            writeIMAGIC(select_img,mode);
+        else
+            err = writeSPIDER(select_img,isStack,mode);
+        if ( err < 0 )
+        {
+            std::cerr << " Filename = " << filename << " Extension= " << ext_name << std::endl;
+            REPORT_ERROR((std::string)"Error writing file "+ filename + " Extension= " + ext_name);
+        }
+
+        /* If initially the file did not existed, once the first image is written,
+         * then the file exists
+         */
+        if (!_exists)
+            hFile->exist = _exists = true;
+    }
+
+
+};
+
+// Some image-specific operations
+
+// For image normalization
+void normalise(Image<double> &I, int bg_radius, double white_dust_stddev, double black_dust_stddev);
+
+void calculateBackgroundAvgStddev(Image<double> &I, double &avg, double &stddev, int bg_radius);
+
+// For dust removal
+void removeDust(Image<double> &I, bool is_white, double thresh, double avg, double stddev);
+
+// for contrast inversion
+void invert_contrast(Image<double> &I);
+
+// for image re-scaling
+void rescale(Image<double> &I, int mysize);
+
+// for image re-windowing
+void rewindow(Image<double> &I, int mysize);
+
+
+
+/// @defgroup ImageFormats Image Formats
+/// @ingroup Images
+// Functions belonging to this topic are commented in rw*.h
+//@}
+#endif
diff --git a/src/macros.h b/src/macros.h
new file mode 100644
index 0000000..0c35fc4
--- /dev/null
+++ b/src/macros.h
@@ -0,0 +1,391 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef MACROS_H
+#define MACROS_H
+
+#ifndef _CYGWIN
+#ifdef __APPLE__
+#include <limits.h>
+#else
+#include <values.h>
+#endif
+#endif
+
+#ifndef MINFLOAT
+#define MINFLOAT -1e30
+#endif
+#ifndef MAXFLOAT
+#define MAXFLOAT  1e30
+#endif
+
+//#define DEBUG
+//#define DEBUG_CHECKSIZES
+
+/// @defgroup Macros Macros
+/// @ingroup DataLibrary
+//@{
+/// @name Constants
+//@{
+
+/** Pi
+ * @ingroup MacrosConstants
+ */
+#ifndef PI
+#define PI 3.14159265358979323846
+#endif
+
+/** Equal accuracy
+ *
+ * In a comparison if two values are closer than this epsilon they are said to
+ * be the same. Actually set to 1e-6
+ */
+#define XMIPP_EQUAL_ACCURACY 1e-6
+//@}
+
+/// @name Numerical functions
+//@{
+/** Absolute value
+ *
+ * Valid for any kind of number (int, short, float, etc)
+ *
+ * @code
+ * x = ABS(x);
+ * @endcode
+ */
+#ifndef ABS
+#define ABS(x) (((x) >= 0) ? (x) : (-(x)))
+#endif
+
+/** Sign of
+ *
+ * Valid for any kind of number (int, short, float, etc). It returns +1 or -1
+ *
+ * @code
+ * if (SGN(x) == -1)
+ *     std::cout << "x is negative" << std::endl;
+ * @endcode
+ */
+#ifndef SGN
+#define SGN(x) (((x) >= 0) ? 1 : -1)
+#endif
+
+/** Sign of, considering 0 as 0
+ *
+ * Valid for any kind of number (int, short, float, etc). It returns +1 if the
+ * number is positive, -1 if the number is negative, and 0 if the number is 0.
+ *
+ * @code
+ * if (SGN0(x) == -1)
+ *     std::cout << "x is negative" << std::endl;
+ * @endcode
+ */
+#ifndef SGN0
+#define SGN0(x) (((x) >= 0) ? (((x) == 0) ? 0:1) : -1)
+#endif
+
+/** Minimum
+ *
+ * Valid for any kind of numbers (int, short, float, etc).
+ *
+ * @code
+ * min_val = XMIPP_MIN(x, y);
+ * @endcode
+ */
+#ifndef XMIPP_MIN
+#define XMIPP_MIN(x, y) (((x) >= (y)) ? (y) : (x))
+#endif
+
+/** Maximum
+ *
+ * Valid for any kind of numbers (int, short, float, etc).
+ *
+ * @code
+ * max_val = XMIPP_MAX(x, y);
+ * @endcode
+ */
+#ifndef XMIPP_MAX
+#define XMIPP_MAX(x,y) (((x)>=(y))?(x):(y))
+#endif
+
+/** Round to next integer
+ *
+ * Valid for any kind of numbers (int, short, float, etc). The result is of type
+ * integer.
+ *
+ * @code
+ * a = ROUND(-0.8); // a = -1
+ * a = ROUND(-0.2); // a = 0
+ * a = ROUND(0.2); // a = 0
+ * a = ROUND(0.8); // a = 1
+ * @endcode
+ */
+#ifndef ROUND
+#define ROUND(x) (((x) > 0) ? (int)((x) + 0.5) : (int)((x) - 0.5))
+#endif
+
+/** Round to next larger integer
+ *
+ * Valid for any kind of numbers (int, short, float, etc). The result is of type
+ * integer.
+ *
+ * @code
+ * a = CEIL(-0.8); // a = 0
+ * a = CEIL(-0.2); // a = 0
+ * a = CEIL(0.2); // a = 1
+ * a = CEIL(0.8); // a = 1
+ * @endcode
+ */
+#define CEIL(x) (((x) == (int)(x)) ? (int)(x):(((x) > 0) ? (int)((x) + 1) : \
+                 (int)(x)))
+
+/** Round to next smaller integer
+ *
+ * Valid for any kind of numbers (int, short, float, etc). The result is of type
+ * integer.
+ *
+ * @code
+ * a = FLOOR(-0.8); // a = -1
+ * a = FLOOR(-0.2); // a = -1
+ * a = FLOOR(0.2); // a = 0
+ * a = FLOOR(0.8); // a = 0
+ * @endcode
+ */
+#define FLOOR(x) (((x) == (int)(x)) ? (int)(x):(((x) > 0) ? (int)(x) : \
+                  (int)((x) - 1)))
+
+/** Return the fractional part of a value
+ *
+ * The fractional part of 3.7 is 0.7 and of -3.7 is -0.7.
+ */
+#define FRACTION(x) ((x) - (int)(x))
+
+/** Clip in a saturation fashion
+ *
+ * CLIP is a macro which acts like a saturation curve, a value x is "clipped" to
+ * a range defined by x0 and xF, for example the output values for the following
+ * x and CLIP(x,-2,2) would be
+ *
+ * @code
+ * x = ... -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 ...
+ * output = ... -2 -2 -2 -2 -2 -2 -2 -1 0 1 2 2 2 2 2 2 2 ...
+ * @endcode
+ */
+#define CLIP(x, x0, xF) (((x) < (x0)) ? (x0) : (((x) > (xF)) ? (xF) : (x)))
+
+/** Wrapping for integers
+ *
+ * intWRAP performs a wrapping in the integer set, when the cycle is finsihed it
+ * begins again. For example, for intWRAP(x,-2,2) would be
+ *
+ * @code
+ * x = ... -8 -7 -6 -5 -4 -3 -2 -1  0  1  2  3  4  5  6  7  8 ...
+ * output = ...  2 -2 -1  0  1  2 -2 -1  0  1  2 -2 -1  0  1  2 -2 ...
+ * @endcode
+ */
+#define intWRAP(x, x0, xF) (((x) >= (x0) && (x) <= (xF)) ? (x) : ((x) < (x0)) \
+                            ? ((x) - (int)(((x) - (x0) + 1) / ((xF) - (x0) + 1) - 1) * \
+                               ((xF) - (x0) + 1)) : ((x) - (int)(((x) - (xF) - 1) / ((xF) - (x0) + 1) \
+                                                                 + 1) * ((xF) - (x0) + 1)))
+
+/** Wrapping for real numbers
+ *
+ * realWRAP is used to keep a floating number between a range with a wrapping
+ * fashion. For instance, it is used in trigonometry to say that an angle of
+ * 5*PI is the same as PI, ie, to keep an angle in the range 0...2*PI
+ *
+ * @code
+ * Corrected_angle = realWRAP(angle, 0, 2*PI);
+ * @endcode
+ */
+#define realWRAP(x, x0, xF) (((x) >= (x0) && (x) <= (xF)) ? (x) : ((x) < (x0)) \
+                             ? ((x) - (int)(((x) - (x0)) / ((xF) - (x0)) - 1) * ((xF) - (x0))) : \
+                             ((x) - (int)(((x) - (xF)) / ((xF) - (x0)) + 1) * ((xF) - (x0))))
+
+/** Degrees to radians
+ *
+ * @code
+ * angle_in_radians = DEG2RAD(ang_in_degrees);
+ * @endcode
+ */
+#define DEG2RAD(d) ((d) * PI / 180)
+
+/** Radians to degrees
+ *
+ * @code
+ * angle_in_degrees = RAD2DEG(ang_in_radians);
+ * @endcode
+ */
+#define RAD2DEG(r) ((r) * 180 / PI)
+
+/** Cosine in degrees
+ *
+ * @code
+ * if (COSD(90) == 0)
+ *     std::cout << "This is in degrees!\n";
+ * @endcode
+ */
+#define COSD(x) cos(PI * (x) / 180.)
+
+/** ArcCosine in degrees
+ *
+ * @code
+ * if (ACOSD(0.5) == 60)
+ *     std::cout << "This is in degrees!\n";
+ * @endcode
+ */
+#define ACOSD(x) acos((x)) * 180. / PI
+
+/** Sine in degrees
+ *
+ * @code
+ * if (SIND(90) == 1)
+ *     std::cout << "This is in degrees!\n";
+ * @endcode
+ */
+#define SIND(x) sin(PI * (x) / 180.)
+
+/** ArcSine in degrees
+ *
+ * @code
+ * if (ASIND(0.5) == 30.)
+ *     std::cout << "This is in degrees!\n";
+ * @endcode
+ */
+#define ASIND(x) asin((x)) * 180. / PI
+
+/** SINC function
+ *
+ * The sinc function is defined as sin(PI*x)/(PI*x).
+ */
+#define SINC(x) (((x) < 0.0001 && (x) > -0.0001) ? 1 : sin(PI * (x)) \
+                 / (PI * (x)))
+
+/** Returns next positive power_class of 2
+ *
+ * It is supposed that the given number is positive although it's not needed to
+ * be an integer
+ *
+ * @code
+ * next_power = NEXT_POWER_OF_2(1000); // next_power = 1024
+ * @endcode
+ */
+#define NEXT_POWER_OF_2(x) pow(2, ceil(log((double) x) / log(2.0)-XMIPP_EQUAL_ACCURACY) )
+
+/** Linear interpolation
+ *
+ * From low (when a=0) to high (when a=1). The following value is returned
+ * (equal to (a*h)+((1-a)*l)
+ */
+#define LIN_INTERP(a, l, h) ((l) + ((h) - (l)) * (a))
+
+/** Cubic B-spline
+ *
+ */
+#define BSPLINE03(arg,result) {\
+	double x = ABS(arg); \
+	if (x < 1.0) \
+	    result=(x * x * (x - 2.0) * (1.0 / 2.0) + 2.0 / 3.0);\
+	else if (x < 2.0) { \
+	    x -= 2.0;\
+	    result=x*x*x*(-1.0 / 6.0); \
+	} else \
+            result=0;\
+    }
+
+/** XOR
+ *
+ * Logical Xor
+ */
+#define XOR(a, b) (((a) && !(b)) || (!(a) && (b)))
+//@}
+
+/// @name Miscellaneous
+//@{
+
+/** Speed up temporary variables
+ *
+ * The following variables are provided:
+ *
+ * @code
+ * float spduptmp0, spduptmp1, spduptmp2;
+ * int ispduptmp0, ispduptmp1, ispduptmp2, ispduptmp3, ispduptmp4, ispduptmp5;
+ * @endcode
+ */
+#define SPEED_UP_temps \
+    double spduptmp0, spduptmp1, spduptmp2, \
+    spduptmp3, spduptmp4, spduptmp5, \
+    spduptmp6, spduptmp7, spduptmp8; \
+    int   ispduptmp0, ispduptmp1, ispduptmp2, \
+    ispduptmp3, ispduptmp4, ispduptmp5;
+
+/** Swap two values
+ *
+ * It uses a temporal variable which must be of the same type as the two
+ * parameters
+ */
+#define SWAP(a, b, tmp) {\
+        tmp = a; \
+        a = b; \
+        b = tmp; }
+
+/** Starting point for Xmipp volume/image
+ *
+ * Given a size (in some direction), this function returns the first index for
+ * a volume/image/array with this size. The formula is -(int) ((float) (size)
+ * / 2.0)
+ */
+#define FIRST_XMIPP_INDEX(size) -(long int)((float) (size) / 2.0)
+
+/** Starting point for Xmipp volume/image
+ * @ingroup MacrosMisc
+ *
+ * Given a size (in some direction), this function returns the first index for a
+ * volume/image/array with this size. The formula is FIRST_XMIPP_INDEX(size) +
+ * (size) - 1
+ */
+#define LAST_XMIPP_INDEX(size) FIRST_XMIPP_INDEX(size) + (size) - 1
+//@}
+//@}
+#endif
diff --git a/src/manualpicker.cpp b/src/manualpicker.cpp
new file mode 100644
index 0000000..33ffa46
--- /dev/null
+++ b/src/manualpicker.cpp
@@ -0,0 +1,510 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include "src/manualpicker.h"
+
+std::vector<int> imics;
+std::vector<FileName> global_fn_mics;
+std::vector<FileName> global_fn_ctfs;
+std::vector<bool> selected;
+std::vector<int> number_picked;
+std::vector<Fl_Button*> viewmic_buttons;
+std::vector<Fl_Button*> viewctf_buttons;
+std::vector<Fl_Text_Display*> text_displays;
+std::vector<Fl_Text_Display*> count_displays;
+std::vector<Fl_Check_Button*> check_buttons;
+int last_pick_viewed;
+int last_ctf_viewed;
+
+
+bool   global_has_ctf;
+double global_angpix;
+double global_lowpass;
+double global_particle_diameter;
+double global_sigma_contrast;
+double global_black_val;
+double global_white_val;
+double global_micscale;
+double global_ctfscale;
+double global_blue_value;
+double global_red_value;
+int    global_total_count;
+FileName global_pickname;
+FileName global_fn_color;
+FileName global_color_label;
+bool global_do_color;
+
+
+void cb_viewmic(Fl_Widget* w, void* data)
+{
+
+	// Get my own number back
+	int *iptr = (int*)data;
+	int imic = *iptr;
+
+	// Update the count of the last one we picked...
+	if (last_pick_viewed >= 0 && last_pick_viewed < count_displays.size() && selected[last_pick_viewed])
+	{
+		MetaDataTable MDcoord;
+		FileName fn_coord = global_fn_mics[last_pick_viewed].withoutExtension() + "_" + global_pickname + ".star";
+		int my_nr_picked;
+		if (exists(fn_coord))
+		{
+			MDcoord.read(fn_coord);
+			my_nr_picked = MDcoord.numberOfObjects();
+		}
+		else
+		{
+			my_nr_picked = 0;
+		}
+		Fl_Text_Buffer *textbuff2 = new Fl_Text_Buffer();
+		textbuff2->text(floatToString(my_nr_picked).c_str());
+		count_displays[last_pick_viewed]->buffer(textbuff2);
+		count_displays[last_pick_viewed]->redraw();
+	}
+
+	FileName fn_coord = global_fn_mics[imic].withoutExtension() + "_" + global_pickname + ".star";
+
+	int rad = ROUND(global_particle_diameter/(2. * global_angpix));
+	std::string command;
+	command =  "relion_display --pick  --i " + global_fn_mics[imic];
+	command += "  --coords " + fn_coord;
+	command += " --scale " + floatToString(global_micscale);
+	command += " --black "  + floatToString(global_black_val);
+	command += " --white "  + floatToString(global_white_val);
+	command += " --sigma_contrast "  + floatToString(global_sigma_contrast);
+	command += " --particle_radius " + floatToString(rad);
+	command += " --lowpass " + floatToString(global_lowpass);
+	command += " --angpix " + floatToString(global_angpix);
+
+	if (global_color_label != "")
+	{
+		command += " --color_label " + global_color_label;
+		command += " --blue " + floatToString(global_blue_value);
+		command += " --red " + floatToString(global_red_value);
+		if (global_fn_color != "")
+			command += " --color_star " + global_fn_color;
+	}
+
+	command += " &";
+	std::cerr << command << std::endl;
+	system(command.c_str());
+
+	last_pick_viewed = imic;
+	for (int i = 0; i < viewmic_buttons.size(); i++)
+	{
+		if (i == last_pick_viewed)
+		{
+			viewmic_buttons[i]->color(GUI_BUTTON_DARK_COLOR, GUI_BUTTON_DARK_COLOR);
+		}
+		else
+		{
+			viewmic_buttons[i]->color(GUI_BUTTON_COLOR, GUI_BUTTON_COLOR);
+		}
+		viewmic_buttons[i]->redraw();
+	}
+
+
+}
+
+void cb_viewctf(Fl_Widget* w, void* data)
+{
+
+	// Get my own number back
+	int *iptr = (int*)data;
+	int imic = *iptr;
+
+	std::string command;
+	command =  "relion_display --i " + global_fn_ctfs[imic];
+	command += " --scale " + floatToString(global_ctfscale);
+	command += " &";
+	std::cerr << command << std::endl;
+	system(command.c_str());
+
+	last_ctf_viewed = imic;
+	for (int i = 0; i < viewctf_buttons.size(); i++)
+	{
+		if (i == last_ctf_viewed)
+		{
+			viewctf_buttons[i]->color(GUI_BUTTON_DARK_COLOR, GUI_BUTTON_DARK_COLOR);
+		}
+		else
+		{
+			viewctf_buttons[i]->color(GUI_BUTTON_COLOR, GUI_BUTTON_COLOR);
+		}
+		viewctf_buttons[i]->redraw();
+	}
+
+
+}
+
+void cb_selectmic(Fl_Widget* w, void* data)
+{
+
+	// Get my own number back
+	int *iptr = (int*)data;
+	int imic = *iptr;
+
+	Fl_Text_Buffer *textbuff2 = new Fl_Text_Buffer();
+	selected[imic] = !selected[imic];
+	if (selected[imic])
+	{
+		text_displays[imic]->color(GUI_INPUT_COLOR, GUI_INPUT_COLOR);
+		text_displays[imic]->activate();
+		viewmic_buttons[imic]->activate();
+		count_displays[imic]->color(GUI_INPUT_COLOR, GUI_INPUT_COLOR);
+		textbuff2->text(floatToString(number_picked[imic]).c_str());
+		count_displays[imic]->buffer(textbuff2);
+		count_displays[imic]->activate();
+		if (global_has_ctf)
+			viewctf_buttons[imic]->activate();
+	}
+	else
+	{
+		text_displays[imic]->color(GUI_BACKGROUND_COLOR, GUI_BACKGROUND_COLOR);
+		text_displays[imic]->deactivate();
+		viewmic_buttons[imic]->deactivate();
+		count_displays[imic]->color(GUI_BACKGROUND_COLOR, GUI_BACKGROUND_COLOR);
+		textbuff2->text("");
+		count_displays[imic]->buffer(textbuff2);
+		count_displays[imic]->deactivate();
+		if (global_has_ctf)
+			viewctf_buttons[imic]->deactivate();
+	}
+
+}
+
+int manualpickerGuiWindow::fill()
+{
+
+	color(GUI_BACKGROUND_COLOR);
+
+
+	Fl_Menu_Bar *menubar = new Fl_Menu_Bar(0, 0, w(), 25);
+    menubar->add("File/Save selection",  FL_ALT+'s', cb_menubar_save, this);
+    menubar->add("File/Recount picked particles",  FL_ALT+'c', cb_menubar_recount, this);
+    menubar->add("File/Quit", FL_ALT+'q', cb_menubar_quit, this);
+    int current_y = 25;
+
+    // Scroll bars
+    Fl_Scroll scroll(0, current_y, w(), h()-current_y);
+    scroll.type(Fl_Scroll::VERTICAL);
+
+	selected.clear();
+	number_picked.clear();
+
+	global_has_ctf = MDin.containsLabel(EMDL_CTF_IMAGE);
+
+	FileName fn_mic, fn_ctf;
+	int ystep = 35;
+
+	imics.clear();
+	for (int ii =0; ii < MDin.numberOfObjects(); ii++)
+	{
+		imics.push_back(ii);
+	}
+
+	int imic =0;
+	global_fn_mics.clear();
+	global_fn_ctfs.clear();
+	text_displays.clear();
+	viewmic_buttons.clear();
+	viewctf_buttons.clear();
+	number_picked.clear();
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDin)
+	{
+		MDin.getValue(EMDL_MICROGRAPH_NAME, fn_mic);
+		// Display the name of the micrograph
+		global_fn_mics.push_back(fn_mic);
+
+		Fl_Check_Button *mycheck = new Fl_Check_Button(4, current_y, ystep-8, ystep-8, "");
+		mycheck->callback(cb_selectmic, &(imics[imic]));
+		mycheck->value(1);
+		selected.push_back(true);
+		check_buttons.push_back(mycheck);
+
+		Fl_Text_Buffer *textbuff = new Fl_Text_Buffer();
+		textbuff->text(fn_mic.c_str());
+		int ystep2 = (fn_mic.length() > MWCOL1/12) ? ystep - 5 : ystep - 10;
+		Fl_Text_Display* mydisp = new Fl_Text_Display(MXCOL0, current_y, MWCOL1, ystep2);
+		mydisp->scrollbar_width(5);
+		mydisp->scroll(0,MWCOL1);
+		mydisp->buffer(textbuff);
+		mydisp->color(GUI_INPUT_COLOR, GUI_INPUT_COLOR);
+		text_displays.push_back(mydisp);
+
+		// Button to display the micrographimage
+		Fl_Button *myviewmic = new Fl_Button(MXCOL1, current_y, MWCOL2, ystep-5, "pick");
+		myviewmic->color(GUI_BUTTON_COLOR);
+		myviewmic->callback(cb_viewmic, &(imics[imic]));
+		viewmic_buttons.push_back(myviewmic);
+
+		// Count how many particles have been picked
+		Fl_Text_Buffer *textbuff2 = new Fl_Text_Buffer();
+		textbuff2->text("");
+		Fl_Text_Display* mycount = new Fl_Text_Display(MXCOL2, current_y, MWCOL3, ystep-5);
+		mycount->color(GUI_INPUT_COLOR, GUI_INPUT_COLOR);
+		mycount->buffer(textbuff2);
+		count_displays.push_back(mycount);
+		number_picked.push_back(10);
+
+		// Button to display the CTF image
+		if (global_has_ctf)
+		{
+			MDin.getValue(EMDL_CTF_IMAGE, fn_ctf);
+			global_fn_ctfs.push_back(fn_ctf);
+			// Button to display the CTF image
+			Fl_Button *myviewctf = new Fl_Button(MXCOL3, current_y, MWCOL4, ystep-5, "CTF");
+			myviewctf->color(GUI_BUTTON_COLOR);
+			myviewctf->callback(cb_viewctf, &(imics[imic]));
+			viewctf_buttons.push_back(myviewctf);
+		}
+
+		imic++;
+		current_y += ystep;
+	}
+
+
+	// See if the output STAR file already exists, if so apply that selection
+	readOutputStarfile();
+
+	// Also count the number of particles that were already picked
+	cb_menubar_recount_i();
+
+	resizable(*this);
+	show();
+	return Fl::run();
+
+}
+
+void manualpickerGuiWindow::readOutputStarfile()
+{
+
+	if (exists(fn_out))
+	{
+		for (int imic = 0; imic < selected.size(); imic++)
+			selected[imic] = false;
+		MetaDataTable MDout;
+		MDout.read(fn_out);
+		FileName fn_mic, fn_mic_in;
+		for (int imic = 0; imic < selected.size(); imic++)
+		{
+			MDin.getValue(EMDL_MICROGRAPH_NAME, fn_mic_in, imic);
+			bool has_found = false;
+			FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDout)
+			{
+				MDout.getValue(EMDL_MICROGRAPH_NAME, fn_mic);
+				// Which one in the input metadatatable was this one?
+				if (fn_mic == fn_mic_in)
+				{
+					has_found = true;
+					break;
+				}
+			}
+			selected[imic] = has_found;
+			if (has_found)
+			{
+				check_buttons[imic]->value(1);
+				text_displays[imic]->color(GUI_INPUT_COLOR, GUI_INPUT_COLOR);
+				text_displays[imic]->activate();
+				viewmic_buttons[imic]->activate();
+				count_displays[imic]->color(GUI_INPUT_COLOR, GUI_INPUT_COLOR);
+				count_displays[imic]->activate();
+				if (global_has_ctf)
+					viewctf_buttons[imic]->activate();
+			}
+			else
+			{
+				check_buttons[imic]->value(0);
+				text_displays[imic]->color(GUI_BACKGROUND_COLOR, GUI_BACKGROUND_COLOR);
+				text_displays[imic]->deactivate();
+				viewmic_buttons[imic]->deactivate();
+				count_displays[imic]->color(GUI_BACKGROUND_COLOR, GUI_BACKGROUND_COLOR);
+				count_displays[imic]->deactivate();
+				if (global_has_ctf)
+					viewctf_buttons[imic]->deactivate();
+			}
+		}
+	}
+}
+
+
+void manualpickerGuiWindow::writeOutputStarfile()
+{
+	MetaDataTable MDout;
+	for (int imic = 0; imic < selected.size(); imic++)
+	{
+		if (selected[imic])
+		{
+			MDout.addObject(MDin.getObject(imic));
+		}
+	}
+
+	MDout.write(fn_out);
+
+}
+void manualpickerGuiWindow::cb_menubar_save(Fl_Widget* w, void* v)
+{
+	manualpickerGuiWindow* T=(manualpickerGuiWindow*)v;
+    T->cb_menubar_save_i();
+
+}
+
+void manualpickerGuiWindow::cb_menubar_save_i()
+{
+	writeOutputStarfile();
+	std::cout << " Saved " << fn_out << std::endl;
+}
+
+void manualpickerGuiWindow::cb_menubar_quit(Fl_Widget* w, void* v)
+{
+	manualpickerGuiWindow* T=(manualpickerGuiWindow*)v;
+    T->cb_menubar_quit_i();
+
+}
+void manualpickerGuiWindow::cb_menubar_quit_i()
+{
+	cb_menubar_save_i();
+	exit(0);
+}
+
+void manualpickerGuiWindow::cb_menubar_recount(Fl_Widget* w, void* v)
+{
+	manualpickerGuiWindow* T=(manualpickerGuiWindow*)v;
+    T->cb_menubar_recount_i();
+
+}
+void manualpickerGuiWindow::cb_menubar_recount_i()
+{
+
+	global_total_count = 0;
+	int nr_sel_mic = 0;
+	for (int imic = 0; imic < global_fn_mics.size(); imic++)
+	{
+		MetaDataTable MDcoord;
+		FileName fn_coord = global_fn_mics[imic].withoutExtension() + "_" + global_pickname + ".star";
+		int my_nr_picked;
+		if (exists(fn_coord))
+		{
+			MDcoord.read(fn_coord);
+			my_nr_picked = MDcoord.numberOfObjects();
+		}
+		else
+		{
+			my_nr_picked = 0;
+		}
+		Fl_Text_Buffer *textbuff2 = new Fl_Text_Buffer();
+		if (selected[imic])
+		{
+			global_total_count += my_nr_picked;
+			textbuff2->text(floatToString(my_nr_picked).c_str());
+			count_displays[imic]->buffer(textbuff2);
+			count_displays[imic]->redraw();
+			nr_sel_mic++;
+		}
+		else
+		{
+			textbuff2->text("");
+			count_displays[imic]->buffer(textbuff2);
+		}
+		number_picked[imic] = my_nr_picked;
+	}
+	std::cout << " Total number of picked particles: " << global_total_count << " from " << nr_sel_mic << " selected micrographs." << std::endl;
+
+}
+
+
+
+void ManualPicker::read(int argc, char **argv)
+{
+	parser.setCommandLine(argc, argv);
+
+	int gen_section = parser.addSection("General options");
+	fn_in = parser.getOption("--i", "Micrograph STAR file OR filenames from which to pick particles, e.g. \"Micrographs/*.mrc\"");
+	fn_out = parser.getOption("--o", "Name for output STAR file", "micrographs_selected.star");
+	global_pickname = parser.getOption("--pickname", "Rootname for the picked coordinate files", "manualpick");
+	global_angpix = textToFloat(parser.getOption("--angpix", "Pixel size in Angstroms"));
+	global_particle_diameter = textToFloat(parser.getOption("--particle_diameter", "Diameter of the circles that will be drawn around each picked particle (in Angstroms)"));
+
+	int mic_section = parser.addSection("Displaying options");
+	global_micscale = textToFloat(parser.getOption("--scale", "Relative scale for the micrograph display", "1"));
+	global_black_val = textToFloat(parser.getOption("--black", "Pixel value for black (default is auto-contrast)", "0"));
+	global_white_val = textToFloat(parser.getOption("--white", "Pixel value for white (default is auto-contrast)", "0"));
+	global_sigma_contrast  = textToFloat(parser.getOption("--sigma_contrast", "Set white and black pixel values this many times the image stddev from the mean (default is auto-contrast)", "0"));
+	global_lowpass = textToFloat(parser.getOption("--lowpass", "Lowpass filter in Angstroms for the micrograph (0 for no filtering)","0"));
+
+	global_ctfscale = textToFloat(parser.getOption("--ctf_scale", "Relative scale for the CTF-image display", "1"));
+
+	// coloring
+	global_fn_color = parser.getOption("--color_star", "STAR file with a column for red-blue coloring (a subset of) the particles", "");
+	global_color_label = parser.getOption("--color_label", "MetaDataLabel to color particles on (e.g. rlnParticleSelectZScore)", "");
+	global_blue_value = textToFloat(parser.getOption("--blue", "Value of the blue color", "1."));
+	global_red_value = textToFloat(parser.getOption("--red", "Value of the red color", "0."));
+
+	// Check for errors in the command-line option
+	if (parser.checkForErrors())
+		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+}
+
+void ManualPicker::usage()
+{
+	parser.writeUsage(std::cerr);
+}
+
+void ManualPicker::initialise()
+{
+	// If we down-scale the micrograph: always low-pass filter to get better displays
+
+	if (global_micscale < 1.)
+	{
+		double new_nyquist = global_angpix * 2. / global_micscale;
+		if (new_nyquist > global_lowpass)
+			global_lowpass = new_nyquist;
+		std::cout << " Set low-pass filter to " << global_lowpass << " due to downscaling of " << global_micscale << std::endl;
+	}
+
+}
+
+void ManualPicker::run()
+{
+	Fl::scheme("gtk+");
+
+	manualpickerGuiWindow win(TOTALWIDTH, TOTALHEIGHT, "RELION manual-picking GUI");
+	if (fn_in.isStarFile())
+	{
+		MDin.read(fn_in);
+	}
+	else
+	{
+		std::vector<FileName> glob_fn_mics;
+		fn_in.globFiles(glob_fn_mics);
+		for (int imic = 0; imic < glob_fn_mics.size(); imic++)
+		{
+			MDin.addObject();
+			MDin.setValue(EMDL_MICROGRAPH_NAME, glob_fn_mics[imic]);
+		}
+	}
+
+	// Transfer all parameters to the gui
+	win.MDin = MDin;
+	win.fn_out = fn_out;
+	win.fill();
+
+}
diff --git a/src/manualpicker.h b/src/manualpicker.h
new file mode 100644
index 0000000..31a33cb
--- /dev/null
+++ b/src/manualpicker.h
@@ -0,0 +1,124 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef MANUALPICKER_H_
+#define MANUALPICKER_H_
+#include "src/metadata_table.h"
+#include "src/args.h"
+#include "src/filename.h"
+#include "src/gui_entries.h"
+#include <external/fltk-1.3.0/FL/Fl.H>
+#include <external/fltk-1.3.0/FL/Fl_Shared_Image.H>
+#include <external/fltk-1.3.0/FL/Fl_Double_Window.H>
+#include <external/fltk-1.3.0/FL/Fl_Scroll.H>
+#include <external/fltk-1.3.0/FL/Fl_Image.H>
+#include <external/fltk-1.3.0/FL/Fl_JPEG_Image.H>
+#include <external/fltk-1.3.0/FL/Fl_Box.H>
+#include <external/fltk-1.3.0/FL/fl_draw.H>
+#include <external/fltk-1.3.0/FL/Fl_Menu_Bar.H>
+#include <external/fltk-1.3.0/FL/Fl_File_Chooser.H>
+#include <external/fltk-1.3.0/FL/Fl_Float_Input.H>
+#include <external/fltk-1.3.0/FL/Fl_Text_Display.H>
+
+#define MWCOL1 300
+#define MWCOL2 60
+#define MWCOL3 60
+#define MWCOL4 60
+#define MXCOL0 30
+#define MXCOL1 (MXCOL0 + MWCOL1 + 10)
+#define MXCOL2 (MXCOL1 + MWCOL2 + 10)
+#define MXCOL3 (MXCOL2 + MWCOL3 + 10)
+#define TOTALWIDTH (MWCOL1 + MWCOL2 + MWCOL3 + MWCOL4 + 100)
+#define TOTALHEIGHT 500
+
+// The button for picking particles
+void cb_viewmic(Fl_Widget* w, void* data);
+// The button for viewing the CTF
+void cb_viewctf(Fl_Widget* w, void* data);
+// The selection button
+void cb_selectmic(Fl_Widget* w, void* data);
+
+// This class only puts scrollbars around the resizable canvas
+class manualpickerGuiWindow : public Fl_Window
+{
+public:
+
+	// Input, picking & output names
+	FileName fn_in, fn_out;
+
+	// MetaDataTable of input micrographs
+	MetaDataTable MDin;
+
+	// Constructor with w x h size of the window and a title
+	manualpickerGuiWindow(int W, int H, const char* title=0): Fl_Window(W, H, title){}
+
+	// Fill the window with all entries
+	int fill();
+
+private:
+
+    static void cb_menubar_save(Fl_Widget*, void*);
+    inline void cb_menubar_save_i();
+
+    static void cb_menubar_quit(Fl_Widget*, void*);
+    inline void cb_menubar_quit_i();
+
+    static void cb_menubar_recount(Fl_Widget*, void*);
+    inline void cb_menubar_recount_i();
+
+    void readOutputStarfile();
+    void writeOutputStarfile();
+
+};
+
+class ManualPicker
+{
+public:
+
+	// I/O Parser
+	IOParser parser;
+
+	// The input micrographs
+	MetaDataTable MDin;
+
+	// Input, picking & output names
+	FileName fn_in, fn_out;
+
+
+public:
+	// Read command line arguments
+	void read(int argc, char **argv);
+
+	// Print usage instructions
+	void usage();
+
+	// Initialise some general stuff after reading
+	void initialise();
+
+	// General function to decide what to do
+	void run();
+
+private:
+
+	void writeOutput();
+
+};
+
+#endif /* MANUALPICKER_H_ */
diff --git a/src/mask.cpp b/src/mask.cpp
new file mode 100644
index 0000000..7ffd19d
--- /dev/null
+++ b/src/mask.cpp
@@ -0,0 +1,332 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/mask.h"
+
+// Mask out corners outside sphere (replace by average value)
+// Apply a soft mask (raised cosine with cosine_width pixels width)
+void softMaskOutsideMap(MultidimArray<double> &vol, double radius, double cosine_width, MultidimArray<double> *Mnoise)
+{
+
+	vol.setXmippOrigin();
+	double r, radius_p, raisedcos, sum_bg = 0., sum = 0.;
+	if (radius < 0)
+		radius = (double)XSIZE(vol)/2.;
+	radius_p = radius + cosine_width;
+
+
+	if (Mnoise == NULL)
+	{
+		// Calculate average background value
+		FOR_ALL_ELEMENTS_IN_ARRAY3D(vol)
+		{
+			r = sqrt((double)(k*k + i*i + j*j));
+			if (r < radius)
+				continue;
+			else if (r > radius_p)
+			{
+				sum    += 1.;
+				sum_bg += A3D_ELEM(vol, k, i, j);
+			}
+			else
+			{
+				raisedcos = 0.5 + 0.5 * cos(PI * (radius_p - r) / cosine_width );
+				sum += raisedcos;
+				sum_bg += raisedcos * A3D_ELEM(vol, k, i, j);
+			}
+		}
+		sum_bg /= sum;
+	}
+
+	// Apply noisy or average background value
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(vol)
+	{
+		r = sqrt((double)(k*k + i*i + j*j));
+		if (r < radius)
+		{
+			continue;
+		}
+		else if (r > radius_p)
+		{
+			A3D_ELEM(vol, k, i, j) = (Mnoise == NULL) ? sum_bg : A3D_ELEM(*Mnoise, k, i, j);
+		}
+		else
+		{
+			raisedcos = 0.5 + 0.5 * cos(PI * (radius_p - r) / cosine_width );
+			double add = (Mnoise == NULL) ?  sum_bg : A3D_ELEM(*Mnoise, k, i, j);
+			A3D_ELEM(vol, k, i, j) = (1 - raisedcos) * A3D_ELEM(vol, k, i, j) + raisedcos * add;
+		}
+	}
+
+}
+
+void softMaskOutsideMap(MultidimArray<double> &vol, MultidimArray<double> &msk, bool invert_mask)
+{
+
+	if (msk.computeMax() > 1. || msk.computeMin() < 0.)
+	{
+		std::cerr << " msk.computeMax()= " << msk.computeMax() << " msk.computeMin()= " << msk.computeMin() << std::endl;
+		REPORT_ERROR("ERROR: Values in the solvent mask should be between zero and one.");
+	}
+	if (!(msk.sameShape(vol)))
+		REPORT_ERROR("ERROR: Solvent mask does not have the same size as the reference vol.");
+
+	// Replace solvent by the average value in the solvent region
+	double sum = 0.;
+	double sum_bg = 0.;
+	double solv;
+	FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(msk)
+	{
+		solv = (invert_mask) ? DIRECT_A3D_ELEM(msk, k, i, j) : 1. - DIRECT_A3D_ELEM(msk, k, i, j);
+		sum    += solv;
+		sum_bg += solv * DIRECT_A3D_ELEM(vol, k, i, j);
+	}
+	sum_bg /= sum;
+
+	FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(msk)
+	{
+		solv = (invert_mask) ? DIRECT_A3D_ELEM(msk, k, i, j) : 1. - DIRECT_A3D_ELEM(msk, k, i, j);
+		DIRECT_A3D_ELEM(vol, k, i, j) = ( 1. - solv) * DIRECT_A3D_ELEM(vol, k, i, j) + solv * sum_bg;
+	}
+
+
+}
+
+void autoMask(MultidimArray<double> &img_in, MultidimArray<double> &msk_out,
+		double ini_mask_density_threshold, double extend_ini_mask, double width_soft_mask_edge, bool verb)
+
+{
+	MultidimArray<double> msk_cp;
+	int barstep, update_bar, totalbar;
+
+	// Resize output mask
+	img_in.setXmippOrigin();
+	msk_out.clear();
+	msk_out.resize(img_in);
+
+	// A. Calculate initial binary mask based on density threshold
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(img_in)
+	{
+		if (DIRECT_MULTIDIM_ELEM(img_in, n) >= ini_mask_density_threshold)
+			DIRECT_MULTIDIM_ELEM(msk_out, n) = 1.;
+		else
+			DIRECT_MULTIDIM_ELEM(msk_out, n) = 0.;
+	}
+
+	// B. extend/shrink initial binary mask. To save memory store a temporary copy of Im in I1
+	if (extend_ini_mask > 0. || extend_ini_mask < 0.)
+	{
+		if (verb)
+		{
+			if (extend_ini_mask > 0.)
+				std::cout << "== Extending initial binary mask ..." << std::endl;
+			else
+				std::cout << "== Shrinking initial binary mask ..." << std::endl;
+			init_progress_bar(MULTIDIM_SIZE(img_in));
+			barstep = MULTIDIM_SIZE(img_in)/120;
+			update_bar = 0;
+			totalbar =0;
+		}
+
+		int extend_size = ABS(CEIL(extend_ini_mask));
+		double extend_ini_mask2 = extend_ini_mask * extend_ini_mask;
+		msk_cp = msk_out;
+		if (extend_ini_mask > 0.)
+		{
+			FOR_ALL_ELEMENTS_IN_ARRAY3D(msk_cp)
+			{
+				// only extend zero values to 1.
+				if (A3D_ELEM(msk_cp, k, i, j) < 0.001)
+				{
+					bool already_done = false;
+					for (long int kp = k - extend_size; kp <= k + extend_size; kp++)
+					{
+						for (long int ip = i - extend_size; ip <= i + extend_size; ip++)
+						{
+							for (long int jp = j - extend_size; jp <= j + extend_size; jp++)
+							{
+								if ((kp >= STARTINGZ(msk_cp) && kp <= FINISHINGZ(msk_cp)) &&
+									(ip >= STARTINGY(msk_cp) && ip <= FINISHINGY(msk_cp)) &&
+									(jp >= STARTINGX(msk_cp) && jp <= FINISHINGX(msk_cp)))
+								{
+									// only check distance if neighbouring Im() is one
+									if (A3D_ELEM(msk_cp, kp, ip, jp) > 0.999)
+									{
+										double r2 = (double)( (kp-k)*(kp-k) + (ip-i)*(ip-i)+ (jp-j)*(jp-j) );
+										// Set original voxel to 1 if a neghouring with Im()=1 is within distance extend_ini_mask
+										if (r2 < extend_ini_mask2)
+										{
+											A3D_ELEM(msk_out, k, i, j) = 1.;
+											already_done = true;
+										}
+									}
+								}
+								if (already_done) break;
+							}
+							if (already_done) break;
+						}
+						if (already_done) break;
+					}
+				}
+				if (verb)
+				{
+					if (update_bar > barstep)
+					{
+						update_bar = 0;
+						progress_bar(totalbar);
+					}
+					update_bar++;
+					totalbar++;
+				}
+			}
+		}
+		else
+		{
+			FOR_ALL_ELEMENTS_IN_ARRAY3D(msk_cp)
+			{
+				// only extend one values to zero.
+				if (A3D_ELEM(msk_cp, k, i, j) > 0.999)
+				{
+					bool already_done = false;
+					for (long int kp = k - extend_size; kp <= k + extend_size; kp++)
+					{
+						for (long int ip = i - extend_size; ip <= i + extend_size; ip++)
+						{
+							for (long int jp = j - extend_size; jp <= j + extend_size; jp++)
+							{
+								if ((kp >= STARTINGZ(msk_cp) && kp <= FINISHINGZ(msk_cp)) &&
+									(ip >= STARTINGY(msk_cp) && ip <= FINISHINGY(msk_cp)) &&
+									(jp >= STARTINGX(msk_cp) && jp <= FINISHINGX(msk_cp)))
+								{
+									// only check distance if neighbouring Im() is one
+									if (A3D_ELEM(msk_cp, kp, ip, jp) < 0.001)
+									{
+										double r2 = (double)( (kp-k)*(kp-k) + (ip-i)*(ip-i)+ (jp-j)*(jp-j) );
+										// Set original voxel to 1 if a neghouring with Im()=1 is within distance extend_ini_mask
+										if (r2 < extend_ini_mask2)
+										{
+											A3D_ELEM(msk_out, k, i, j) = 0.;
+											already_done = true;
+										}
+									}
+								}
+								if (already_done) break;
+							}
+							if (already_done) break;
+						}
+						if (already_done) break;
+					}
+				}
+				if (verb)
+				{
+					if (update_bar > barstep)
+					{
+						update_bar = 0;
+						progress_bar(totalbar);
+					}
+					update_bar++;
+					totalbar++;
+				}
+			}
+		}
+		if (verb)
+			progress_bar(MULTIDIM_SIZE(msk_out));
+	}
+
+	if (width_soft_mask_edge > 0.)
+	{
+		if (verb)
+		{
+			std::cout << "== Making a soft edge on the extended mask ..." << std::endl;
+			init_progress_bar(MULTIDIM_SIZE(msk_out));
+			barstep = MULTIDIM_SIZE(msk_out)/120;
+			update_bar = 0;
+			totalbar =0;
+		}
+		// C. Make a soft edge to the mask
+		// Note that the extended mask is now in I1, and we'll put the soft-edge mask again into Im
+
+		msk_cp = msk_out;
+		int extend_size = CEIL(width_soft_mask_edge);
+		double width_soft_mask_edge2 = width_soft_mask_edge * width_soft_mask_edge;
+		FOR_ALL_ELEMENTS_IN_ARRAY3D(msk_cp)
+		{
+			// only extend zero values to values between 0 and 1.
+			if (A3D_ELEM(msk_cp, k, i, j) < 0.001)
+			{
+				double min_r2 = 9999.;
+				for (long int kp = k - extend_size; kp <= k + extend_size; kp++)
+				{
+					for (long int ip = i - extend_size; ip <= i + extend_size; ip++)
+					{
+						for (long int jp = j - extend_size; jp <= j + extend_size; jp++)
+						{
+							if ((kp >= STARTINGZ(msk_cp) && kp <= FINISHINGZ(msk_cp)) &&
+								(ip >= STARTINGY(msk_cp) && ip <= FINISHINGY(msk_cp)) &&
+								(jp >= STARTINGX(msk_cp) && jp <= FINISHINGX(msk_cp)))
+							{
+								// only update distance to a neighbouring msk_cp is one
+								if (A3D_ELEM(msk_cp, kp, ip, jp) > 0.999)
+								{
+									double r2 = (double)( (kp-k)*(kp-k) + (ip-i)*(ip-i)+ (jp-j)*(jp-j) );
+									// Set original voxel to 1 if a neghouring with Im()=1 is within distance extend_ini_mask
+									if (r2 < min_r2)
+										min_r2 = r2;
+								}
+							}
+						}
+					}
+				}
+				if (min_r2 < width_soft_mask_edge2)
+				{
+					A3D_ELEM(msk_out, k, i, j) = 0.5 + 0.5 * cos( PI * sqrt(min_r2) / width_soft_mask_edge);
+				}
+			}
+			if (verb)
+			{
+				if (update_bar > barstep)
+				{
+					update_bar = 0;
+					progress_bar(totalbar);
+				}
+				update_bar++;
+				totalbar++;
+			}
+		}
+		if (verb)
+			progress_bar(MULTIDIM_SIZE(msk_cp));
+	}
+
+}
+void raisedCosineMask(MultidimArray<double> &mask, double radius, double radius_p, int x, int y, int z)
+{
+	mask.setXmippOrigin();
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(mask)
+	{
+		// calculate distance from the origin
+		double d = sqrt((double)((z-k)*(z-k) + (y-i)*(y-i) + (x-j)*(x-j)));
+		if (d > radius_p)
+			A3D_ELEM(mask, k, i, j) = 0.;
+		else if (d < radius)
+			A3D_ELEM(mask, k, i, j) = 1.;
+		else
+			A3D_ELEM(mask, k, i, j) = 0.5 - 0.5 * cos(PI * (radius_p - d) / (radius_p - radius));
+	}
+
+}
diff --git a/src/mask.h b/src/mask.h
new file mode 100644
index 0000000..7f63cd3
--- /dev/null
+++ b/src/mask.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef MASK_H_
+#define MASK_H_
+
+#include "src/multidim_array.h"
+#include "src/fftw.h"
+#include "src/time.h"
+
+// Mask out corners outside sphere (replace by average value)
+// Apply a soft mask (raised cosine with cosine_width pixels width)
+void softMaskOutsideMap(MultidimArray<double> &vol, double radius = -1., double cosine_width = 3, MultidimArray<double> *Mnoise = NULL);
+
+// Apply a soft mask and set density outside the mask at the average value of those pixels in the original map
+void softMaskOutsideMap(MultidimArray<double> &vol, MultidimArray<double> &msk, bool invert_mask = false);
+
+// Make an automated mask, based on:
+// 1. initial binarization (based on ini_mask_density_threshold)
+// 2. Growing extend_ini_mask in all directions
+// 3. Putting a raised-cosine edge on the mask with width width_soft_mask_edge
+// If verb, then output description of steps and progress bars
+void autoMask(MultidimArray<double> &img_in, MultidimArray<double> &msk_out,
+		double  ini_mask_density_threshold, double extend_ini_mask, double width_soft_mask_edge, bool verb = false);
+
+// Fills mask with a soft-edge circular mask (soft-edge in between radius and radius_p), centred at (x, y, z)
+void raisedCosineMask(MultidimArray<double> &mask, double radius, double radius_p, int x, int y, int z = 0);
+
+
+#endif /* MASK_H_ */
diff --git a/src/matrix1d.cpp b/src/matrix1d.cpp
new file mode 100644
index 0000000..c3ba17f
--- /dev/null
+++ b/src/matrix1d.cpp
@@ -0,0 +1,71 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include "src/matrix1d.h"
+
+Matrix1D<double> vectorR2(double x, double y)
+{
+    Matrix1D<double> result(2);
+    result( 0) = x;
+    result( 1) = y;
+    return result;
+}
+
+Matrix1D<double> vectorR3(double x, double y, double z)
+{
+    Matrix1D<double> result(3);
+    result( 0) = x;
+    result( 1) = y;
+    result( 2) = z;
+    return result;
+}
+
+Matrix1D<int> vectorR3(int x, int y, int z)
+{
+    Matrix1D<int> result(3);
+    result( 0) = x;
+    result( 1) = y;
+    result( 2) = z;
+    return result;
+}
diff --git a/src/matrix1d.h b/src/matrix1d.h
new file mode 100644
index 0000000..33e6ed6
--- /dev/null
+++ b/src/matrix1d.h
@@ -0,0 +1,1288 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef MATRIX1D_H_
+#define MATRIX1D_H_
+
+#include "src/funcs.h"
+#include "src/filename.h"
+
+extern int bestPrecision(float F, int _width);
+extern std::string floatToString(float F, int _width, int _prec);
+
+template <typename T> class Matrix2D;
+
+/** @defgroup Vectors Matrix1D Vectors
+ * @ingroup DataLibrary
+*/
+//@{
+/** @name Vectors speed up macros
+ *
+ * This macros are defined to allow high speed in critical parts of your
+ * program. They shouldn't be used systematically as usually there is no
+ * checking on the correctness of the operation you are performing. Speed comes
+ * from three facts: first, they are macros and no function call is performed
+ * (although most of the critical functions are inline functions), there is no
+ * checking on the correctness of the operation (it could be wrong and you are
+ * not warned of it), and destination vectors are not returned saving time in
+ * the copy constructor and in the creation/destruction of temporary vectors.
+ */
+//@{
+/** Array access.
+ * This macro gives you access to the array (T)
+ */
+#define MATRIX1D_ARRAY(v) ((v).vdata)
+
+/** For all elements in the array
+ * This macro is used to generate loops for the vector in an easy manner. It
+ * defines an internal index 'i' which ranges the vector using its mathematical
+ * definition (ie, logical access).
+ *
+ * @code
+ * FOR_ALL_ELEMENTS_IN_MATRIX1D(v)
+ * {
+ *     std::cout << v(i) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_ELEMENTS_IN_MATRIX1D(v) \
+    for (int i=0; i<v.vdim; i++)
+
+/** X dimension of the matrix
+ */
+#define VEC_XSIZE(m) ((m).vdim)
+
+
+/** Access to X component
+ * @code
+ * XX(v) = 1;
+ * val = XX(v);
+ * @endcode
+ */
+#define XX(v) (v).vdata[0]
+
+/** Access to Y component
+ * @code
+ * YY(v) = 1;
+ * val = YY(v);
+ * @endcode
+ */
+#define YY(v) (v).vdata[1]
+
+/** Access to Z component
+ * @code
+ * ZZ(v) = 1;
+ * val = ZZ(v);
+ * @endcode
+ */
+#define ZZ(v) (v).vdata[2]
+
+/** Creates vector in R2
+ * The vector must be created beforehand to the correct size. After this macro
+ * the vector is (x, y) in R2.
+ *
+ * @code
+ * MultidimArray< double > v(2);
+ * VECTOR_R2(v, 1, 2);
+ * @endcode
+ */
+#define VECTOR_R2(v, x, y) { \
+        XX(v) = x; YY(v) = y; }
+
+/** Creates vector in R3
+ * The vector must be created beforehand to the correct size. After this macro
+ * the vector is (x, y, z) in R3.
+ *
+ * @code
+ * MultidimArray< double > v(3);
+ * VECTOR_R2(v, 1, 2, 1);
+ * @endcode
+ */
+#define VECTOR_R3(v, x, y, z) { \
+        XX(v) = x; YY(v) = y; ZZ(v) = z;}
+
+/** Adding two R2 vectors (a=b+c)
+ * @code
+ * MultidimArray< double > a(2), b(2), c(2);
+ * ...;
+ * V2_PLUS_V2(a, b, c);
+ * @endcode
+ */
+#define V2_PLUS_V2(a, b, c) { \
+        XX(a) = XX(b) + XX(c); \
+        YY(a) = YY(b) + YY(c); }
+
+/** Substracting two R2 vectors (a=b-c)
+ * @code
+ * MultidimArray< double > a(2), b(2), c(2);
+ * ...;
+ * V2_MINUS_V2(a, b, c);
+ * @endcode
+ */
+#define V2_MINUS_V2(a, b, c) { \
+        XX(a) = XX(b) - XX(c); \
+        YY(a) = YY(b) - YY(c); }
+
+/** Adding/substracting a constant to a R2 vector (a=b-k).
+ * @code
+ * MultidimArray< double > a(2), b(2);
+ * double k;
+ * ...;
+ * V2_PLUS_CT(a, b, k);
+ *
+ * MultidimArray< double > a(2), b(2);
+ * double k;
+ * ...;
+ * V2_PLUS_CT(a, b, -k);
+ * @endcode
+ */
+#define V2_PLUS_CT(a, b, k) { \
+        XX(a) = XX(b) + (k); \
+        YY(a) = YY(b) + (k); }
+
+/** Multiplying/dividing by a constant a R2 vector (a=b*k)
+ * @code
+ * MultidimArray< double > a(2), b(2);
+ * double k;
+ * ...;
+ * V2_BY_CT(a, b, k);
+ *
+ * MultidimArray< double > a(2), b(2);
+ * double k;
+ * ...;
+ * V2_BY_CT(a, b, 1/k);
+ * @endcode
+ */
+#define V2_BY_CT(a, b, k) { \
+        XX(a) = XX(b) * (k); \
+        YY(a) = YY(b) * (k); }
+
+/** Adding two R3 vectors (a=b+c)
+ * @code
+ * MultidimArray< double > a(3), b(3), c(3);
+ * ...;
+ * V3_PLUS_V3(a, b, c);
+ * @endcode
+ */
+#define V3_PLUS_V3(a, b, c) { \
+        XX(a) = XX(b) + XX(c); \
+        YY(a) = YY(b) + YY(c); \
+        ZZ(a) = ZZ(b) + ZZ(c); }
+
+/** Substracting two R3 vectors (a=b-c)
+ * @code
+ * MultidimArray< double > a(3), b(3), c(3);
+ * ...;
+ * V3_MINUS_V3(a, b, c);
+ * @endcode
+ */
+#define V3_MINUS_V3(a, b, c) { \
+        XX(a) = XX(b) - XX(c); \
+        YY(a) = YY(b) - YY(c); \
+        ZZ(a) = ZZ(b) - ZZ(c); }
+
+/** Adding/substracting a constant to a R3 vector (a=b-k)
+ * @code
+ * MultidimArray< double > a(3), b(3);
+ * double k;
+ * ...;
+ * V3_PLUS_CT(a, b, k);
+ *
+ * MultidimArray< double > a(3), b(3);
+ * double k;
+ * ...;
+ * V3_PLUS_CT(a, b, -k);
+ * @endcode
+ */
+#define V3_PLUS_CT(a, b, c) { \
+        XX(a) = XX(b) + (c); \
+        YY(a) = YY(b) + (c); \
+        ZZ(a) = ZZ(b) + (c); }
+
+/** Multiplying/dividing by a constant a R3 vector (a=b*k)
+ * @code
+ * MultidimArray< double > a(3), b(3);
+ * double k;
+ * ...;
+ * V3_BY_CT(a, b, k);
+ *
+ * MultidimArray< double > a(3), b(3);
+ * double k;
+ * ...;
+ * V3_BY_CT(a, b, 1/k);
+ * @endcode
+ */
+#define V3_BY_CT(a, b, c) { \
+        XX(a) = XX(b) * (c); \
+        YY(a) = YY(b) * (c); \
+        ZZ(a) = ZZ(b) * (c); }
+
+/** Direct access to vector element
+ */
+#define VEC_ELEM(v,i) ((v).vdata[(i)])
+//@}
+
+/** Matrix1D class.*/
+template<typename T>
+class Matrix1D
+{
+public:
+    /// The array itself
+    T* vdata;
+
+    /// Destroy data
+    bool destroyData;
+
+    /// Number of elements
+    int vdim;
+
+    /// <0=column vector (default), 1=row vector
+    bool row;
+
+    /// @name Constructors
+    //@{
+    /** Empty constructor
+     *
+     * The empty constructor creates a vector with no memory associated,
+     * origin=0, size=0, no statistics, ... You can choose between a column
+     * vector (by default), or a row one.
+     *
+     * @code
+     * Matrix1D< double > v1;
+     * Matrix1D< double > v1(true);
+     * // both are examples of empty column vectors
+     *
+     * Matrix1D< int > v1(false);
+     * // empty row vector
+     * @endcode
+     */
+    Matrix1D(bool column = true)
+    {
+    	coreInit();
+    	row = ! column;
+    }
+
+    /** Dimension constructor
+     *
+     * The dimension constructor creates a vector with memory associated (but
+     * not assigned to anything, could be full of garbage) origin=0, size=the
+     * given one. You can choose between a column vector (by default), or a row
+     * one.
+     *
+     * @code
+     * Matrix1D< double > v1(6);
+     * Matrix1D< double > v1(6, 'y');
+     * // both are examples of column vectors of dimensions 6
+     *
+     * Matrix1D< int > v1('n');
+     * // empty row vector
+     * @endcode
+     */
+    Matrix1D(int dim, bool column = true)
+    {
+    	coreInit();
+    	row = ! column;
+        resize(dim);
+    }
+
+    /** Copy constructor
+     *
+     * The created vector is a perfect copy of the input vector but with a
+     * different memory assignment.
+     *
+     * @code
+     * Matrix1D< double > v2(v1);
+     * @endcode
+     */
+    Matrix1D(const Matrix1D<T>& v)
+    {
+        coreInit();
+        *this = v;
+    }
+
+    /** Destructor.
+     */
+     ~Matrix1D()
+     {
+        coreDeallocate();
+     }
+
+     /** Assignment.
+      *
+      * You can build as complex assignment expressions as you like. Multiple
+      * assignment is allowed.
+      *
+      * @code
+      * v1 = v2 + v3;
+      * v1 = v2 = v3;
+      * @endcode
+      */
+     Matrix1D<T>& operator=(const Matrix1D<T>& op1)
+     {
+         if (&op1 != this)
+         {
+             resize(op1);
+             for (int i = 0; i < vdim; i++)
+             	vdata[i] = op1.vdata[i];
+             row=op1.row;
+         }
+
+         return *this;
+     }
+     //@}
+
+     /// @name Core memory operations for Matrix1D
+     //@{
+    /** Clear.
+     */
+     void clear()
+     {
+        coreDeallocate();
+        coreInit();
+     }
+
+    /** Core init.
+     * Initialize everything to 0
+     */
+    void coreInit()
+    {
+        vdim=0;
+        row=false;
+        vdata=NULL;
+        destroyData=true;
+    }
+
+    /** Core allocate.
+     */
+    inline void coreAllocate(int _vdim)
+    {
+        if (_vdim<=0)
+        {
+            clear();
+            return;
+        }
+
+        vdim=_vdim;
+        vdata = new T [vdim];
+        if (vdata == NULL)
+            REPORT_ERROR("Allocate: No space left");
+    }
+
+    /** Core deallocate.
+     * Free all vdata.
+     */
+    inline void coreDeallocate()
+    {
+        if (vdata != NULL && destroyData)
+            delete[] vdata;
+        vdata=NULL;
+    }
+    //@}
+
+    ///@name Size and shape of Matrix1D
+    //@{
+    /** Resize to a given size
+     *
+     * This function resize the actual array to the given size. The origin is
+     * not modified. If the actual array is larger than the pattern then the
+     * values outside the new size are lost, if it is smaller then 0's are
+     * added. An exception is thrown if there is no memory.
+     *
+     * @code
+     * V1.resize(3, 3, 2);
+     * @endcode
+     */
+    inline void resize(int Xdim)
+    {
+        if (Xdim == vdim)
+            return;
+
+        if (Xdim <= 0)
+        {
+            clear();
+            return;
+        }
+
+        T * new_vdata;
+        try
+        {
+        	new_vdata = new T [Xdim];
+        }
+        catch (std::bad_alloc &)
+        {
+			REPORT_ERROR("Allocate: No space left");
+        }
+
+		// Copy needed elements, fill with 0 if necessary
+		for (int j = 0; j < Xdim; j++)
+		{
+			T val;
+			if (j >= vdim)
+				val = 0;
+			else
+				val = vdata[j];
+			new_vdata[j] = val;
+		}
+
+		// deallocate old vector
+		coreDeallocate();
+
+		// assign *this vector to the newly created
+		vdata = new_vdata;
+		vdim = Xdim;
+
+    }
+
+    /** Resize according to a pattern.
+     *
+     * This function resize the actual array to the same size
+     * as the input pattern. If the actual array is larger than the pattern
+     * then the trailing values are lost, if it is smaller then 0's are
+     * added at the end
+     *
+     * @code
+     * v2.resize(v1);
+     * // v2 has got now the same structure as v1
+     * @endcode
+     */
+    template<typename T1>
+    void resize(const Matrix1D<T1> &v)
+    {
+        if (vdim != v.vdim)
+            resize(v.vdim);
+    }
+
+    /** Same shape.
+     *
+     * Returns true if this object has got the same shape (origin and size)
+     * than the argument
+     */
+    template <typename T1>
+    bool sameShape(const Matrix1D<T1>& op) const
+    {
+        return (vdim == op.vdim);
+    }
+
+    /** Returns the size of this vector
+     *
+     * @code
+     * int nn = a.size();
+     * @endcode
+     */
+    inline int size() const
+    {
+        return vdim;
+    }
+
+    /** True if vector is a row.
+     *
+     * @code
+     * if (v.isRow())
+     *     std::cout << "v is a row vector\n";
+     * @endcode
+     */
+    int isRow() const
+    {
+        return row;
+    }
+
+    /** True if vector is a column
+     *
+     * @code
+     * if (v.isCol())
+     *     std::cout << "v is a column vector\n";
+     * @endcode
+     */
+    int  isCol()  const
+    {
+        return !row;
+    }
+
+    /** Forces the vector to be a row vector
+     *
+     * @code
+     * v.setRow();
+     * @endcode
+     */
+    void setRow()
+    {
+        row = true;
+    }
+
+    /** Forces the vector to be a column vector
+     *
+     * @code
+     * v.setCol();
+     * @endcode
+     */
+    void setCol()
+    {
+        row = false;
+    }
+    //@}
+
+    /// @name Initialization of Matrix1D values
+    //@{
+    /** Same value in all components.
+     *
+     * The constant must be of a type compatible with the array type, ie,
+     * you cannot  assign a double to an integer array without a casting.
+     * It is not an error if the array is empty, then nothing is done.
+     *
+     * @code
+     * v.initConstant(3.14);
+     * @endcode
+     */
+    void initConstant(T val)
+    {
+    	for (int j = 0; j < vdim; j++)
+    	{
+    		vdata[j] = val;
+    	}
+    }
+
+    /** Initialize to zeros with current size.
+     *
+     * All values are set to 0. The current size and origin are kept. It is not
+     * an error if the array is empty, then nothing is done.
+     *
+     * @code
+     * v.initZeros();
+     * @endcode
+     */
+    void initZeros()
+    {
+        memset(vdata,0,vdim*sizeof(T));
+    }
+
+    /** Initialize to zeros with a given size.
+     */
+    void initZeros(int Xdim)
+    {
+    	if (vdim!=Xdim)
+    		resize(Xdim);
+        memset(vdata,0,vdim*sizeof(T));
+    }
+
+    /** Initialize to zeros following a pattern.
+      *
+      * All values are set to 0, and the origin and size of the pattern are
+      * adopted.
+      *
+      * @code
+      * v2.initZeros(v1);
+      * @endcode
+      */
+    template <typename T1>
+    void initZeros(const Matrix1D<T1>& op)
+    {
+    	if (vdim!=op.vdim)
+    		resize(op);
+        memset(vdata,0,vdim*sizeof(T));
+	}
+    //@}
+
+	/// @name Matrix1D operators
+    //@{
+    /** v3 = v1 * k.
+     */
+    Matrix1D<T> operator*(T op1) const
+    {
+        Matrix1D<T> tmp(*this);
+        for (int i=0; i < vdim; i++)
+        	tmp.vdata[i] = vdata[i] * op1;
+        return tmp;
+    }
+
+    /** v3 = v1 / k.
+     */
+    Matrix1D<T> operator/(T op1) const
+    {
+        Matrix1D<T> tmp(*this);
+        for (int i=0; i < vdim; i++)
+        	tmp.vdata[i] = vdata[i] / op1;
+        return tmp;
+    }
+
+    /** v3 = v1 + k.
+     */
+    Matrix1D<T> operator+(T op1) const
+    {
+        Matrix1D<T> tmp(*this);
+        for (int i=0; i < vdim; i++)
+        	tmp.vdata[i] = vdata[i] + op1;
+        return tmp;
+    }
+
+    /** v3 = v1 - k.
+     */
+    Matrix1D<T> operator-(T op1) const
+    {
+        Matrix1D<T> tmp(*this);
+        for (int i=0; i < vdim; i++)
+        	tmp.vdata[i] = vdata[i] - op1;
+        return tmp;
+    }
+
+    /** v3 = k * v2.
+     */
+    friend Matrix1D<T> operator*(T op1, const Matrix1D<T>& op2)
+    {
+        Matrix1D<T> tmp(op2);
+        for (int i=0; i < op2.vdim; i++)
+        	tmp.vdata[i] = op1 * op2.vdata[i];
+        return tmp;
+    }
+
+    /** v3 = k / v2.
+     */
+    friend Matrix1D<T> operator/(T op1, const Matrix1D<T>& op2)
+    {
+        Matrix1D<T> tmp(op2);
+        for (int i=0; i < op2.vdim; i++)
+        	tmp.vdata[i] = op1 / op2.vdata[i];
+        return tmp;
+    }
+
+    /** v3 = k + v2.
+     */
+    friend Matrix1D<T> operator+(T op1, const Matrix1D<T>& op2)
+    {
+        Matrix1D<T> tmp(op2);
+        for (int i=0; i < op2.vdim; i++)
+        	tmp.vdata[i] = op1 + op2.vdata[i];
+        return tmp;
+    }
+
+    /** Vector summation
+     *
+     * @code
+     * A += B;
+     * @endcode
+     */
+    void operator+=(const Matrix1D<T>& op1) const
+    {
+        if (vdim != op1.vdim)
+            REPORT_ERROR("Not same sizes in vector summation");
+
+        for (int i = 0; i < vdim; i++)
+        	vdata[i] += op1.vdata[i];
+    }
+
+    /** v3 = k - v2.
+     */
+    friend Matrix1D<T> operator-(T op1, const Matrix1D<T>& op2)
+    {
+        Matrix1D<T> tmp(op2);
+        for (int i=0; i < op2.vdim; i++)
+        	tmp.vdata[i] = op1 - op2.vdata[i];
+        return tmp;
+    }
+
+    /** Vector substraction
+     *
+     * @code
+     * A -= B;
+     * @endcode
+     */
+    void operator-=(const Matrix1D<T>& op1) const
+    {
+        if (vdim != op1.vdim)
+            REPORT_ERROR("Not same sizes in vector summation");
+
+        for (int i = 0; i < vdim; i++)
+        	vdata[i] -= op1.vdata[i];
+    }
+
+    /** v3 *= k.
+     */
+    void operator*=(T op1)
+    {
+        for (int i=0; i < vdim; i++)
+        	vdata[i] *= op1;
+    }
+
+    /** v3 /= k.
+      */
+     void operator/=(T op1)
+     {
+         for (int i=0; i < vdim; i++)
+         	vdata[i] /= op1;
+     }
+
+     /** v3 += k.
+     */
+    void operator+=(T op1)
+    {
+        for (int i=0; i < vdim; i++)
+        	vdata[i] += op1;
+    }
+
+    /** v3 -= k.
+      */
+     void operator-=(T op1)
+     {
+         for (int i=0; i < vdim; i++)
+         	vdata[i] -= op1;
+     }
+
+     /** v3 = v1 * v2.
+     */
+     Matrix1D<T> operator*(const Matrix1D<T>& op1) const
+    {
+         Matrix1D<T> tmp(op1);
+         for (int i=0; i < vdim; i++)
+         	tmp.vdata[i] = vdata[i] * op1.vdata[i];
+         return tmp;
+    }
+
+     /** v3 = v1 / v2.
+     */
+     Matrix1D<T> operator/(const Matrix1D<T>& op1) const
+    {
+         Matrix1D<T> tmp(op1);
+         for (int i=0; i < vdim; i++)
+         	tmp.vdata[i] = vdata[i] / op1.vdata[i];
+         return tmp;
+    }
+     /** v3 = v1 + v2.
+     */
+     Matrix1D<T> operator+(const Matrix1D<T>& op1) const
+    {
+         Matrix1D<T> tmp(op1);
+         for (int i=0; i < vdim; i++)
+         	tmp.vdata[i] = vdata[i] + op1.vdata[i];
+         return tmp;
+    }
+
+     /** v3 = v1 - v2.
+     */
+     Matrix1D<T> operator-(const Matrix1D<T>& op1) const
+    {
+         Matrix1D<T> tmp(op1);
+         for (int i=0; i < vdim; i++)
+         	tmp.vdata[i] = vdata[i] - op1.vdata[i];
+         return tmp;
+    }
+
+     /** v3 *= v2.
+     */
+    void operator*=(const Matrix1D<T>& op1)
+    {
+        for (int i=0; i < vdim; i++)
+        	vdata[i] *= op1.vdata[i];
+    }
+
+    /** v3 /= v2.
+     */
+    void operator/=(const Matrix1D<T>& op1)
+    {
+        for (int i=0; i < vdim; i++)
+         	vdata[i] /= op1.vdata[i];
+    }
+
+     /** v3 += v2.
+     */
+    void operator+=(const Matrix1D<T>& op1)
+    {
+        for (int i=0; i < vdim; i++)
+        	vdata[i] += op1.vdata[i];
+    }
+
+    /** v3 -= v2.
+     */
+    void operator-=(const Matrix1D<T>& op1)
+    {
+        for (int i=0; i < vdim; i++)
+         	vdata[i] -= op1.vdata[i];
+    }
+
+    /** Unary minus.
+     *
+     * It is used to build arithmetic expressions. You can make a minus
+     * of anything as long as it is correct semantically.
+     *
+     * @code
+     * v1 = -v2;
+     * v1 = -v2.transpose();
+     * @endcode
+     */
+    Matrix1D<T> operator-() const
+    {
+        Matrix1D<T> tmp(*this);
+        for (int i=0; i < vdim; i++)
+         	tmp.vdata[i] = - vdata[i];
+        return tmp;
+    }
+
+    /** Vector by matrix
+     *
+     * Algebraic vector by matrix multiplication. This function is actually
+     * implemented in xmippMatrices2D
+     */
+    Matrix1D<T> operator*(const Matrix2D<T>& M);
+
+    /** Vector element access
+     *
+     * Returns the value of a vector logical position. In our example we could
+     * access from v(-2) to v(2). The elements can be used either by value or by
+     * reference.
+     *
+     * @code
+     * v(-2) = 1;
+     * val = v(-2);
+     * @endcode
+     */
+    T& operator()(int i) const
+    {
+        return vdata[i];
+    }
+    //@}
+
+	/// @name Utilities for Matrix1D
+    //@{
+
+    /** Produce a vector suitable for working with Numerical Recipes
+     *
+     * This function must be used only as a preparation for routines which need
+     * that the first physical index is 1 and not 0 as it usually is in C. In
+     * fact the vector provided for Numerical recipes is exactly this same one
+     * but with the indexes changed.
+     *
+     * This function is not ported to Python.
+     */
+    T* adaptForNumericalRecipes() const
+    {
+        return MATRIX1D_ARRAY(*this) - 1;
+    }
+
+    /** Kill an array produced for Numerical Recipes.
+     *
+     * Nothing needs to be done in fact.
+     *
+     * This function is not ported to Python.
+     */
+    void killAdaptationForNumericalRecipes(T* m) const
+        {}
+
+    /** CEILING
+     *
+     * Applies a CEILING (look for the nearest larger integer) to each
+     * array element.
+     */
+    void selfCEIL()
+    {
+        for (int i=0; i < vdim; i++)
+        	vdata[i] = CEIL(vdata[i]);
+    }
+
+    /** FLOOR
+     *
+     * Applies a FLOOR (look for the nearest larger integer) to each
+     * array element.
+     */
+    void selfFLOOR()
+    {
+        for (int i=0; i < vdim; i++)
+        	vdata[i] = FLOOR(vdata[i]);
+    }
+
+    /** ROUND
+     *
+     * Applies a ROUND (look for the nearest larger integer) to each
+     * array element.
+     */
+    void selfROUND()
+    {
+        for (int i=0; i < vdim; i++)
+        	vdata[i] = ROUND(vdata[i]);
+    }
+
+    /** Index for the maximum element.
+     *
+     * This function returns the index of the maximum element of an matrix1d.
+     * Returns -1 if the array is empty
+     */
+    void maxIndex(int& jmax) const
+    {
+        if (vdim == 0)
+        {
+            jmax = -1;
+            return;
+        }
+
+        jmax = 0;
+        T maxval = (*this)(0);
+        for (int j = 0; j < vdim; j++)
+       	 if ( (*this)(j) > maxval )
+       		 jmax =j;
+    }
+
+    /** Index for the minimum element.
+     *
+     * This function returns the index of the minimum element of an matrix1d.
+     * Returns -1 if the array is empty
+     */
+    void minIndex(int& jmin) const
+    {
+        if (vdim == 0)
+        {
+            jmin = -1;
+            return;
+        }
+
+        jmin = 0;
+        T minval = (*this)(0);
+        for (int j = 0; j < vdim; j++)
+       	 if ( (*this)(j) < minval )
+       		 jmin =j;
+    }
+
+    /** Algebraic transpose of vector
+     *
+     * You can use the transpose in as complex expressions as you like. The
+     * origin of the vector is not changed.
+     *
+     * @code
+     * v2 = v1.transpose();
+     * @endcode
+     */
+    Matrix1D<T> transpose() const
+    {
+        Matrix1D<T> temp(*this);
+        temp.selfTranspose();
+        return temp;
+    }
+
+    /** Algebraic transpose of vector
+     *
+     * The same as before but the result is stored in this same object.
+     */
+    void selfTranspose()
+    {
+        row = !row;
+    }
+
+    /** Sum of vector values.
+     *
+     * This function returns the sum of all internal values.
+     *
+     * @code
+     * double sum = m.sum();
+     * @endcode
+     */
+    double sum(bool average=false) const
+    {
+        double sum = 0;
+		for (int j = 0; j < vdim; j++)
+		{
+			sum += vdata[j];
+		}
+		if (average)
+			return sum/(double)vdim;
+		else
+			return sum;
+    }
+
+   /** Sum of squared vector values.
+     *
+     * This function returns the sum of all internal values to the second
+     * power_class.
+     *
+     * @code
+     * double sum2 = m.sum2();
+     * @endcode
+     */
+    double sum2() const
+    {
+        double sum = 0;
+		for (int j = 0; j < vdim; j++)
+		{
+			sum += vdata[j] * vdata[j];
+		}
+		return sum;
+    }
+
+    /** Module of the vector
+     *
+     * This module is defined as the square root of the sum of the squared
+     * components. Euclidean norm of the vector.
+     *
+     * @code
+     * double mod = v.module();
+     * @endcode
+     */
+    double module() const
+    {
+        return sqrt(sum2());
+    }
+
+    /** Angle of the vector
+     *
+     * Supposing this vector is in R2 this function returns the angle of this
+     * vector with X axis, ie, atan2(YY(v), XX(v))
+     */
+    double angle()
+    {
+        return atan2((double) YY(*this), (double) XX(*this));
+    }
+
+    /** Normalize this vector, store the result here
+     */
+    void selfNormalize()
+    {
+        double m = module();
+        if (ABS(m) > XMIPP_EQUAL_ACCURACY)
+        {
+            T im=(T) (1.0/m);
+            *this *= im;
+        }
+        else
+            initZeros();
+    }
+
+    /** Reverse vector values, keep in this object.
+     */
+    void selfReverse()
+    {
+    	for (int j = 0; j <= (int)(vdim - 1) / 2; j++)
+    	{
+    		T aux;
+    		SWAP(vdata[j], vdata[vdim-1-j], aux);
+    	}
+    }
+
+    /** Compute numerical derivative
+     *
+     * The numerical derivative is of the same size as the input vector.
+     * However, the first two and the last two samples are set to 0,
+     * because the numerical method is not able to correctly estimate the
+     * derivative there.
+     */
+    void numericalDerivative(Matrix1D<double> &result)
+    {
+         const double i12=1.0/12.0;
+         result.initZeros(*this);
+         for (int i=STARTINGX(*this)+2; i<=FINISHINGX(*this)-2; i++)
+        	 result(i)=i12*(-(*this)(i+2)+8*(*this)(i+1)
+        			 -8*(*this)(i-1)+(*this)(i+2));
+    }
+
+    /** Output to output stream.*/
+    friend std::ostream& operator<<(std::ostream& ostrm, const Matrix1D<T>& v)
+    {
+        if (v.vdim == 0)
+            ostrm << "NULL Array\n";
+        else
+            ostrm << std::endl;
+
+        double max_val = ABS(v.vdata[0]);
+
+        for (int j = 0; j < v.vdim; j++)
+        {
+       	 max_val = XMIPP_MAX(max_val, v.vdata[j]);
+        }
+
+        int prec = bestPrecision(max_val, 10);
+
+        for (int j = 0; j < v.vdim; j++)
+        {
+       	 ostrm << floatToString((double) v.vdata[j], 10, prec)
+       	 << std::endl;
+        }
+        return ostrm;
+    }
+
+   //@}
+};
+
+ /**@name Vector Related functions
+  * These functions are not methods of Matrix1D
+  */
+
+ /** Creates vector in R2.
+  * After this function the vector is (x,y) in R2.
+  *
+  * @code
+  * Matrix1D< double > v = vectorR2(1, 2);
+  * @endcode
+  */
+ Matrix1D< double > vectorR2(double x, double y);
+
+ /** Creates vector in R3.
+  * After this function the vector is (x,y,z) in R3.
+  *
+  * @code
+  * Matrix1D< double > v = vectorR2(1, 2, 1);
+  * @endcode
+  */
+ Matrix1D< double > vectorR3(double x, double y, double z);
+
+ /** Creates an integer vector in Z3.
+  */
+ Matrix1D< int > vectorR3(int x, int y, int z);
+
+ /** Dot product.
+  * Given any two vectors in Rn (n-dimensional vector), this function returns the
+  * dot product of both. If the vectors are not of the same size or shape then an
+  * exception is thrown. The dot product is defined as the sum of the component
+  * by component multiplication.
+  *
+  * For the R3 vectors (V1x,V1y,V1z), (V2x, V2y, V2z) the result is V1x*V2x +
+  * V1y*V2y + V1z*V2z.
+  *
+  * @code
+  * Matrix1D< double > v1(1000);
+  * v1.init_random(0, 10, "gaussian");
+  * std::cout << "The power_class of this vector should be 100 and is " <<
+  *     dotProduct(v1, v1) << std::endl;
+  * @endcode
+  */
+ template<typename T>
+ T dotProduct(const Matrix1D< T >& v1, const Matrix1D< T >& v2)
+ {
+     if (!v1.sameShape(v2))
+         REPORT_ERROR("Dot product: vectors of different size or shape");
+
+     T accumulate = 0;
+     for (int j = 0; j < v1.vdim; j++)
+     {
+    	 accumulate += v1.vdata[j] * v2.vdata[j];
+     }
+     return accumulate;
+ }
+
+ /** Vector product in R3.
+  * This function takes two R3 vectors and compute their vectorial product. For
+  * two vectors (V1x,V1y,V1z), (V2x, V2y, V2z) the result is (V1y*V2z-V1z*v2y,
+  * V1z*V2x-V1x*V2z, V1x*V2y-V1y*V2x). Pay attention that this operator is not
+  * conmutative. An exception is thrown if the vectors are not of the same shape
+  * or they don't belong to R3.
+  *
+  * @code
+  * Matrix1D< T > X = vectorR3(1, 0, 0), Y = vector_R3(0, 1, 0);
+  * std::cout << "X*Y=Z=" << vectorProduct(X,Y).transpose() << std::endl;
+  * @endcode
+  */
+ template<typename T>
+ Matrix1D< T > vectorProduct(const Matrix1D< T >& v1, const Matrix1D< T >& v2)
+ {
+     if (v1.vdim != 3 || v2.vdim != 3)
+         REPORT_ERROR("Vector_product: vectors are not in R3");
+
+     if (v1.isRow() != v2.isRow())
+         REPORT_ERROR("Vector_product: vectors are of different shape");
+
+     Matrix1D< T > result(3);
+     XX(result) = YY(v1) * ZZ(v2) - ZZ(v1) * YY(v2);
+     YY(result) = ZZ(v1) * XX(v2) - XX(v1) * ZZ(v2);
+     ZZ(result) = XX(v1) * YY(v2) - YY(v1) * XX(v2);
+
+     return result;
+ }
+
+ /** Vector product in R3.
+  * This function computes the vector product of two R3 vectors.
+  * No check is performed, it is assumed that the output vector
+  * is already resized
+  *
+  */
+ template<typename T>
+ void vectorProduct(const Matrix1D< T >& v1, const Matrix1D< T >& v2,
+    Matrix1D<T> &result)
+ {
+     XX(result) = YY(v1) * ZZ(v2) - ZZ(v1) * YY(v2);
+     YY(result) = ZZ(v1) * XX(v2) - XX(v1) * ZZ(v2);
+     ZZ(result) = XX(v1) * YY(v2) - YY(v1) * XX(v2);
+ }
+
+/** Sort two vectors.
+  * v1 and v2 must be of the same shape, if not an exception is thrown. After
+  * calling this function all components in v1 are the minimum between the
+  * corresponding components in v1 and v2, and all components in v2 are the
+  * maximum.
+  *
+  * For instance, XX(v1)=MIN(XX(v1), XX(v2)), XX(v2)=MAX(XX(v1), XX(v2)). Notice
+  * that both vectors are modified. This function is very useful for sorting two
+  * corners. After calling it you can certainly perform a non-empty for (from
+  * corner1 to corner2) loop.
+  */
+ template<typename T>
+ void sortTwoVectors(Matrix1D<T>& v1, Matrix1D<T>& v2)
+ {
+     T temp;
+     if (!v1.sameShape(v2))
+         REPORT_ERROR("sortTwoVectors: vectors are not of the same shape");
+
+     for (int j = 0; j < v1.vdim; j++)
+     {
+    	 temp       = XMIPP_MIN(v1.vdata[j], v2.vdata[j]);
+    	 v2.vdata[j] = XMIPP_MAX(v1.vdata[j], v2.vdata[j]);
+    	 v1.vdata[j] = temp;
+     }
+ }
+
+/** Conversion from one type to another.
+  * If we have an integer array and we need a double one, we can use this
+  * function. The conversion is done through a type casting of each element
+  * If n >= 0, only the nth volumes will be converted, otherwise all NSIZE volumes
+  */
+ template<typename T1, typename T2>
+ void typeCast(const Matrix1D<T1>& v1,  Matrix1D<T2>& v2)
+ {
+     if (v1.vdim == 0)
+     {
+         v2.clear();
+         return;
+     }
+
+     v2.resize(v1.vdim);
+     for (int j = 0; j < v1.vdim; j++)
+     {
+    	 v2.vdata[j] = static_cast< T2 > (v1.vdata[j]);
+     }
+
+ }
+//@}
+#endif /* MATRIX1D_H_ */
diff --git a/src/matrix2d.cpp b/src/matrix2d.cpp
new file mode 100644
index 0000000..c189743
--- /dev/null
+++ b/src/matrix2d.cpp
@@ -0,0 +1,36 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+/* Is diagonal ------------------------------------------------------------- */
+#include "src/matrix2d.h"
+
+/* Interface to numerical recipes: svbksb ---------------------------------- */
+void svbksb(Matrix2D<double> &u, Matrix1D<double> &w, Matrix2D<double> &v,
+            Matrix1D<double> &b, Matrix1D<double> &x)
+{
+    // Call to the numerical recipes routine. Results will be stored in X
+    svbksb(u.adaptForNumericalRecipes2(),
+           w.adaptForNumericalRecipes(),
+           v.adaptForNumericalRecipes2(),
+           u.mdimy, u.mdimx,
+           b.adaptForNumericalRecipes(),
+           x.adaptForNumericalRecipes());
+}
+
diff --git a/src/matrix2d.h b/src/matrix2d.h
new file mode 100644
index 0000000..448712d
--- /dev/null
+++ b/src/matrix2d.h
@@ -0,0 +1,1492 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef MATRIX2D_H_
+#define MATRIX2D_H_
+
+#include <string.h>
+#include <iomanip>
+#include "src/matrix1d.h"
+
+/** @defgroup Matrices Matrix2D Matrices
+ * @ingroup DataLibrary
+ */
+//@{
+/** @name Matrices speed up macros */
+//@{
+
+/** Array access.
+ *
+ * This macro gives you access to the array (T)
+ */
+#define MATRIX2D_ARRAY(m) ((m).mdata)
+
+/** For all elements in the array
+ *
+ * This macro is used to generate loops for the matrix in an easy way. It
+ * defines internal indexes 'i' and 'j' which ranges the matrix using its
+ * mathematical definition (ie, logical access).
+ *
+ * @code
+ * FOR_ALL_ELEMENTS_IN_MATRIX2D(m)
+ * {
+ *     std::cout << m(i, j) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_ELEMENTS_IN_MATRIX2D(m) \
+    for (int i=0; i<(m).mdimy; i++) \
+        for (int j=0; j<(m).mdimx; j++)
+
+/** Access to a matrix element
+ * v is the array, i and j define the element v_ij.
+ *
+  * @code
+ * MAT_ELEM(m, 0, 0) = 1;
+ * val = MAT_ELEM(m, 0, 0);
+ * @endcode
+ */
+#define MAT_ELEM(m,i,j) ((m).mdata[(i)*(m).mdimx+(j)])
+
+/** X dimension of the matrix
+ */
+#define MAT_XSIZE(m) ((m).mdimx)
+
+/** Y dimension of the matrix
+ */
+#define MAT_YSIZE(m) ((m).mdimy)
+
+/** Matrix (2x2) by vector (2x1) (a=M*b)
+ *
+ * You must "load" the temporary variables, and create the result vector with
+ * the appropiate size. You can reuse the vector b to store the results (that
+ * is, M2x2_BY_V2x1(b, M, b);, is allowed).
+ *
+ * @code
+ * double example
+ * {
+ *     SPEED_UP_temps;
+ *
+ *     Matrix1D< double > a(2), b(2);
+ *     Matrix2D< double > M(2, 2);
+ *
+ *     M.init_random(0, 1);
+ *     b.init_random(0, 1);
+ *
+ *     M2x2_BY_V2x1(a, M, b);
+ *
+ *     return a.sum();
+ * }
+ * @endcode
+ * 	TODO: remove this from the code.... DONT USE IT ANY FURTHER....
+ */
+#define M2x2_BY_V2x1(a, M, b) { \
+        spduptmp0 = MAT_ELEM(M, 0, 0) * XX(b) + MAT_ELEM(M, 0, 1) * YY(b); \
+        spduptmp1 = MAT_ELEM(M, 1, 0) * XX(b) + MAT_ELEM(M, 1, 1) * YY(b); \
+        XX(a) = spduptmp0; \
+        YY(a) = spduptmp1; }
+
+/** Matrix (3x3) by vector (3x1) (a=M*b)
+ *
+ * You must "load" the temporary variables, and create the result vector with
+ * the appropiate size. You can reuse the vector b to store the results (that
+ * is, M3x3_BY_V3x1(b, M, b);, is allowed).
+ *
+ * @code
+ * double example
+ * {
+ *     SPEED_UP_temps;
+ *
+ *     Matrix1D< double > a(3), b(3);
+ *     Matrix2D< double > M(3, 3);
+ *
+ *     M.init_random(0, 1);
+ *     b.init_random(0, 1);
+ *     M3x3_BY_V3x1(a, M, b);
+ *
+ *     return a.sum();
+ * }
+ * @endcode
+ * 	TODO: remove this from the code.... DONT USE IT ANY FURTHER....
+ */
+#define M3x3_BY_V3x1(a, M, b) { \
+        spduptmp0 = MAT_ELEM(M, 0, 0) * XX(b) + MAT_ELEM(M, 0, 1) * YY(b) + MAT_ELEM(M, 0, 2) \
+                    * ZZ(b); \
+        spduptmp1 = MAT_ELEM(M, 1, 0) * XX(b) + MAT_ELEM(M, 1, 1) * YY(b) + MAT_ELEM(M, 1, 2) \
+                    * ZZ(b); \
+        spduptmp2 = MAT_ELEM(M, 2, 0) * XX(b) + MAT_ELEM(M, 2, 1) * YY(b) + MAT_ELEM(M, 2, 2) \
+                    * ZZ(b); \
+        XX(a) = spduptmp0; YY(a) = spduptmp1; ZZ(a) = spduptmp2; }
+
+
+// Forward declarations
+template<typename T>
+class Matrix1D;
+template<typename T>
+class Matrix2D;
+
+template<typename T>
+void ludcmp(const Matrix2D<T>& A, Matrix2D<T>& LU, Matrix1D< int >& indx, T& d);
+
+template<typename T>
+void lubksb(const Matrix2D<T>& LU, Matrix1D< int >& indx, Matrix1D<T>& b);
+
+template<typename T>
+void svdcmp(const Matrix2D< T >& a,
+            Matrix2D< double >& u,
+            Matrix1D< double >& w,
+            Matrix2D< double >& v);
+
+void svbksb(Matrix2D< double >& u,
+            Matrix1D< double >& w,
+            Matrix2D< double >& v,
+            Matrix1D< double >& b,
+            Matrix1D< double >& x);
+
+template<typename T>
+void solve(const Matrix2D<T>& A,
+		   const Matrix1D<T>& b,
+           Matrix1D< double >& result,
+           double tolerance);
+
+/** Matrix2D class */
+template<typename T>
+class Matrix2D
+{
+public:
+    // The array itself
+    T* mdata;
+
+    // Destroy data
+    bool destroyData;
+
+    // Number of elements in X
+    int mdimx;
+
+    // Number of elements in Y
+    int mdimy;
+
+    // Total number of elements
+    int mdim;
+
+    /// @name Constructors
+    /// @{
+    /** Empty constructor
+     */
+    Matrix2D()
+    {
+        coreInit();
+    }
+
+    /** Dimension constructor
+     */
+    Matrix2D(int Ydim, int Xdim)
+    {
+        coreInit();
+        resize(Ydim, Xdim);
+    }
+
+    /** Copy constructor
+     */
+    Matrix2D(const Matrix2D<T>& v)
+    {
+        coreInit();
+        *this = v;
+    }
+
+    /** Destructor.
+     */
+    ~Matrix2D()
+    {
+        coreDeallocate();
+    }
+
+    /** Assignment.
+     *
+     * You can build as complex assignment expressions as you like. Multiple
+     * assignment is allowed.
+     *
+     * @code
+     * v1 = v2 + v3;
+     * v1 = v2 = v3;
+     * @endcode
+     */
+    Matrix2D<T>& operator=(const Matrix2D<T>& op1)
+    {
+        if (&op1 != this)
+        {
+            if (MAT_XSIZE(*this)!=MAT_XSIZE(op1) ||
+                MAT_YSIZE(*this)!=MAT_YSIZE(op1))
+                resize(op1);
+            memcpy(mdata,op1.mdata,op1.mdim*sizeof(T));
+        }
+
+        return *this;
+    }
+    //@}
+
+    /// @name Core memory operations for Matrix2D
+    //@{
+    /** Clear.
+     */
+    void clear()
+    {
+        coreDeallocate();
+        coreInit();
+    }
+
+    /** Core init.
+     * Initialize everything to 0
+     */
+    void coreInit()
+    {
+        mdimx=mdimy=mdim=0;
+        mdata=NULL;
+        destroyData=true;
+    }
+
+    /** Core allocate.
+     */
+    void coreAllocate(int _mdimy, int _mdimx)
+    {
+        if (_mdimy <= 0 ||_mdimx<=0)
+        {
+            clear();
+            return;
+        }
+
+        mdimx=_mdimx;
+        mdimy=_mdimy;
+        mdim=_mdimx*_mdimy;
+        mdata = new T [mdim];
+        if (mdata == NULL)
+            REPORT_ERROR("coreAllocate: No space left");
+    }
+
+    /** Core deallocate.
+     * Free all mdata.
+     */
+    void coreDeallocate()
+    {
+        if (mdata != NULL && destroyData)
+            delete[] mdata;
+        mdata=NULL;
+    }
+    //@}
+
+    /// @name Size and shape of Matrix2D
+    //@{
+    /** Resize to a given size
+     */
+    void resize(int Ydim, int Xdim)
+    {
+
+        if (Xdim == mdimx && Ydim == mdimy)
+            return;
+
+        if (Xdim <= 0 || Ydim <= 0)
+        {
+            clear();
+            return;
+        }
+
+        T * new_mdata;
+        size_t YXdim=Ydim*Xdim;
+
+        try
+        {
+            new_mdata = new T [YXdim];
+        }
+        catch (std::bad_alloc &)
+        {
+            REPORT_ERROR("Allocate: No space left");
+        }
+
+        // Copy needed elements, fill with 0 if necessary
+        for (int i = 0; i < Ydim; i++)
+            for (int j = 0; j < Xdim; j++)
+            {
+                T val;
+                if (i >= mdimy)
+                    val = 0;
+                else if (j >= mdimx)
+                    val = 0;
+                else
+                    val = mdata[i*mdimx + j];
+                new_mdata[i*Xdim+j] = val;
+            }
+
+        // deallocate old vector
+        coreDeallocate();
+
+        // assign *this vector to the newly created
+        mdata = new_mdata;
+        mdimx = Xdim;
+        mdimy = Ydim;
+        mdim = Xdim * Ydim;
+    }
+
+    /** Resize according to a pattern.
+     *
+     * This function resize the actual array to the same size and origin
+     * as the input pattern. If the actual array is larger than the pattern
+     * then the trailing values are lost, if it is smaller then 0's are
+     * added at the end
+     *
+     * @code
+     * v2.resize(v1);
+     * // v2 has got now the same structure as v1
+     * @endcode
+     */
+    template<typename T1>
+    void resize(const Matrix2D<T1> &v)
+    {
+        if (mdimx != v.mdimx || mdimy != v.mdimy)
+            resize(v.mdimy, v.mdimx);
+    }
+
+    /** Extract submatrix and assign to this object.
+     */
+    void submatrix(int i0, int j0, int iF, int jF)
+    {
+        if (i0 < 0 || j0 < 0 || iF >= MAT_YSIZE(*this) || jF >= MAT_XSIZE(*this))
+            REPORT_ERROR("Submatrix indexes out of bounds");
+        Matrix2D<T> result(iF - i0 + 1, jF - j0 + 1);
+
+        FOR_ALL_ELEMENTS_IN_MATRIX2D(result)
+        MAT_ELEM(result, i, j) = MAT_ELEM(*this, i+i0, j+j0);
+
+        *this = result;
+    }
+
+    /** Same shape.
+     *
+     * Returns true if this object has got the same shape (origin and size)
+     * than the argument
+     */
+    template <typename T1>
+    bool sameShape(const Matrix2D<T1>& op) const
+    {
+        return ((mdimx == op.mdimx) && (mdimy == op.mdimy));
+    }
+
+    /** X dimension
+     *
+     * Returns X dimension
+     */
+    inline int Xdim() const
+    {
+        return mdimx;
+    }
+
+    /** Y dimension
+     *
+     * Returns Y dimension
+     */
+    inline int Ydim() const
+    {
+        return mdimy;
+    }
+    //@}
+
+    /// @name Initialization of Matrix2D values
+    //@{
+    /** Same value in all components.
+     *
+     * The constant must be of a type compatible with the array type, ie,
+     * you cannot  assign a double to an integer array without a casting.
+     * It is not an error if the array is empty, then nothing is done.
+     *
+     * @code
+     * v.initConstant(3.14);
+     * @endcode
+     */
+    void initConstant(T val)
+    {
+        for (int j = 0; j < mdim; j++)
+            mdata[j] = val;
+    }
+
+    /** Initialize to zeros with current size.
+     *
+     * All values are set to 0. The current size and origin are kept. It is not
+     * an error if the array is empty, then nothing is done.
+     *
+     * @code
+     * v.initZeros();
+     * @endcode
+     */
+    void initZeros()
+    {
+        memset(mdata,0,mdimx*mdimy*sizeof(T));
+    }
+
+    /** Initialize to zeros with a given size.
+     */
+    void initZeros(int Ydim, int Xdim)
+    {
+        if (mdimx!=Xdim || mdimy!=Ydim)
+            resize(Ydim, Xdim);
+        memset(mdata,0,mdimx*mdimy*sizeof(T));
+    }
+
+    /** Initialize to zeros following a pattern.
+      *
+      * All values are set to 0, and the origin and size of the pattern are
+      * adopted.
+      *
+      * @code
+      * v2.initZeros(v1);
+      * @endcode
+      */
+    template <typename T1>
+    void initZeros(const Matrix2D<T1>& op)
+    {
+        if (mdimx!=op.mdimx || mdimy!=op.mdimy)
+            resize(op);
+        memset(mdata,0,mdimx*mdimy*sizeof(T));
+    }
+
+    /** 2D Identity matrix of current size
+     *
+     * If actually the matrix is not squared then an identity matrix is
+     * generated of size (Xdim x Xdim).
+     *
+     * @code
+     * m.initIdentity();
+     * @endcode
+     */
+    void initIdentity()
+    {
+        initIdentity(MAT_XSIZE(*this));
+    }
+
+    /** 2D Identity matrix of a given size
+     *
+     * A (dim x dim) identity matrix is generated.
+     *
+     * @code
+     * m.initIdentity(3);
+     * @endcode
+     */
+    void initIdentity(int dim)
+    {
+        if (mdimx!=dim || mdimy!=dim)
+            resize(dim, dim);
+        for (int i = 0; i < dim; i++)
+            MAT_ELEM(*this,i,i) = 1;
+    }
+    //@}
+
+    /// @name Operators for Matrix2D
+    //@{
+
+    /** Matrix element access
+     */
+    T& operator()(int i, int j) const
+    {
+        return MAT_ELEM((*this),i,j);
+    }
+    /** Parenthesis operator for phyton
+    */
+    void setVal(T val,int y, int x)
+    {
+        MAT_ELEM((*this),y,x)=val;
+    }
+    /** Parenthesis operator for phyton
+    */
+    T getVal( int y, int x) const
+    {
+        return MAT_ELEM((*this),y,x);
+    }
+
+    /** v3 = v1 * k.
+     */
+    Matrix2D<T> operator*(T op1) const
+    {
+        Matrix2D<T> tmp(*this);
+        for (int i=0; i < mdim; i++)
+            tmp.mdata[i] = mdata[i] * op1;
+        return tmp;
+    }
+
+    /** v3 = v1 / k.
+     */
+    Matrix2D<T> operator/(T op1) const
+    {
+        Matrix2D<T> tmp(*this);
+        for (int i=0; i < mdim; i++)
+            tmp.mdata[i] = mdata[i] / op1;
+        return tmp;
+    }
+
+    /** v3 = k * v2.
+     */
+    friend Matrix2D<T> operator*(T op1, const Matrix2D<T>& op2)
+    {
+        Matrix2D<T> tmp(op2);
+        for (int i=0; i < op2.mdim; i++)
+            tmp.mdata[i] = op1 * op2.mdata[i];
+        return tmp;
+    }
+
+    /** v3 *= k.
+      */
+    void operator*=(T op1)
+    {
+        for (int i=0; i < mdim; i++)
+            mdata[i] *= op1;
+    }
+
+    /** v3 /= k.
+      */
+    void operator/=(T op1)
+    {
+        for (int i=0; i < mdim; i++)
+            mdata[i] /= op1;
+    }
+
+    /** Matrix by vector multiplication
+     *
+     * @code
+     * v2 = A*v1;
+     * @endcode
+     */
+    Matrix1D<T> operator*(const Matrix1D<T>& op1) const
+    {
+        Matrix1D<T> result;
+
+        if (mdimx != op1.size())
+            REPORT_ERROR("Not compatible sizes in matrix by vector");
+
+        if (!op1.isCol())
+            REPORT_ERROR("Vector is not a column");
+
+        result.initZeros(mdimy);
+
+        for (int i = 0; i < mdimy; i++)
+            for (int j = 0; j < op1.size(); j++)
+                result(i) += (*this)(i, j) * op1(j);
+
+        result.setCol();
+        return result;
+    }
+
+    /** Matrix by Matrix multiplication
+     *
+     * @code
+     * C = A*B;
+     * @endcode
+     */
+    Matrix2D<T> operator*(const Matrix2D<T>& op1) const
+    {
+        Matrix2D<T> result;
+        if (mdimx != op1.mdimy)
+            REPORT_ERROR("Not compatible sizes in matrix multiplication");
+
+        result.initZeros(mdimy, op1.mdimx);
+        for (int i = 0; i < mdimy; i++)
+            for (int j = 0; j < op1.mdimx; j++)
+                for (int k = 0; k < mdimx; k++)
+                    result(i, j) += (*this)(i, k) * op1(k, j);
+        return result;
+    }
+
+    /** Matrix summation
+     *
+     * @code
+     * C = A + B;
+     * @endcode
+     */
+    Matrix2D<T> operator+(const Matrix2D<T>& op1) const
+    {
+        Matrix2D<T> result;
+        if (mdimx != op1.mdimx || mdimy != op1.mdimy)
+            REPORT_ERROR("operator+: Not same sizes in matrix summation");
+
+        result.initZeros(mdimy, mdimx);
+        for (int i = 0; i < mdimy; i++)
+            for (int j = 0; j < mdimx; j++)
+                result(i, j) = (*this)(i, j) + op1(i, j);
+
+        return result;
+    }
+
+    /** Matrix summation
+     *
+     * @code
+     * A += B;
+     * @endcode
+     */
+    void operator+=(const Matrix2D<T>& op1) const
+    {
+        if (mdimx != op1.mdimx || mdimy != op1.mdimy)
+            REPORT_ERROR("operator+=: Not same sizes in matrix summation");
+
+        for (int i = 0; i < mdimy; i++)
+            for (int j = 0; j < mdimx; j++)
+                MAT_ELEM(*this,i, j) += MAT_ELEM(op1, i, j);
+    }
+
+    /** Matrix subtraction
+     *
+     * @code
+     * C = A - B;
+     * @endcode
+     */
+    Matrix2D<T> operator-(const Matrix2D<T>& op1) const
+    {
+        Matrix2D<T> result;
+        if (mdimx != op1.mdimx || mdimy != op1.mdimy)
+            REPORT_ERROR("operator-: Not same sizes in matrix summation");
+
+        result.initZeros(mdimy, mdimx);
+        for (int i = 0; i < mdimy; i++)
+            for (int j = 0; j < mdimx; j++)
+                result(i, j) = (*this)(i, j) - op1(i, j);
+
+        return result;
+    }
+
+    /** Matrix substraction
+     *
+     * @code
+     * A -= B;
+     * @endcode
+     */
+    void operator-=(const Matrix2D<T>& op1) const
+    {
+        if (mdimx != op1.mdimx || mdimy != op1.mdimy)
+            REPORT_ERROR("operator-=: Not same sizes in matrix summation");
+
+        for (int i = 0; i < mdimy; i++)
+            for (int j = 0; j < mdimx; j++)
+                MAT_ELEM(*this,i, j) -= MAT_ELEM(op1, i, j);
+    }
+
+    /** Equality.
+     *
+     * Returns true if this object has got the same shape (origin and size)
+     * than the argument and the same values (within accuracy).
+     */
+    bool equal(const Matrix2D<T>& op,
+               double accuracy = XMIPP_EQUAL_ACCURACY) const
+    {
+        if (!sameShape(op))
+            return false;
+        for (int i = 0; i < mdimy; i++)
+            for (int j = 0; j < mdimx; j++)
+                if (ABS( (*this)(i,j) - op(i,j) ) > accuracy)
+                    return false;
+        return true;
+    }
+    //@}
+
+    /// @name Utilities for Matrix2D
+    //@{
+    /** Set very small values (ABS(val)< accuracy) equal to zero
+      *
+      */
+    void setSmallValuesToZero(double accuracy = XMIPP_EQUAL_ACCURACY)
+    {
+        for (int i = 0; i < mdimy; i++)
+             for (int j = 0; j < mdimx; j++)
+                 if (ABS( (*this)(i,j) ) < accuracy)
+                	 (*this)(i,j) = 0.;
+    }
+
+    /// @name Utilities for Matrix2D
+    //@{
+    /** Maximum of the values in the array.
+      *
+      * The returned value is of the same type as the type of the array.
+      */
+    T computeMax() const
+    {
+        if (mdim <= 0)
+            return static_cast< T >(0);
+
+        T maxval = mdata[0];
+        for (int n = 0; n < mdim; n++)
+            if (mdata[n] > maxval)
+                maxval = mdata[n];
+        return maxval;
+    }
+
+    /** Minimum of the values in the array.
+       *
+       * The returned value is of the same type as the type of the array.
+       */
+    T computeMin() const
+    {
+        if (mdim <= 0)
+            return static_cast< T >(0);
+
+        T minval = mdata[0];
+        for (int n = 0; n < mdim; n++)
+            if (mdata[n] < minval)
+                minval = mdata[n];
+        return minval;
+    }
+
+    /** Produce a 2D array suitable for working with Numerical Recipes
+    *
+    * This function must be used only as a preparation for routines which need
+    * that the first physical index is 1 and not 0 as it usually is in C. New
+    * memory is needed to hold the new double pointer array.
+    */
+    T** adaptForNumericalRecipes() const
+    {
+        T** m = NULL;
+        ask_Tmatrix(m, 1, mdimy, 1, mdimx);
+
+        for (int i = 0; i < mdimy; i++)
+            for (int j = 0; j < mdimx; j++)
+                m[i+1][j+1] = mdata[i*mdimx + j];
+
+        return m;
+    }
+
+    /** Produce a 1D pointer suitable for working with Numerical Recipes (2)
+     *
+     * This function meets the same goal as the one before, however this one
+     * work with 2D arrays as a single pointer. The first element of the array
+     * is pointed by result[1*Xdim+1], and in general result[i*Xdim+j]
+     */
+    T* adaptForNumericalRecipes2() const
+    {
+        return mdata - 1 - mdimx;
+    }
+
+    /** Load 2D array from numerical recipes result.
+     */
+    void loadFromNumericalRecipes(T** m, int Ydim, int Xdim)
+    {
+        if (mdimx!=Xdim || mdimy!=Ydim)
+            resize(Ydim, Xdim);
+
+        for (int i = 1; i <= Ydim; i++)
+            for (int j = 1; j <= Xdim; j++)
+                (*this)(i - 1, j - 1) = m[i][j];
+    }
+
+    /** Kill a 2D array produced for numerical recipes
+     *
+     * The allocated memory is freed.
+     */
+    void killAdaptationForNumericalRecipes(T** m) const
+    {
+        free_Tmatrix(m, 1, mdimy, 1, mdimx);
+    }
+
+    /** Kill a 2D array produced for numerical recipes, 2.
+     *
+     * Nothing needs to be done.
+     */
+    void killAdaptationForNumericalRecipes2(T** m) const
+        {}
+
+    /** Write this matrix to file
+      */
+    void write(const FileName &fn) const
+    {
+        std::ofstream fhOut;
+        fhOut.open(fn.c_str());
+        if (!fhOut)
+            REPORT_ERROR((std::string)"write: Cannot open "+fn+" for output");
+        fhOut << *this;
+        fhOut.close();
+    }
+
+    /** Show matrix
+      */
+    friend std::ostream& operator<<(std::ostream& ostrm, const Matrix2D<T>& v)
+    {
+        if (v.Xdim() == 0 || v.Ydim() == 0)
+            ostrm << "NULL matrix\n";
+        else
+        {
+            ostrm << std::endl;
+            double max_val = v.computeMax();
+            int prec = bestPrecision(max_val, 10);
+
+            for (int i = 0; i < v.Ydim(); i++)
+            {
+                for (int j = 0; j < v.Xdim(); j++)
+                {
+                    ostrm << std::setw(13) << floatToString((double) v(i, j), 10, prec) << ' ';
+                }
+                ostrm << std::endl;
+            }
+        }
+
+        return ostrm;
+    }
+
+    /** Makes a matrix from a vector
+     *
+     * The origin of the matrix is set such that it has one of the index origins
+     * (X or Y) to the same value as the vector, and the other set to 0
+     * according to the shape.
+     *
+     * @code
+     * Matrix2D< double > m = fromVector(v);
+     * @endcode
+     */
+    void fromVector(const Matrix1D<T>& op1)
+    {
+        // Null vector => Null matrix
+        if (op1.size() == 0)
+        {
+            clear();
+            return;
+        }
+
+        // Look at shape and copy values
+        if (op1.isRow())
+        {
+            if (mdimy!=1 || mdimx!=VEC_XSIZE(op1))
+                resize(1, VEC_XSIZE(op1));
+
+            for (int j = 0; j < VEC_XSIZE(op1); j++)
+                MAT_ELEM(*this,0, j) = VEC_ELEM(op1,j);
+        }
+        else
+        {
+            if (mdimy!=1 || mdimx!=VEC_XSIZE(op1))
+                resize(VEC_XSIZE(op1), 1);
+
+            for (int i = 0; i < VEC_XSIZE(op1); i++)
+                MAT_ELEM(*this,i, 0) = VEC_ELEM(op1,i);
+        }
+    }
+
+    /** Makes a vector from a matrix
+     *
+     * An exception is thrown if the matrix is not a single row or a single
+     * column. The origin of the vector is set according to the one of the
+     * matrix.
+     *
+     * @code
+     * Matrix1D< double > v;
+     * m.toVector(v);
+     * @endcode
+     */
+    void toVector(Matrix1D<T>& op1) const
+    {
+        // Null matrix => Null vector
+        if (mdimx == 0 || mdimy == 0)
+        {
+            op1.clear();
+            return;
+        }
+
+        // If matrix is not a vector, produce an error
+        if (!(mdimx == 1 || mdimy == 1))
+            REPORT_ERROR("toVector: Matrix cannot be converted to vector");
+
+        // Look at shape and copy values
+        if (mdimy == 1)
+        {
+            // Row vector
+            if (VEC_XSIZE(op1)!=mdimx)
+                op1.resize(mdimx);
+
+            for (int j = 0; j < mdimx; j++)
+                VEC_ELEM(op1,j) = MAT_ELEM(*this,0, j);
+
+            op1.setRow();
+        }
+        else
+        {
+            // Column vector
+            if (VEC_XSIZE(op1)!=mdimy)
+                op1.resize(mdimy);
+
+            for (int i = 0; i < mdimy; i++)
+                VEC_ELEM(op1,i) = MAT_ELEM(*this,i, 0);
+
+            op1.setCol();
+        }
+    }
+
+    /**Copy matrix to stl::vector
+     */
+    void copyToVector(std::vector<T> &v)
+    {
+        v.assign(mdata, mdata+mdim);
+    }
+    /**Copy stl::vector to matrix
+      */
+    void copyFromVector(std::vector<T> &v,int Xdim, int Ydim)
+    {
+        if (mdimx!=Xdim || mdimy!=Ydim)
+            resize(Ydim, Xdim);
+        copy( v.begin(), v.begin()+v.size(), mdata);
+    }
+
+    /** Get row
+     *
+     * This function returns a row vector corresponding to the choosen
+     * row inside the nth 2D matrix, the numbering of the rows is also
+     * logical not physical.
+     *
+     * @code
+     * std::vector< double > v;
+     * m.getRow(-2, v);
+     * @endcode
+     */
+    void getRow(int i, Matrix1D<T>& v) const
+    {
+        if (mdimx == 0 || mdimy == 0)
+        {
+            v.clear();
+            return;
+        }
+
+        if (i < 0 || i >= mdimy)
+            REPORT_ERROR("getRow: Matrix subscript (i) greater than matrix dimension");
+
+        if (VEC_XSIZE(v)!=mdimx)
+            v.resize(mdimx);
+        for (int j = 0; j < mdimx; j++)
+            VEC_ELEM(v,j) = MAT_ELEM(*this,i, j);
+
+        v.setRow();
+    }
+
+    /** Get Column
+     *
+     * This function returns a column vector corresponding to the
+     * choosen column.
+     *
+     * @code
+     * std::vector< double > v;
+     * m.getCol(-1, v);
+     * @endcode
+     */
+    void getCol(int j, Matrix1D<T>& v) const
+    {
+        if (mdimx == 0 || mdimy == 0)
+        {
+            v.clear();
+            return;
+        }
+
+        if (j < 0 || j >= mdimx)
+            REPORT_ERROR("getCol: Matrix subscript (j) greater than matrix dimension");
+
+        if (VEC_XSIZE(v)!=mdimy)
+            v.resize(mdimy);
+        for (int i = 0; i < mdimy; i++)
+            VEC_ELEM(v,i) = MAT_ELEM(*this,i, j);
+
+        v.setCol();
+    }
+
+    /** Set Row
+     *
+     * This function sets a row vector corresponding to the choosen row in the 2D Matrix
+     *
+     * @code
+     * m.setRow(-2, m.row(1)); // Copies row 1 in row -2
+     * @endcode
+     */
+    void setRow(int i, const Matrix1D<T>& v)
+    {
+        if (mdimx == 0 || mdimy == 0)
+            REPORT_ERROR("setRow: Target matrix is empty");
+
+        if (i < 0 || i >= mdimy)
+            REPORT_ERROR("setRow: Matrix subscript (i) out of range");
+
+        if (VEC_XSIZE(v) != mdimx)
+            REPORT_ERROR("setRow: Vector dimension different from matrix one");
+
+        if (!v.isRow())
+            REPORT_ERROR("setRow: Not a row vector in assignment");
+
+        for (int j = 0; j < mdimx; j++)
+            MAT_ELEM(*this,i, j) = VEC_ELEM(v,j);
+    }
+
+    /** Set Column
+     *
+     * This function sets a column vector corresponding to the choosen column
+     * inside matrix.
+     *
+     * @code
+     * m.setCol(0, (m.row(1)).transpose()); // Copies row 1 in column 0
+     * @endcode
+     */
+    void setCol(int j, const Matrix1D<T>& v)
+    {
+        if (mdimx == 0 || mdimy == 0)
+            REPORT_ERROR("setCol: Target matrix is empty");
+
+        if (j < 0 || j>= mdimx)
+            REPORT_ERROR("setCol: Matrix subscript (j) out of range");
+
+        if (VEC_XSIZE(v) != mdimy)
+            REPORT_ERROR("setCol: Vector dimension different from matrix one");
+
+        if (!v.isCol())
+            REPORT_ERROR("setCol: Not a column vector in assignment");
+
+        for (int i = 0; i < mdimy; i++)
+            MAT_ELEM(*this,i, j) = VEC_ELEM(v,i);
+    }
+
+    /** Determinant of a matrix
+     *
+     * An exception is thrown if the matrix is not squared or it is empty.
+     *
+     * @code
+     * double det = m.det();
+     * @endcode
+     */
+    T det() const
+    {
+        // (see Numerical Recipes, Chapter 2 Section 5)
+        if (mdimx == 0 || mdimy == 0)
+            REPORT_ERROR("determinant: Matrix is empty");
+
+        if (mdimx != mdimy)
+            REPORT_ERROR("determinant: Matrix is not squared");
+
+        for (int i = 0; i < mdimy; i++)
+        {
+            bool all_zeros = true;
+            for (int j = 0; j < mdimx; j++)
+                if (ABS(MAT_ELEM((*this),i, j)) > XMIPP_EQUAL_ACCURACY)
+                {
+                    all_zeros = false;
+                    break;
+                }
+
+            if (all_zeros)
+                return 0;
+        }
+
+        // Perform decomposition
+        Matrix1D< int > indx;
+        T d;
+        Matrix2D<T> LU;
+        ludcmp(*this, LU, indx, d);
+
+        // Calculate determinant
+        for (int i = 0; i < mdimx; i++)
+            d *= (T) MAT_ELEM(LU,i , i);
+
+        return d;
+    }
+
+    /** Algebraic transpose of a Matrix
+     *
+     * You can use the transpose in as complex expressions as you like. The
+     * origin of the vector is not changed.
+     *
+     * @code
+     * v2 = v1.transpose();
+     * @endcode
+     */
+    Matrix2D<T> transpose() const
+    {
+        Matrix2D<T> result(mdimx, mdimy);
+        FOR_ALL_ELEMENTS_IN_MATRIX2D(result)
+        MAT_ELEM(result,i,j) = MAT_ELEM((*this),j,i);
+        return result;
+    }
+
+    /** Inverse of a matrix
+     *
+     * The matrix is inverted using a SVD decomposition. In fact the
+     * pseudoinverse is returned.
+     *
+     * @code
+     * Matrix2D< double > m1_inv;
+     * m1.inv(m1_inv);
+     * @endcode
+     */
+    void inv(Matrix2D<T>& result) const
+    {
+
+        if (mdimx == 0 || mdimy == 0)
+        {
+        	REPORT_ERROR("Inverse: Matrix is empty");
+        }
+        // Initialise output
+        result.initZeros(mdimx, mdimy);
+
+        if (mdimx == 3 && mdimy == 3)
+        {
+        	MAT_ELEM(result, 0, 0) =   MAT_ELEM((*this), 2, 2)*MAT_ELEM((*this), 1, 1)-MAT_ELEM((*this), 2, 1)*MAT_ELEM((*this), 1, 2);
+        	MAT_ELEM(result, 0, 1) = -(MAT_ELEM((*this), 2, 2)*MAT_ELEM((*this), 0, 1)-MAT_ELEM((*this), 2, 1)*MAT_ELEM((*this), 0, 2));
+        	MAT_ELEM(result, 0, 2) =   MAT_ELEM((*this), 1, 2)*MAT_ELEM((*this), 0, 1)-MAT_ELEM((*this), 1, 1)*MAT_ELEM((*this), 0, 2);
+        	MAT_ELEM(result, 1, 0) = -(MAT_ELEM((*this), 2, 2)*MAT_ELEM((*this), 1, 0)-MAT_ELEM((*this), 2, 0)*MAT_ELEM((*this), 1, 2));
+        	MAT_ELEM(result, 1, 1) =   MAT_ELEM((*this), 2, 2)*MAT_ELEM((*this), 0, 0)-MAT_ELEM((*this), 2, 0)*MAT_ELEM((*this), 0, 2);
+        	MAT_ELEM(result, 1, 2) = -(MAT_ELEM((*this), 1, 2)*MAT_ELEM((*this), 0, 0)-MAT_ELEM((*this), 1, 0)*MAT_ELEM((*this), 0, 2));
+        	MAT_ELEM(result, 2, 0) =   MAT_ELEM((*this), 2, 1)*MAT_ELEM((*this), 1, 0)-MAT_ELEM((*this), 2, 0)*MAT_ELEM((*this), 1, 1);
+        	MAT_ELEM(result, 2, 1) = -(MAT_ELEM((*this), 2, 1)*MAT_ELEM((*this), 0, 0)-MAT_ELEM((*this), 2, 0)*MAT_ELEM((*this), 0, 1));
+        	MAT_ELEM(result, 2, 2) =   MAT_ELEM((*this), 1, 1)*MAT_ELEM((*this), 0, 0)-MAT_ELEM((*this), 1, 0)*MAT_ELEM((*this), 0, 1);
+        	double tmp = MAT_ELEM((*this), 0, 0) * MAT_ELEM(result, 0, 0) +
+        			     MAT_ELEM((*this), 1, 0) * MAT_ELEM(result, 0, 1) +
+        			     MAT_ELEM((*this), 2, 0) * MAT_ELEM(result, 0, 2);
+        	result /= tmp;
+        }
+        else if (mdimx == 2 && mdimy == 2)
+        {
+        	MAT_ELEM(result, 0, 0) = MAT_ELEM((*this), 1, 1);
+        	MAT_ELEM(result, 0, 1) = -MAT_ELEM((*this), 0, 1);
+        	MAT_ELEM(result, 1, 0) = -MAT_ELEM((*this), 1, 0);
+        	MAT_ELEM(result, 1, 1) =  MAT_ELEM((*this), 0, 0);
+        	double tmp = MAT_ELEM((*this), 0, 0) * MAT_ELEM((*this), 1, 1) -
+					     MAT_ELEM((*this), 0, 1) * MAT_ELEM((*this), 1, 0);
+        	result /= tmp;
+        }
+        else
+        {
+
+			// Perform SVD decomposition
+			Matrix2D< double > u, v;
+			Matrix1D< double > w;
+			svdcmp(*this, u, w, v); // *this = U * W * V^t
+
+			double tol = computeMax() * XMIPP_MAX(mdimx, mdimy) * 1e-14;
+
+			// Compute W^-1
+			bool invertible = false;
+			FOR_ALL_ELEMENTS_IN_MATRIX1D(w)
+			{
+				if (ABS(VEC_ELEM(w,i)) > tol)
+				{
+					VEC_ELEM(w,i) = 1.0 / VEC_ELEM(w,i);
+					invertible = true;
+				}
+				else
+					VEC_ELEM(w,i) = 0.0;
+			}
+
+			if (!invertible)
+				return;
+
+			// Compute V*W^-1
+			FOR_ALL_ELEMENTS_IN_MATRIX2D(v)
+			MAT_ELEM(v,i,j) *= VEC_ELEM(w,j);
+
+			// Compute Inverse
+			for (int i = 0; i < mdimx; i++)
+				for (int j = 0; j < mdimy; j++)
+					for (int k = 0; k < mdimx; k++)
+						MAT_ELEM(result,i,j) += (T) MAT_ELEM(v,i,k) * MAT_ELEM(u,j,k);
+
+       }
+
+    }
+
+    /** Inverse of a matrix
+     */
+    Matrix2D<T> inv() const
+    {
+        Matrix2D<T> result;
+        inv(result);
+
+        return result;
+    }
+
+    /** True if the matrix is identity
+     *
+     * @code
+     * if (m.isIdentity())
+     *     std::cout << "The matrix is identity\n";
+     * @endcode
+     */
+    bool isIdentity() const
+    {
+        for (int i = 0; i < mdimy; i++)
+            for (int j = 0; j < mdimx; j++)
+                if (i != j)
+                {
+                    if (ABS(MAT_ELEM(*this,i,j)) > XMIPP_EQUAL_ACCURACY)
+                        return false;
+                }
+                else
+                {
+                    if (ABS(MAT_ELEM(*this,i,j) - 1.) > XMIPP_EQUAL_ACCURACY )
+                        return false;
+                }
+        return true;
+    }
+    //@}
+};
+
+// Implementation of the vector*matrix
+// Documented in matrix1D.h
+template<typename T>
+Matrix1D<T> Matrix1D<T>::operator*(const Matrix2D<T>& M)
+{
+    Matrix1D<T> result;
+
+    if (VEC_XSIZE(*this) != MAT_YSIZE(M))
+        REPORT_ERROR("Not compatible sizes in matrix by vector");
+
+    if (!isRow())
+        REPORT_ERROR("Vector is not a row");
+
+    result.initZeros(MAT_XSIZE(M));
+    for (int j = 0; j < MAT_XSIZE(M); j++)
+        for (int i = 0; i < MAT_YSIZE(M); i++)
+            VEC_ELEM(result,j) += VEC_ELEM(*this,i) * MAT_ELEM(M,i, j);
+
+    result.setRow();
+    return result;
+}
+
+/**@name Matrix Related functions
+ * These functions are not methods of Matrix2D
+ */
+//@{
+/** LU Decomposition
+ */
+template<typename T>
+void ludcmp(const Matrix2D<T>& A, Matrix2D<T>& LU, Matrix1D< int >& indx, T& d)
+{
+    LU = A;
+    if (VEC_XSIZE(indx)!=A.mdimx)
+        indx.resize(A.mdimx);
+    ludcmp(LU.adaptForNumericalRecipes2(), A.mdimx,
+           indx.adaptForNumericalRecipes(), &d);
+}
+
+/** LU Backsubstitution
+ */
+template<typename T>
+void lubksb(const Matrix2D<T>& LU, Matrix1D< int >& indx, Matrix1D<T>& b)
+{
+    lubksb(LU.adaptForNumericalRecipes2(), indx.size(),
+           indx.adaptForNumericalRecipes(),
+           b.adaptForNumericalRecipes());
+}
+
+/** SVD Backsubstitution
+ */
+void svbksb(Matrix2D< double >& u,
+            Matrix1D< double >& w,
+            Matrix2D< double >& v,
+            Matrix1D< double >& b,
+            Matrix1D< double >& x);
+
+/** SVD Decomposition (through numerical recipes)
+ */
+template<typename T>
+void svdcmp(const Matrix2D< T >& a,
+            Matrix2D< double >& u,
+            Matrix1D< double >& w,
+            Matrix2D< double >& v)
+{
+    // svdcmp only works with double
+    typeCast(a, u);
+
+    // Set size of matrices
+    w.initZeros(u.mdimx);
+    v.initZeros(u.mdimx, u.mdimx);
+
+    // Call to the numerical recipes routine
+    svdcmp(u.mdata,
+           u.mdimy, u.mdimx,
+           w.vdata,
+           v.mdata);
+}
+
+/** Solve system of linear equations (Ax=b) through SVD Decomposition (through numerical recipes)
+ */
+template<typename T>
+void solve(const Matrix2D< double >& A, const Matrix1D< double >& b,
+                  Matrix1D< double >& result, double tolerance)
+{
+    if (A.mdimx == 0)
+        REPORT_ERROR("Solve: Matrix is empty");
+
+    if (A.mdimx != A.mdimy)
+        REPORT_ERROR("Solve: Matrix is not squared");
+
+    if (A.mdimx != b.vdim)
+        REPORT_ERROR("Solve: Different sizes of Matrix and Vector");
+
+    if (b.isRow())
+        REPORT_ERROR("Solve: Not correct vector shape");
+
+    // First perform de single value decomposition
+    // Xmipp interface that calls to svdcmp of numerical recipes
+    Matrix2D< double > u, v;
+    Matrix1D< double > w;
+    svdcmp(A, u, w, v);
+
+    // Here is checked if eigenvalues of the svd decomposition are acceptable
+    // If a value is lower than tolerance, the it's zeroed, as this increases
+    // the precision of the routine.
+    FOR_ALL_ELEMENTS_IN_MATRIX1D(w)
+    if (w(i) < tolerance)
+        w(i) = 0;
+
+    // Set size of matrices
+    result.resize(b.vdim);
+
+    // Xmipp interface that calls to svdksb of numerical recipes
+    Matrix1D< double > bd;
+    typeCast(b, bd);
+    svbksb(u, w, v, bd, result);
+}
+
+/** Solve system of linear equations (Ax=b), x and b being matrices through SVD Decomposition (through Gauss-Jordan numerical recipes)
+ */
+template<typename T>
+void solve(const Matrix2D<T>& A, const Matrix2D<T>& b, Matrix2D<T>& result)
+{
+    if (A.mdimx == 0)
+        REPORT_ERROR("Solve: Matrix is empty");
+
+    if (A.mdimx != A.mdimy)
+        REPORT_ERROR("Solve: Matrix is not squared");
+
+    if (A.mdimy != b.mdimy)
+        REPORT_ERROR("Solve: Different sizes of A and b");
+
+    // Solve
+    result = b;
+    Matrix2D<T> Aux = A;
+    gaussj(Aux.adaptForNumericalRecipes2(), Aux.mdimy,
+           result.adaptForNumericalRecipes2(), b.mdimx);
+}
+
+
+/** Least-squares rigid transformation between two sets of 3D coordinates
+ *
+double lsq_rigid_body_transformation(std::vector<Matrix1D<double> > &set1, std::vector<Matrix1D<double> > &set2,
+		Matrix2D<double> &Rot, Matrix1D<double> &trans)
+{
+	Matrix2D<double> A;
+	Matrix1D<double> avg1, avg2;
+
+	if (set1.size() != set2.size())
+		REPORT_ERROR("lsq_rigid_body_transformation ERROR: unequal set size");
+
+	// Calculate average of set1 and set2
+	avg1 = vectorR3(0., 0., 0.);
+	avg2 = vectorR3(0., 0., 0.);
+	for (int i = 0; i < set1.size(); i++)
+	{
+		if (set1[i].vdim != 3)
+			REPORT_ERROR("lsq_rigid_body_transformation ERROR: not a 3-point set1");
+		if (set2[i].vdim != 3)
+			REPORT_ERROR("lsq_rigid_body_transformation ERROR: not a 3-point set2");
+		avg1 += set1[i];
+		avg2 += set2[i];
+	}
+	avg1 /= (double)set1.size();
+	avg2 /= (double)set1.size();
+
+	A.initZeros(3, 3);
+	Rot.initZeros(4,4);
+	for (int i = 0; i < set1.size(); i++)
+	{
+		// fill A
+		A(0, 0) += (XX(set1[i]) - XX(avg1)) * (XX(set2[i]) - XX(avg2));
+		A(0, 1) += (XX(set1[i]) - XX(avg1)) * (YY(set2[i]) - YY(avg2));
+		A(0, 2) += (XX(set1[i]) - XX(avg1)) * (ZZ(set2[i]) - ZZ(avg2));
+		A(1, 0) += (YY(set1[i]) - YY(avg1)) * (XX(set2[i]) - XX(avg2));
+		A(1, 1) += (YY(set1[i]) - YY(avg1)) * (YY(set2[i]) - YY(avg2));
+		A(1, 2) += (YY(set1[i]) - YY(avg1)) * (ZZ(set2[i]) - ZZ(avg2));
+		A(2, 0) += (ZZ(set1[i]) - ZZ(avg1)) * (XX(set2[i]) - XX(avg2));
+		A(2, 1) += (ZZ(set1[i]) - ZZ(avg1)) * (YY(set2[i]) - YY(avg2));
+		A(2, 2) += (ZZ(set1[i]) - ZZ(avg1)) * (ZZ(set2[i]) - ZZ(avg2));
+	}
+
+	Matrix2D< double > U, V;
+	Matrix1D< double > w;
+
+	// TODO: check inverse, transpose etc etc!!!
+
+	// Optimal rotation
+	svdcmp(A, U, w, V);
+	Rot = V.transpose() * U;
+
+	// Optimal translation
+	trans = avg1 - Rot * avg2;
+
+	// return the squared difference term
+	double error = 0.;
+	for (int i = 0; i < set1.size(); i++)
+	{
+		error += (Rot * set2[i] + trans - set1[i]).sum2();
+	}
+
+	return error;
+
+}
+*/
+
+/** Conversion from one type to another.
+ *
+ * If we have an integer array and we need a double one, we can use this
+ * function. The conversion is done through a type casting of each element
+ * If n >= 0, only the nth volumes will be converted, otherwise all NSIZE volumes
+ */
+template<typename T1, typename T2>
+void typeCast(const Matrix2D<T1>& v1,  Matrix2D<T2>& v2)
+{
+    if (v1.mdim == 0)
+    {
+        v2.clear();
+        return;
+    }
+
+    if (v1.mdimx!=v2.mdimx || v1.mdimy!=v2.mdimy)
+        v2.resize(v1);
+    for (unsigned long int n = 0; n < v1.mdim; n++)
+        v2.mdata[n] = static_cast< T2 > (v1.mdata[n]);
+}
+//@}
+//@}
+#endif /* MATRIX2D_H_ */
diff --git a/src/memory.cpp b/src/memory.cpp
new file mode 100644
index 0000000..7a12f4c
--- /dev/null
+++ b/src/memory.cpp
@@ -0,0 +1,56 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/memory.h"
+
+char*  askMemory(unsigned long memsize) 
+{ 
+    char*		ptr = NULL;
+    
+    if ( memsize == 0 ) {
+        REPORT_ERROR("Error in askMemory: Memory allocation size requested is zero!");
+        return(NULL);
+    }
+	
+    if ( ( ptr = (char *) calloc(1,memsize*sizeof(char)) ) == NULL ) {
+        std::cerr<<"Memory allocation of %ld bytes failed, memsize= "<< memsize<<std::endl;
+        REPORT_ERROR("Error in askMemory");
+        return(NULL); 
+    }
+	
+    //memset(ptr, 0, memsize); 	 
+
+    return(ptr); 
+}
+
+int  freeMemory(void* ptr, unsigned long memsize)
+{
+    if ( ptr == NULL ) 
+        return(0);
+	
+    if ( memsize < 1 ) 
+    {
+        return(-1);
+    }
+
+    free(ptr);
+    ptr = NULL;
+    return(0);
+}
+
diff --git a/src/memory.h b/src/memory.h
new file mode 100644
index 0000000..a1a8ada
--- /dev/null
+++ b/src/memory.h
@@ -0,0 +1,189 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef _XMIPP_MEMORY
+#define _XMIPP_MEMORY
+
+#include "src/error.h"
+
+/* Memory managing --------------------------------------------------------- */
+///@defgroup MemoryManaging Memory management for numerical recipes
+/// @ingroup DataLibrary
+//@{
+/** Ask memory for any type vector.
+    The valid values range from v[nl] to v[nh]. If no memory is available
+    an exception is thrown. NULL is returned if nh is not greater than nl*/
+template <class T> void ask_Tvector(T* &v, int nl, int nh)
+{
+    if (nh - nl + 1 > 1)
+    {
+        v = (T *)malloc((unsigned)(nh - nl + 1) * sizeof(T));
+        if (!v) REPORT_ERROR("allocation failure in vector()");
+        v -= nl;
+    }
+    else v = NULL;
+}
+
+/** Free memory associated to any type vector.
+    After freeing v=NULL*/
+template <class T> void free_Tvector(T* &v, int nl, int nh)
+{
+    if (v != NULL)
+    {
+        free((char*)(v + nl));
+        v = NULL;
+    }
+}
+
+/** Ask memory for any type matrix.
+    The valid values range from v[nrl][ncl] to v[nrh][nch].
+    If no memory is available an exception is thrown. NULL is returned if any
+    nh is not greater than its nl*/
+template <class T> void ask_Tmatrix(T ** &m, int nrl, int nrh,
+                                    int ncl, int nch)
+{
+    if (nrh - nrl + 1 > 1 && nch - ncl + 1 > 1)
+    {
+        m = (T **) malloc((unsigned)(nrh - nrl + 1) * sizeof(T*));
+        if (!m) REPORT_ERROR( "allocation failure 1 in matrix()");
+        m -= nrl;
+
+        for (int i = nrl;i <= nrh;i++)
+        {
+            m[i] = (T *) malloc((unsigned)(nch - ncl + 1) * sizeof(T));
+            if (!m[i]) REPORT_ERROR( "allocation failure 2 in matrix()");
+            m[i] -= ncl;
+        }
+    }
+    else m = NULL;
+}
+
+/** Free memory associated to any type matrix.
+    After freeing v=NULL*/
+template <class T> void free_Tmatrix(T ** &m, int nrl, int nrh,
+                                     int ncl, int nch)
+{
+    if (m != NULL)
+    {
+        for (int i = nrh;i >= nrl;i--) free((char*)(m[i] + ncl));
+        free((char*)(m + nrl));
+        m = NULL;
+    }
+}
+
+/** Ask memory for any type voliume.
+    The valid values range from v[nsl][nrl][ncl] to v[nsh][nrh][nch].
+    If no memory is available an exception is thrown. NULL is returned if any
+    nh is not greater than its nl. */
+template <class T> void ask_Tvolume(T *** &m, int nsl, int nsh, int nrl,
+                                    int nrh, int ncl, int nch)
+{
+    if (nsh - nsl + 1 > 1 && nrh - nrl + 1 > 1 && nch - ncl + 1 > 1)
+    {
+        m = (T ***) malloc((unsigned)(nsh - nsl + 1) * sizeof(T**));
+        if (!m) REPORT_ERROR( "allocation failure 1 in matrix()");
+        m -= nsl;
+
+        for (int k = nsl;k <= nsh;k++)
+        {
+            m[k] = (T **) malloc((unsigned)(nrh - nrl + 1) * sizeof(T*));
+            if (!m[k]) REPORT_ERROR( "allocation failure 2 in matrix()");
+            m[k] -= nrl;
+
+            for (int i = nrl;i <= nrh;i++)
+            {
+                m[k][i] = (T *) malloc((unsigned)(nch - ncl + 1) * sizeof(T));
+                if (!m[k][i]) REPORT_ERROR( "allocation failure 2 in matrix()");
+                m[k][i] -= ncl;
+            }
+        }
+    }
+    else m = NULL;
+}
+
+/** Free memory associated to any type volume.
+    After freeing v=NULL*/
+template <class T> void free_Tvolume(T *** &m, int nsl, int nsh,
+                                     int nrl, int nrh, int ncl, int nch)
+{
+    if (m != NULL)
+    {
+        for (int k = nsh;k >= nsl;k--)
+        {
+            for (int i = nrh;i >= nrl;i--) free((char*)(m[k][i] + ncl));
+            free((char*)(m[k] + nrl));
+        }
+        free((char*)(m + nsl));
+        m = NULL;
+    }
+}
+/** Allocates memory.
+ * Adapted from Bsofts bfree
+ *
+ * It is called exactly like malloc, with the following enhancements:
+ *
+ * - If allocation of zero bytes are requested it notifies the user.
+ * - NO LONGER TRUE: Successfully allocated memory is zeroed
+ * - Allocation is attempted and an error message is printed on failure.
+ * - All failures return a NULL pointer to allow error handling from
+ *    calling functions.
+ *
+ * returns char* : a pointer to the memory (NULL on failure)
+ */
+char* askMemory(unsigned long size);
+
+/** Frees allocated memory.
+ * Adapted from Bsofts bfree
+ *
+ * It is called exactly like free, with the following enhancements:
+ *  - If freeing fails an error message is printed.
+ *  - the pointer is reset to NULL
+ *
+ * returns int: 0 = success, -1 = failure.
+*/
+int freeMemory(void* ptr, unsigned long memsize);
+
+//@}
+#endif
+
diff --git a/src/metadata_container.cpp b/src/metadata_container.cpp
new file mode 100644
index 0000000..338479a
--- /dev/null
+++ b/src/metadata_container.cpp
@@ -0,0 +1,486 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     J.R. Bilbao-Castro (jrbcast at ace.ual.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+#include "src/metadata_container.h"
+
+MetaDataContainer::MetaDataContainer()
+{
+}
+;
+MetaDataContainer::~MetaDataContainer()
+{
+    clear();
+}
+;
+
+
+
+void MetaDataContainer::insertVoidPtr(EMDLabel name, void * value)
+{
+    // If values[name] already existed, first free that memory
+    if (values[name])
+    {
+        if (EMDL::isDouble(name))
+            delete (double*)values[name];
+        else if (EMDL::isInt(name))
+            delete (int*)values[name];
+        else if (EMDL::isLong(name))
+            delete (long int*)values[name];
+        else if (EMDL::isBool(name))
+            delete (bool*)values[name];
+        else if (EMDL::isString(name))
+            delete (std::string*)values[name];
+        else
+            REPORT_ERROR("Unrecognised label type in MetaDataContainer clear");
+    }
+    values[name] = value;
+}
+
+void * MetaDataContainer::getVoidPtr(EMDLabel name)
+{
+    std::map<EMDLabel, void *>::iterator element;
+    element = values.find(name);
+    if (element == values.end())
+    {
+        REPORT_ERROR((std::string) "Label " + EMDL::label2Str(name) + " not found on getVoidPtr()\n" );
+    }
+    else
+    {
+        return element->second;
+    }
+}
+
+void MetaDataContainer::copy(const MetaDataContainer &MDc)
+{
+
+    clear();
+	if (this != &MDc)
+    {
+        void * aux;
+        EMDLabel lCode;
+        std::map<EMDLabel, void *>::const_iterator It;
+        for (It = (MDc.values).begin(); It != (MDc.values).end(); It++)
+        {
+            aux = It->second;
+            lCode = It->first;
+
+            if (EMDL::isDouble(lCode))
+            {
+                addValue(lCode, *((double *) aux));
+            }
+            else if (EMDL::isString(lCode))
+            {
+                addValue(lCode, *((std::string *) aux));
+            }
+            else if (EMDL::isInt(lCode))
+            {
+                addValue(lCode, *((int *) aux));
+            }
+            else if (EMDL::isLong(lCode))
+            {
+                addValue(lCode, *((long int *) aux));
+            }
+            else if (EMDL::isBool(lCode))
+            {
+                addValue(lCode, *((bool *) aux));
+            }
+
+        }
+    }
+}
+
+MetaDataContainer& MetaDataContainer::operator =(const MetaDataContainer &MDc)
+{
+    copy(MDc);
+    return *this;
+}
+
+MetaDataContainer::MetaDataContainer(const MetaDataContainer &MDc)
+{
+    copy(MDc);
+}
+
+
+void MetaDataContainer::addValue(const std::string &name,
+        const std::string &value)
+{
+    EMDLabel lCode = EMDL::str2Label(name);
+    std::istringstream i(value);
+
+    // Look for a double value
+    if (EMDL::isDouble(lCode))
+    {
+        double doubleValue;
+
+        i >> doubleValue;
+
+        addValue(lCode, doubleValue);
+    }
+    else if (EMDL::isString(lCode))
+    {
+        addValue(lCode, value);
+    }
+    else if (EMDL::isInt(lCode))
+    {
+        int intValue;
+
+        i >> intValue;
+
+        addValue(lCode, intValue);
+    }
+    else if (EMDL::isLong(lCode))
+    {
+        long int longValue;
+
+        i >> longValue;
+
+        addValue(lCode, longValue);
+    }
+    else if (EMDL::isBool(lCode))
+    {
+        bool boolValue;
+
+        i >> boolValue;
+
+        addValue(lCode, boolValue);
+    }
+}
+
+void MetaDataContainer::addValue(EMDLabel name, const double &value)
+{
+    if (EMDL::isDouble(name))
+    {
+    	void * newValue = (void *) (new double(value));
+    	insertVoidPtr(name, newValue);
+    }
+    else
+    	REPORT_ERROR("addValue for double: label " + EMDL::label2Str(name) + " is not of type double!");
+}
+
+void MetaDataContainer::addValue(EMDLabel name, const int &value)
+{
+    if (EMDL::isInt(name))
+    {
+    	void * newValue = (void *) (new int(value));
+    	insertVoidPtr(name, newValue);
+    }
+    else
+    	REPORT_ERROR("addValue for int: label " + EMDL::label2Str(name) + " is not of type int!");
+}
+
+void MetaDataContainer::addValue(EMDLabel name, const long int &value)
+{
+    if (EMDL::isLong(name))
+    {
+    	void * newValue = (void *) (new long int(value));
+    	insertVoidPtr(name, newValue);
+    }
+    else
+    	REPORT_ERROR("addValue for long: label " + EMDL::label2Str(name) + " is not of type long!");
+}
+
+void MetaDataContainer::addValue(EMDLabel name, const bool &value)
+{
+    if (EMDL::isBool(name))
+    {
+    	void * newValue = (void *) (new bool(value));
+    	insertVoidPtr(name, newValue);
+    }
+    else
+    	REPORT_ERROR("addValue for bool: label " + EMDL::label2Str(name) + " is not of type bool!");
+}
+
+void MetaDataContainer::addValue(EMDLabel name, const std::string &value)
+{
+    if (EMDL::isString(name))
+    {
+    	void * newValue = (void *) (new std::string(value));
+    	insertVoidPtr(name, newValue);
+    }
+    else
+    	REPORT_ERROR("addValue for string: label " + EMDL::label2Str(name) + " is not of type string!");
+}
+
+/** Creates a new label-value pair, with the default value for the corresponding type */
+void MetaDataContainer::addDefaultValue(EMDLabel name)
+{
+	void * newValue;
+	if (EMDL::isDouble(name))
+    {
+    	newValue = (void *) (new double(0.));
+    }
+    else if (EMDL::isInt(name) || EMDL::isLong(name))
+    {
+    	newValue = (void *) (new int(0));
+    }
+    else if (EMDL::isBool(name))
+    {
+    	newValue = (void *) (new bool(false));
+    }
+    else if (EMDL::isString(name))
+    {
+    	newValue = (void *) (new std::string(""));
+    }
+    else
+    	REPORT_ERROR("MetaDataContainer::addDefaultValu: unrecognised data type for label " + EMDL::label2Str(name));
+
+    insertVoidPtr(name, newValue);
+
+}
+
+bool MetaDataContainer::getValue( const EMDLabel name, double &value)
+{
+    std::map<EMDLabel, void *>::iterator element;
+
+    element = values.find(name);
+
+    if (element == values.end())
+    {
+        return false;
+    }
+    else
+    {
+    	if (EMDL::isDouble(element->first))
+    		value = *((double *) element->second);
+    	else
+    		REPORT_ERROR("getValue for double: label " + EMDL::label2Str(element->first) + " is not of type double!");
+
+    	return true;
+    }
+}
+
+bool MetaDataContainer::getValue( const EMDLabel name, int &value)
+{
+    std::map<EMDLabel, void *>::iterator element;
+
+    element = values.find(name);
+
+    if (element == values.end())
+    {
+        return false;
+    }
+    else
+    {
+    	if (EMDL::isInt(element->first))
+    		value = *((int *) element->second);
+    	else
+    		REPORT_ERROR("getValue for int: label " + EMDL::label2Str(element->first) + " is not of type int!");
+
+    	return true;
+    }
+}
+
+bool MetaDataContainer::getValue( const EMDLabel name, long int &value)
+{
+    std::map<EMDLabel, void *>::iterator element;
+
+    element = values.find(name);
+
+    if (element == values.end())
+    {
+        return false;
+    }
+    else
+    {
+    	if (EMDL::isLong(element->first))
+    		value = *((long int *) element->second);
+    	else
+    		REPORT_ERROR("getValue for long int: label " + EMDL::label2Str(element->first) + " is not of type long int!");
+
+    	return true;
+    }
+}
+
+bool MetaDataContainer::getValue( const EMDLabel name, bool &value)
+{
+    std::map<EMDLabel, void *>::iterator element;
+
+    element = values.find(name);
+
+    if (element == values.end())
+    {
+        return false;
+    }
+    else
+    {
+    	if (EMDL::isBool(element->first))
+    		value = *((bool *) element->second);
+    	else
+    		REPORT_ERROR("getValue for bool: label " + EMDL::label2Str(element->first) + " is not of type bool!");
+
+    	return true;
+    }
+}
+
+bool MetaDataContainer::getValue( const EMDLabel name, std::string &value)
+{
+    std::map<EMDLabel, void *>::iterator element;
+
+    element = values.find(name);
+
+    if (element == values.end())
+    {
+        return false;
+    }
+    else
+    {
+    	if (EMDL::isString(element->first))
+    		value = *((std::string *) element->second);
+    	else
+    		REPORT_ERROR("getValue for string: label " + EMDL::label2Str(element->first) + " is not of type string!");
+
+    	return true;
+    }
+}
+
+bool MetaDataContainer::valueExists(EMDLabel name)
+{
+    if (values.find(name) == values.end())
+    {
+        return false;
+    }
+    else
+    {
+        return true;
+    }
+}
+//A template exists for pairexists different from string
+bool MetaDataContainer::pairExists(EMDLabel name, const std::string &value)
+{
+    // Traverse all the structure looking for objects
+    // that satisfy search criteria
+    std::map<EMDLabel, void *>::iterator It;
+
+    It = values.find(name);
+
+    if (It != values.end())
+    {
+        if (*((std::string *) (It->second)) == value)
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+std::vector<EMDLabel> MetaDataContainer::getLabels()
+{
+	std::vector<EMDLabel> result;
+	std::map<EMDLabel, void *>::iterator It;
+	for (It = values.begin(); It != values.end(); It++)
+		result.push_back(It->first);
+
+	return result;
+}
+
+bool MetaDataContainer::writeValueToStream(std::ostream &outstream,
+        EMDLabel inputLabel)
+{
+	if (valueExists(inputLabel))
+    {
+#ifdef DEBUG_MDC
+		std::cerr << " EMDL::label2Str(inputLabel)= " << EMDL::label2Str(inputLabel) << std::endl;
+#endif
+		if (EMDL::isDouble(inputLabel))
+        {
+            double d;
+            d = *((double*) (getVoidPtr(inputLabel)));
+            if ((ABS(d) > 0. && ABS(d) < 0.001) || ABS(d) > 100000.)
+                outstream << std::setw(12) << std::scientific;
+            else
+                outstream << std::setw(12) << std::fixed;
+            outstream << d;
+#ifdef DEBUG_MDC
+            std::cerr << " d= " << d << std::endl;
+#endif
+        }
+        else if (EMDL::isString(inputLabel))
+        {
+            outstream << *((std::string*) (getVoidPtr(inputLabel)));
+#ifdef DEBUG_MDC
+            std::cerr << " *((std::string*) (getVoidPtr(inputLabel)))= " << *((std::string*) (getVoidPtr(inputLabel))) << std::endl;
+#endif
+        }
+        else if (EMDL::isInt(inputLabel))
+        {
+        	outstream << std::setw(12) << std::fixed;
+            outstream << *((int*) (getVoidPtr(inputLabel)));
+#ifdef DEBUG_MDC
+            std::cerr << " *((int*) (getVoidPtr(inputLabel)))= " << *((int*) (getVoidPtr(inputLabel))) << std::endl;
+#endif
+        }
+        else if (EMDL::isLong(inputLabel))
+        {
+        	outstream << std::setw(12) << std::fixed;
+            outstream << *((long int*) (getVoidPtr(inputLabel)));
+#ifdef DEBUG_MDC
+            std::cerr << " *((long int*) (getVoidPtr(inputLabel)))= " << *((long int*) (getVoidPtr(inputLabel))) << std::endl;
+#endif
+        }
+        else if (EMDL::isBool(inputLabel))
+        {
+        	outstream << std::setw(12) << std::fixed;
+        	outstream << *((bool*) (getVoidPtr(inputLabel)));
+#ifdef DEBUG_MDC
+        	std::cerr << " *((bool*) (getVoidPtr(inputLabel)))= " << *((bool*) (getVoidPtr(inputLabel))) << std::endl;
+#endif
+        }
+		return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+bool MetaDataContainer::writeValueToString(std::string &outString,
+        EMDLabel inLabel)
+{
+    std::ostringstream oss;
+    bool result = writeValueToStream(oss, inLabel);
+    outString = result ? oss.str() : std::string("");
+
+    return result;
+}
+
diff --git a/src/metadata_container.h b/src/metadata_container.h
new file mode 100644
index 0000000..9b2e8d0
--- /dev/null
+++ b/src/metadata_container.h
@@ -0,0 +1,174 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     J.R. Bilbao-Castro (jrbcast at ace.ual.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef METADATA_CONTAINER_H
+#define METADATA_CONTAINER_H
+
+#include <map>
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <fstream>
+#include "src/funcs.h"
+//#include "src/xmipp/strings.h"
+#include "src/metadata_label.h"
+
+//useful to init values to zero
+//static double zeroD=0.;
+//static double    oneD=1.;
+//static bool  falseb=false;
+
+class MetaDataContainer
+{
+    /** Container for attribute-value pairs.
+     * Note that void * allows to use mixed types */
+    std::map<EMDLabel, void *> values;
+
+    void insertVoidPtr(EMDLabel name, void * value);
+    void * getVoidPtr(EMDLabel name);
+    void copy(const MetaDataContainer &MDc);
+
+public:
+
+    /**Assignment operator
+     *
+     */
+    MetaDataContainer& operator =(const MetaDataContainer &MDc);
+
+    /** Constructor */
+    MetaDataContainer();
+    /** Copy constructor
+     *
+     */
+    MetaDataContainer(const MetaDataContainer &MDc);
+
+    /** Destructor */
+    ~MetaDataContainer();
+
+    /** Create a new attribute-value pair of string type */
+    void addValue(const std::string &name, const std::string &value);
+
+    /** Creates a new label-value pair, and checks the type of the label is the same as that of value */
+    void addValue(EMDLabel name, const double &value);
+    void addValue(EMDLabel name, const int &value);
+    void addValue(EMDLabel name, const long int &value);
+    void addValue(EMDLabel name, const bool &value);
+    void addValue(EMDLabel name, const std::string &value);
+
+    /** Creates a new label-value pair, with the default value for the corresponding type */
+    void addDefaultValue(EMDLabel name);
+
+    /** clean metadatacontainer
+     *
+     */
+    void clear(void)
+    {
+        // Manually delete the map of pointers!
+        for (std::map<EMDLabel, void *>::iterator it = values.begin();
+             it != values.end(); ++it)
+        {
+        	if (EMDL::isDouble(it->first))
+                delete (double*)it->second;
+            else if (EMDL::isInt(it->first))
+                delete (int*)it->second;
+            else if (EMDL::isLong(it->first))
+                delete (long int*)it->second;
+            else if (EMDL::isBool(it->first))
+                delete (bool*)it->second;
+            else if (EMDL::isString(it->first))
+                delete (std::string*)it->second;
+            else
+                REPORT_ERROR("Unrecognised label type in MetaDataContainer clear");
+        }
+    	values.clear();
+    }
+
+    /** Get a value for a given name.
+     *  If the metadata container contains the name,
+     *  the function will check the type of value with the type of the label and report an error if they do not match,
+     *  If they do match, the value will be get and the function returns true
+     *  If the name does not exist in the container, the function returns false
+     *
+     */
+    bool getValue( const EMDLabel name, double &value);
+    bool getValue( const EMDLabel name, int &value);
+    bool getValue( const EMDLabel name, long int &value);
+    bool getValue( const EMDLabel name, bool &value);
+    bool getValue( const EMDLabel name, std::string &value);
+
+    // Check whether this label is present in the container
+    bool valueExists(EMDLabel name);
+
+    //string is not part of the template because - is not defined for string
+    bool pairExists(EMDLabel name, const std::string &value);
+
+    template<class T>
+    bool pairExists(EMDLabel name, const T& value)
+    {
+        // Traverse all the structure looking for objects
+        // that satisfy search criteria
+        std::map<EMDLabel, void *>::iterator It;
+
+        It = values.find(name);
+
+        if (It != values.end())
+        {
+            if (ABS( *((T *)(It->second)) - value )
+                    < XMIPP_EQUAL_ACCURACY)
+            {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    // Get all labels in this container
+    std::vector<EMDLabel> getLabels();
+
+    bool writeValueToStream(std::ostream &outstream, EMDLabel inputLabel);
+    bool writeValueToString(std::string &outString, EMDLabel inputLabel);
+};
+
+#endif
diff --git a/src/metadata_label.cpp b/src/metadata_label.cpp
new file mode 100644
index 0000000..4f9fdc6
--- /dev/null
+++ b/src/metadata_label.cpp
@@ -0,0 +1,140 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:    J.M. De la Rosa Trevin (jmdelarosa at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+#include "src/metadata_label.h"
+
+//This is needed for static memory allocation
+std::map<EMDLabel, EMDLabelData> EMDL::data;
+std::map<std::string, EMDLabel> EMDL::names;
+std::map<std::string, std::string> EMDL::definitions;
+StaticInitialization EMDL::initialization; //Just for initialization
+
+void EMDL::addLabel(EMDLabel label, EMDLabelType type, std::string name, std::string definition)
+{
+    data[label] = EMDLabelData(type, name);
+    names[name] = label;
+    definitions[name] = definition;
+}//close function addLable
+
+void EMDL::printDefinitions(std::ostream& out)
+{
+	out << "+++ RELION MetaDataLabel (EMDL) definitions: +++" <<std::endl;
+	 std::map<std::string, std::string>::const_iterator strIt;
+	for (strIt = definitions.begin(); strIt != definitions.end(); strIt++)
+	{
+		out << std::setw(30) <<strIt->first;
+		if (EMDL::isInt(names[strIt->first]))
+			out << " (int)    ";
+		else if (EMDL::isLong(names[strIt->first]))
+			out << " (long)   ";
+		else if (EMDL::isBool(names[strIt->first]))
+			out << " (bool)   ";
+		else if (EMDL::isDouble(names[strIt->first]))
+			out << " (double) ";
+		else if (EMDL::isString(names[strIt->first]))
+			out << " (string) ";
+		else
+			REPORT_ERROR("EMDL::printDefinitions: unrecognised type");
+		out << ": " << strIt->second <<std::endl;
+	}
+}
+
+
+
+EMDLabel  EMDL::str2Label(const std::string &labelName)
+{
+	if (names.find(labelName) == names.end())
+        return EMDL_UNDEFINED;
+    return names[labelName];
+}//close function str2Label
+
+std::string  EMDL::label2Str(const EMDLabel &label)
+{
+    if (data.find(label) == data.end())
+            return "";
+    return data[label].str;
+}//close function label2Str
+
+bool EMDL::isInt(const EMDLabel &label)
+{
+    return (data[label].type == EMDL_INT);
+}
+bool EMDL::isLong(const EMDLabel &label)
+{
+    return (data[label].type == EMDL_LONG);
+}
+bool EMDL::isBool(const EMDLabel &label)
+{
+    return (data[label].type == EMDL_BOOL);
+}
+bool EMDL::isString(const EMDLabel &label)
+{
+    return (data[label].type == EMDL_STRING);
+}
+bool EMDL::isDouble(const EMDLabel &label)
+{
+    return (data[label].type == EMDL_DOUBLE);
+}
+bool EMDL::isNumber(const EMDLabel &label)
+{
+    return (data[label].type == EMDL_DOUBLE || data[label].type == EMDL_LONG || data[label].type == EMDL_INT);
+}
+
+bool EMDL::isValidLabel(const EMDLabel &label)
+{
+    return (label > EMDL_UNDEFINED && label < EMDL_LAST_LABEL);
+}
+bool EMDL::isValidLabel(const std::string &labelName)
+{
+    EMDLabel label = EMDL::str2Label(labelName);
+    return EMDL::isValidLabel(label);
+}
+
+bool vectorContainsLabel(const std::vector<EMDLabel>& labelsVector, const EMDLabel label)
+{
+    std::vector<EMDLabel>::const_iterator location;
+    location = std::find(labelsVector.begin(), labelsVector.end(), label);
+
+    return (location != labelsVector.end());
+}
+
diff --git a/src/metadata_label.h b/src/metadata_label.h
new file mode 100644
index 0000000..9f92dd3
--- /dev/null
+++ b/src/metadata_label.h
@@ -0,0 +1,644 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     J.M. De la Rosa Trevin (jmdelarosa at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef METADATA_LABEL_H
+#define METADATA_LABEL_H
+
+#include <map>
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <fstream>
+#include "src/funcs.h"
+
+class EMDLabelData;
+class StaticInitialization;
+
+enum EMDLabel
+{
+    EMDL_UNDEFINED = -1, // Keep the order the same as in StaticInitialization below!!
+    EMDL_FIRST_LABEL,
+    EMDL_OBJID = EMDL_FIRST_LABEL, ///< object id (int), NOTE: This label is special and shouldn't be used
+
+    EMDL_AREA_ID, ///< ID for the area (or field of view). If one does not use (tilt) series, area would be the same as micrograph...
+    EMDL_AREA_NAME, ///< Name for the area (or field of view). If one does not use (tilt) series, area would be the same as micrograph...
+    EMDL_COMMENT, // The EMDL_COMMENT is handled specially as well
+
+    EMDL_CTF_BFACTOR, ///< B-factor
+    EMDL_CTF_SCALEFACTOR, ///< linear scale-factor
+    EMDL_CTF_SAMPLING_RATE, ///< Sampling rate
+    EMDL_CTF_VOLTAGE, ///< Microscope voltage (kV)
+    EMDL_CTF_DEFOCUSU, ///< Defocus U (Angstroms)
+    EMDL_CTF_DEFOCUSV, ///< Defocus V (Angstroms)
+    EMDL_CTF_DEFOCUS_ANGLE, ///< Defocus angle (degrees)
+    EMDL_CTF_CS, ///< Spherical aberration
+    EMDL_CTF_CA, ///< Chromatic aberration
+    EMDL_CTF_DETECTOR_PIXEL_SIZE, ///< Pixel size for detector as used in CTF-determination
+    EMDL_CTF_ENERGY_LOSS, ///< Energy loss
+    EMDL_CTF_FOM, ///< ctffind3 FOM (CC) for quality of CTF-fit
+    EMDL_CTF_IMAGE, ///< name of an image describing the CTF model
+    EMDL_CTF_LENS_STABILITY, ///< Lens stability
+    EMDL_CTF_MAGNIFICATION, ///< Magnification used for CTF-determination
+    EMDL_CTF_CONVERGENCE_CONE, ///< Convergence cone
+    EMDL_CTF_LONGITUDINAL_DISPLACEMENT, ///< Longitudinal displacement
+    EMDL_CTF_TRANSVERSAL_DISPLACEMENT, ///< Transversal displacemente
+    EMDL_CTF_Q0, ///< Amplitude contrast
+    EMDL_CTF_K, ///< CTF gain
+    EMDL_CTF_VALUE, ///< CTF value
+
+    EMDL_IMAGE_NAME,
+    EMDL_IMAGE_RECONSTRUCT_NAME,
+    EMDL_IMAGE_ID,
+    EMDL_IMAGE_ENABLED,
+    EMDL_IMAGE_DATATYPE,
+    EMDL_IMAGE_DIMENSIONALITY,
+    EMDL_IMAGE_BEAMTILT_X,
+    EMDL_IMAGE_BEAMTILT_Y,
+    EMDL_IMAGE_BEAMTILT_GROUP,
+    EMDL_IMAGE_COORD_X,
+    EMDL_IMAGE_COORD_Y,
+    EMDL_IMAGE_COORD_Z,
+    EMDL_IMAGE_FRAME_NR,
+    EMDL_IMAGE_MAGNIFICATION_CORRECTION,
+    EMDL_IMAGE_NORM_CORRECTION,
+    EMDL_IMAGE_SAMPLINGRATE,
+    EMDL_IMAGE_SAMPLINGRATE_X,
+    EMDL_IMAGE_SAMPLINGRATE_Y,
+    EMDL_IMAGE_SAMPLINGRATE_Z,
+    EMDL_IMAGE_SIZE,
+    EMDL_IMAGE_SIZEX,
+    EMDL_IMAGE_SIZEY,
+    EMDL_IMAGE_SIZEZ,
+    EMDL_IMAGE_STATS_MIN,
+    EMDL_IMAGE_STATS_MAX,
+    EMDL_IMAGE_STATS_AVG,
+    EMDL_IMAGE_STATS_STDDEV,
+    EMDL_IMAGE_STATS_SKEW,
+    EMDL_IMAGE_STATS_KURT,
+    EMDL_IMAGE_WEIGHT,
+
+    EMDL_MATRIX_1_1,
+    EMDL_MATRIX_1_2,
+    EMDL_MATRIX_1_3,
+    EMDL_MATRIX_2_1,
+    EMDL_MATRIX_2_2,
+    EMDL_MATRIX_2_3,
+    EMDL_MATRIX_3_1,
+    EMDL_MATRIX_3_2,
+    EMDL_MATRIX_3_3,
+
+    EMDL_MICROGRAPH_ID,
+    EMDL_MICROGRAPH_NAME,
+    EMDL_MICROGRAPH_TILT_ANGLE,
+    EMDL_MICROGRAPH_TILT_AXIS_DIRECTION,
+    EMDL_MICROGRAPH_TILT_AXIS_OUTOFPLANE,
+
+    EMDL_MLMODEL_ACCURACY_ROT,
+    EMDL_MLMODEL_ACCURACY_TRANS,
+    EMDL_MLMODEL_AVE_PMAX,
+    EMDL_MLMODEL_CURRENT_RESOLUTION,
+    EMDL_MLMODEL_CURRENT_SIZE,
+    EMDL_MLMODEL_DATA_VS_PRIOR_REF,
+    EMDL_MLMODEL_DIMENSIONALITY,
+    EMDL_MLMODEL_DIMENSIONALITY_DATA,
+    EMDL_MLMODEL_DIFF2_HALVES_REF,
+    EMDL_MLMODEL_FSC_HALVES_REF,
+    EMDL_MLMODEL_GROUP_NAME,
+    EMDL_MLMODEL_GROUP_NO,
+    EMDL_MLMODEL_GROUP_NR_PARTICLES,
+    EMDL_MLMODEL_GROUP_SCALE_CORRECTION,
+    EMDL_MLMODEL_INTERPOLATOR,
+    EMDL_MLMODEL_LL,
+    EMDL_MLMODEL_MINIMUM_RADIUS_NN_INTERPOLATION,
+    EMDL_MLMODEL_NORM_CORRECTION_AVG,
+    EMDL_MLMODEL_NR_CLASSES,
+    EMDL_MLMODEL_NR_GROUPS,
+    EMDL_MLMODEL_ORIGINAL_SIZE,
+    EMDL_MLMODEL_ORIENTABILITY_CONTRIBUTION,
+    EMDL_MLMODEL_PADDING_FACTOR,
+    EMDL_MLMODEL_PDF_CLASS,
+    EMDL_MLMODEL_PRIOR_OFFX_CLASS,
+    EMDL_MLMODEL_PRIOR_OFFY_CLASS,
+    EMDL_MLMODEL_PDF_ORIENT,
+    EMDL_MLMODEL_PIXEL_SIZE,
+    EMDL_MLMODEL_POWER_REF,
+    EMDL_MLMODEL_PRIOR_MODE,
+    EMDL_MLMODEL_SIGMA_OFFSET,
+    EMDL_MLMODEL_SIGMA_ROT,
+    EMDL_MLMODEL_SIGMA_TILT,
+    EMDL_MLMODEL_SIGMA_PSI,
+    EMDL_MLMODEL_REF_IMAGE,
+    EMDL_MLMODEL_SIGMA2_NOISE,
+    EMDL_MLMODEL_SIGMA2_REF,
+    EMDL_MLMODEL_SSNR_REF,
+    EMDL_MLMODEL_TAU2_FUDGE_FACTOR,
+    EMDL_MLMODEL_TAU2_REF,
+
+    EMDL_OPTIMISER_ACCURACY_ROT,
+    EMDL_OPTIMISER_ACCURACY_TRANS,
+    EMDL_OPTIMISER_ADAPTIVE_FRACTION,
+    EMDL_OPTIMISER_ADAPTIVE_OVERSAMPLING,
+    EMDL_OPTIMISER_AUTO_LOCAL_HP_ORDER,
+    EMDL_OPTIMISER_AVAILABLE_MEMORY,
+    EMDL_OPTIMISER_BEST_RESOL_THUS_FAR,
+	EMDL_OPTIMISER_CHANGES_OPTIMAL_OFFSETS,
+	EMDL_OPTIMISER_CHANGES_OPTIMAL_ORIENTS,
+	EMDL_OPTIMISER_CHANGES_OPTIMAL_CLASSES,
+    EMDL_OPTIMISER_COARSE_SIZE,
+    EMDL_OPTIMISER_DATA_ARE_CTF_PHASE_FLIPPED,
+    EMDL_OPTIMISER_DATA_STARFILE,
+    EMDL_OPTIMISER_DO_AUTO_REFINE,
+    EMDL_OPTIMISER_DO_ONLY_FLIP_CTF_PHASES,
+    EMDL_OPTIMISER_DO_CORRECT_CTF,
+    EMDL_OPTIMISER_DO_CORRECT_MAGNIFICATION,
+    EMDL_OPTIMISER_DO_CORRECT_NORM,
+    EMDL_OPTIMISER_DO_CORRECT_SCALE,
+    EMDL_OPTIMISER_DO_REALIGN_MOVIES,
+    EMDL_OPTIMISER_DO_MAP,
+    EMDL_OPTIMISER_DO_SOLVENT_FLATTEN,
+    EMDL_OPTIMISER_DO_SKIP_ALIGN,
+    EMDL_OPTIMISER_DO_SKIP_ROTATE,
+    EMDL_OPTIMISER_DO_SPLIT_RANDOM_HALVES,
+    EMDL_OPTIMISER_DO_ZERO_MASK,
+    EMDL_OPTIMISER_FIX_SIGMA_NOISE,
+    EMDL_OPTIMISER_FIX_SIGMA_OFFSET,
+    EMDL_OPTIMISER_FIX_TAU,
+    EMDL_OPTIMISER_HAS_CONVERGED,
+    EMDL_OPTIMISER_HAS_HIGH_FSC_AT_LIMIT,
+    EMDL_OPTIMISER_HAS_LARGE_INCR_SIZE_ITER_AGO,
+    EMDL_OPTIMISER_HIGHRES_LIMIT_EXP,
+    EMDL_OPTIMISER_IGNORE_CTF_UNTIL_FIRST_PEAK,
+    EMDL_OPTIMISER_INCR_SIZE,
+    EMDL_OPTIMISER_ITERATION_NO,
+    EMDL_OPTIMISER_LOWRES_JOIN_RANDOM_HALVES,
+    EMDL_OPTIMISER_MAGNIFICATION_RANGE,
+    EMDL_OPTIMISER_MAGNIFICATION_STEP,
+    EMDL_OPTIMISER_MAX_COARSE_SIZE,
+    EMDL_OPTIMISER_MAX_NR_POOL,
+    EMDL_OPTIMISER_MODEL_STARFILE,
+    EMDL_OPTIMISER_MODEL_STARFILE2,
+    EMDL_OPTIMISER_NR_ITERATIONS,
+    EMDL_OPTIMISER_NR_ITER_WO_RESOL_GAIN,
+    EMDL_OPTIMISER_NR_ITER_WO_HIDDEN_VAR_CHANGES,
+    EMDL_OPTIMISER_OUTPUT_ROOTNAME,
+    EMDL_OPTIMISER_PARTICLE_DIAMETER,
+    EMDL_OPTIMISER_RADIUS_MASK_3D_MAP,
+    EMDL_OPTIMISER_RADIUS_MASK_EXP_PARTICLES,
+    EMDL_OPTIMISER_RANDOM_SEED,
+    EMDL_OPTIMISER_REFS_ARE_CTF_CORRECTED,
+    EMDL_OPTIMISER_SAMPLING_STARFILE,
+    EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_CLASSES,
+    EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_OFFSETS,
+    EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_ORIENTS,
+    EMDL_OPTIMISER_SOLVENT_MASK_NAME,
+    EMDL_OPTIMISER_SOLVENT_MASK2_NAME,
+    EMDL_OPTIMISER_TAU_SPECTRUM_NAME,
+    EMDL_OPTIMISER_USE_TOO_COARSE_SAMPLING,
+    EMDL_OPTIMISER_WIDTH_MASK_EDGE,
+
+    EMDL_ORIENT_FLIP,
+    EMDL_ORIENT_ID,
+    EMDL_ORIENT_ORIGIN_X,
+    EMDL_ORIENT_ORIGIN_X_PRIOR,
+    EMDL_ORIENT_ORIGIN_Y,
+    EMDL_ORIENT_ORIGIN_Y_PRIOR,
+    EMDL_ORIENT_ORIGIN_Z,
+    EMDL_ORIENT_ORIGIN_Z_PRIOR,
+    EMDL_ORIENT_ROT,
+    EMDL_ORIENT_ROT_PRIOR,
+    EMDL_ORIENT_TILT,
+    EMDL_ORIENT_TILT_PRIOR,
+    EMDL_ORIENT_PSI,
+    EMDL_ORIENT_PSI_PRIOR,
+
+    EMDL_PARTICLE_AUTOPICK_FOM,
+    EMDL_PARTICLE_CLASS,
+    EMDL_PARTICLE_DLL,
+    EMDL_PARTICLE_ID,
+    EMDL_PARTICLE_FOM,
+    EMDL_PARTICLE_KL_DIVERGENCE,
+    EMDL_PARTICLE_RANDOM_SUBSET,
+    EMDL_PARTICLE_NAME,
+    EMDL_PARTICLE_ORI_NAME,
+    EMDL_PARTICLE_NR_SIGNIFICANT_SAMPLES,
+    EMDL_PARTICLE_NR_FRAMES,
+    EMDL_PARTICLE_PMAX,
+
+    EMDL_POSTPROCESS_BFACTOR,
+    EMDL_POSTPROCESS_FINAL_RESOLUTION,
+    EMDL_POSTPROCESS_FSC_TRUE,
+    EMDL_POSTPROCESS_FSC_MASKED,
+    EMDL_POSTPROCESS_FSC_UNMASKED,
+    EMDL_POSTPROCESS_FSC_RANDOM_MASKED,
+    EMDL_POSTPROCESS_GUINIER_FIT_CORRELATION,
+    EMDL_POSTPROCESS_GUINIER_FIT_INTERCEPT,
+    EMDL_POSTPROCESS_GUINIER_FIT_SLOPE,
+    EMDL_POSTPROCESS_GUINIER_VALUE_IN,
+    EMDL_POSTPROCESS_GUINIER_VALUE_INVMTF,
+    EMDL_POSTPROCESS_GUINIER_VALUE_WEIGHTED,
+    EMDL_POSTPROCESS_GUINIER_VALUE_SHARPENED,
+    EMDL_POSTPROCESS_GUINIER_VALUE_INTERCEPT,
+    EMDL_POSTPROCESS_GUINIER_RESOL_SQUARED,
+    EMDL_POSTPROCESS_MTF_VALUE, ///< Detector MTF value
+
+    EMDL_SAMPLING_IS_3D,
+    EMDL_SAMPLING_IS_3D_TRANS,
+    EMDL_SAMPLING_HEALPIX_ORDER,
+    EMDL_SAMPLING_LIMIT_TILT,
+    EMDL_SAMPLING_OFFSET_RANGE,
+    EMDL_SAMPLING_OFFSET_STEP,
+    EMDL_SAMPLING_PERTURB,
+    EMDL_SAMPLING_PERTURBATION_FACTOR,
+    EMDL_SAMPLING_PRIOR_MODE,
+    EMDL_SAMPLING_PSI_STEP,
+    EMDL_SAMPLING_SIGMA_ROT,
+    EMDL_SAMPLING_SIGMA_TILT,
+    EMDL_SAMPLING_SIGMA_PSI,
+    EMDL_SAMPLING_SYMMETRY,
+
+    EMDL_SELECTED,
+    EMDL_SELECT_PARTICLES_ZSCORE,
+    EMDL_SORTED_IDX,
+    EMDL_PERFRAME_CUMULATIVE_WEIGHT,
+    EMDL_PERFRAME_RELATIVE_WEIGHT,
+
+    EMDL_RESOLUTION,
+    EMDL_RESOLUTION_ANGSTROM,
+    EMDL_RESOLUTION_INVPIXEL,
+    EMDL_SPECTRAL_IDX,
+
+    EMDL_LAST_LABEL                       // **** NOTE ****: Do keep this label always at the end
+    // it is here for looping purposes
+};//close enum Label
+
+enum EMDLabelType
+{
+    EMDL_INT, EMDL_LONG, EMDL_BOOL, EMDL_DOUBLE, EMDL_FLOAT, EMDL_STRING
+};
+
+class EMDL
+{
+public:
+    // This enum defines what MetaDataLabels this class can manage, if
+    // you need a new one add it here and modify affected methods:
+    //
+    //  - static EMDLabel codifyLabel( std::string strLabel );        EMDL::addLabel(EMDL_OPTIMISER_RANDOM_SEED, EMDL_INT, "randomSeed");
+
+    // - static std::string EMDL::label2Str( EMDLabel inputLabel );
+    // - void writeValuesToFile( std::ofstream &outfile, EMDLabel inputLabel );
+    // - void addValue( std::string name, std::string value );
+    //
+    // Keep this special structure (using EMDL_FIRSTLABEL and EMDL_LAST_LABEL) so the
+    // programmer can iterate through it like this:
+    //
+    //  for( EMDLabel mdl = EMDL_FIRST_LABEL ; mdl < EMDL_LAST_LABEL ; EMDLabel( mdl+1 ) )
+    //
+
+static EMDLabel str2Label(const std::string &labelName);
+static std::string label2Str(const EMDLabel &label);
+
+static bool isInt(const EMDLabel &label);
+static bool isLong(const EMDLabel &label);
+static bool isBool(const EMDLabel &label);
+static bool isString(const EMDLabel &label);
+static bool isDouble(const EMDLabel &label);
+static bool isNumber(const EMDLabel &label);
+static bool isValidLabel(const EMDLabel &label);
+static bool isValidLabel(const std::string &labelName);
+
+static void printDefinitions(std::ostream& out);
+
+private:
+    static std::map<EMDLabel, EMDLabelData> data;
+    static std::map<std::string, EMDLabel> names;
+    static std::map<std::string, std::string> definitions;
+    static StaticInitialization initialization; //Just for initialization
+
+    static void addLabel(EMDLabel label, EMDLabelType type, std::string name, std::string definition = "undocumented");
+
+    friend class StaticInitialization;
+}
+;//close class MLD definition
+
+//Just an struct to store type and string alias
+class EMDLabelData
+{
+public:
+    EMDLabelType type;
+    std::string str;
+    //Default constructor
+    EMDLabelData()
+    {
+    }
+    EMDLabelData(EMDLabelType t, std::string s)
+    {
+        type = t;
+        str = s;
+    }
+};//close class EMDLabelData c
+
+//Just a class for static initialization
+class StaticInitialization
+{
+private:
+    StaticInitialization()
+    {
+        ///==== Add labels entries from here in the SAME ORDER as declared in ENUM ==========
+    	EMDL::addLabel(EMDL_COMMENT, EMDL_STRING, "rlnComment", "A metadata comment (This is treated in a special way)");
+
+        EMDL::addLabel(EMDL_AREA_ID, EMDL_LONG, "rlnAreaId", "ID (i.e. a unique number) of an area (i.e. field-of-view)");
+        EMDL::addLabel(EMDL_AREA_NAME, EMDL_STRING, "rlnAreaName", "Name of an area (i.e. field-of-view)");
+
+    	EMDL::addLabel(EMDL_CTF_BFACTOR, EMDL_DOUBLE, "rlnBfactor", "B-factor (in A^2) that describes power spectrum fall-off");
+    	EMDL::addLabel(EMDL_CTF_SCALEFACTOR, EMDL_DOUBLE, "rlnCtfScalefactor", "Linear scale-factor on the CTF (values between 0 and 1)");
+        EMDL::addLabel(EMDL_CTF_VOLTAGE, EMDL_DOUBLE, "rlnVoltage", "Voltage of the microscope (in kV)");
+        EMDL::addLabel(EMDL_CTF_DEFOCUSU, EMDL_DOUBLE, "rlnDefocusU", "Defocus in U-direction (in Angstroms, positive values for underfocus)");
+        EMDL::addLabel(EMDL_CTF_DEFOCUSV, EMDL_DOUBLE, "rlnDefocusV", "Defocus in V-direction (in Angstroms, positive values for underfocus)");
+        EMDL::addLabel(EMDL_CTF_DEFOCUS_ANGLE, EMDL_DOUBLE, "rlnDefocusAngle", "Angle between X and defocus U direction (in degrees)");
+        EMDL::addLabel(EMDL_CTF_CS, EMDL_DOUBLE, "rlnSphericalAberration", "Spherical aberration (in millimeters)");
+        EMDL::addLabel(EMDL_CTF_CA, EMDL_DOUBLE, "rlnChromaticAberration", "Chromatic aberration (in millimeters)");
+        EMDL::addLabel(EMDL_CTF_DETECTOR_PIXEL_SIZE, EMDL_DOUBLE, "rlnDetectorPixelSize", "Pixel size of the detector (in micrometers)");
+        EMDL::addLabel(EMDL_CTF_ENERGY_LOSS, EMDL_DOUBLE, "rlnEnergyLoss", "Energy loss (in eV)");
+        EMDL::addLabel(EMDL_CTF_FOM, EMDL_DOUBLE, "rlnCtfFigureOfMerit", "Figure of merit for the fit of the CTF (not used inside relion_refine)");
+        EMDL::addLabel(EMDL_CTF_IMAGE, EMDL_STRING, "rlnCtfImage", "Name of an image with all CTF values");
+        EMDL::addLabel(EMDL_CTF_LENS_STABILITY, EMDL_DOUBLE, "rlnLensStability", "Lens stability (in ppm)");
+        EMDL::addLabel(EMDL_CTF_MAGNIFICATION, EMDL_DOUBLE, "rlnMagnification", "Magnification at the detector (in times)");
+        EMDL::addLabel(EMDL_CTF_CONVERGENCE_CONE, EMDL_DOUBLE, "rlnConvergenceCone", "Convergence cone (in mrad)");
+        EMDL::addLabel(EMDL_CTF_LONGITUDINAL_DISPLACEMENT, EMDL_DOUBLE, "rlnLongitudinalDisplacement", "Longitudinal displacement (in Angstroms)");
+        EMDL::addLabel(EMDL_CTF_TRANSVERSAL_DISPLACEMENT, EMDL_DOUBLE, "rlnTransversalDisplacement", "Transversal displacement (in Angstroms)");
+        EMDL::addLabel(EMDL_CTF_Q0, EMDL_DOUBLE, "rlnAmplitudeContrast", "Amplitude contrast (as a fraction, i.e. 10% = 0.1)");
+        EMDL::addLabel(EMDL_CTF_VALUE, EMDL_DOUBLE, "rlnCtfValue", "Value of the Contrast Transfer Function");
+
+    	EMDL::addLabel(EMDL_IMAGE_NAME, EMDL_STRING, "rlnImageName", "Name of an image");
+    	EMDL::addLabel(EMDL_IMAGE_RECONSTRUCT_NAME, EMDL_STRING, "rlnReconstructImageName", "Name of an image to be used for reconstruction only");
+    	EMDL::addLabel(EMDL_IMAGE_ID, EMDL_LONG, "rlnImageId", "ID (i.e. a unique number) of an image");
+    	EMDL::addLabel(EMDL_IMAGE_ENABLED, EMDL_BOOL, "rlnEnabled", "Not used in RELION, only included for backward compatibility with XMIPP selfiles");
+        EMDL::addLabel(EMDL_IMAGE_DATATYPE, EMDL_INT, "rlnDataType", "Type of data stored in an image (e.g. int, double etc)");
+        EMDL::addLabel(EMDL_IMAGE_DIMENSIONALITY, EMDL_INT, "rlnDataDimensionality", "Dimensionality of data stored in an image (i.e. 2 or 3)");
+        EMDL::addLabel(EMDL_IMAGE_BEAMTILT_X, EMDL_DOUBLE, "rlnBeamTiltX", "Beam tilt in the X-direction (in mrad)");
+        EMDL::addLabel(EMDL_IMAGE_BEAMTILT_Y, EMDL_DOUBLE, "rlnBeamTiltY", "Beam tilt in the Y-direction (in mrad)");
+        EMDL::addLabel(EMDL_IMAGE_BEAMTILT_GROUP, EMDL_STRING, "rlnBeamTiltGroupName", "Name of a group (of images) with assumedly identical beam-tilts");
+        EMDL::addLabel(EMDL_IMAGE_COORD_X, EMDL_DOUBLE, "rlnCoordinateX", "X-Position of an image in a micrograph (in pixels)");
+        EMDL::addLabel(EMDL_IMAGE_COORD_Y, EMDL_DOUBLE, "rlnCoordinateY", "Y-Position of an image in a micrograph (in pixels)");
+        EMDL::addLabel(EMDL_IMAGE_COORD_Z, EMDL_DOUBLE, "rlnCoordinateZ", "Z-Position of an image in a 3D micrograph, i.e. tomogram (in pixels)");
+        EMDL::addLabel(EMDL_IMAGE_FRAME_NR, EMDL_INT, "rlnMovieFrameNumber", "Number of a movie frame");
+        EMDL::addLabel(EMDL_IMAGE_NORM_CORRECTION, EMDL_DOUBLE, "rlnNormCorrection", "Normalisation correction value for an image");
+        EMDL::addLabel(EMDL_IMAGE_MAGNIFICATION_CORRECTION, EMDL_DOUBLE, "rlnMagnificationCorrection", "Magnification correction value for an image");
+        EMDL::addLabel(EMDL_IMAGE_SAMPLINGRATE, EMDL_DOUBLE, "rlnSamplingRate", "Sampling rate of an image (in Angstrom/pixel)");
+        EMDL::addLabel(EMDL_IMAGE_SAMPLINGRATE_X, EMDL_DOUBLE, "rlnSamplingRateX", "Sampling rate in X-direction of an image (in Angstrom/pixel)");
+        EMDL::addLabel(EMDL_IMAGE_SAMPLINGRATE_Y, EMDL_DOUBLE, "rlnSamplingRateY", "Sampling rate in Y-direction of an image (in Angstrom/pixel)");
+        EMDL::addLabel(EMDL_IMAGE_SAMPLINGRATE_Z, EMDL_DOUBLE, "rlnSamplingRateZ", "Sampling rate in Z-direction of an image (in Angstrom/pixel)");
+        EMDL::addLabel(EMDL_IMAGE_SIZE, EMDL_INT, "rlnImageSize", "Size of an image (in pixels)");
+        EMDL::addLabel(EMDL_IMAGE_SIZEX, EMDL_INT, "rlnImageSizeX", "Size of an image in the X-direction (in pixels)");
+        EMDL::addLabel(EMDL_IMAGE_SIZEY, EMDL_INT, "rlnImageSizeY", "Size of an image in the Y-direction (in pixels)");
+        EMDL::addLabel(EMDL_IMAGE_SIZEZ, EMDL_INT, "rlnImageSizeZ", "Size of an image in the Z-direction (in pixels)");
+        EMDL::addLabel(EMDL_IMAGE_STATS_MIN, EMDL_DOUBLE, "rlnMinimumValue", "Minimum value for the pixels in an image");
+        EMDL::addLabel(EMDL_IMAGE_STATS_MAX, EMDL_DOUBLE, "rlnMaximumValue", "Maximum value for the pixels in an image");
+        EMDL::addLabel(EMDL_IMAGE_STATS_AVG, EMDL_DOUBLE, "rlnAverageValue", "Average value for the pixels in an image");
+        EMDL::addLabel(EMDL_IMAGE_STATS_STDDEV, EMDL_DOUBLE, "rlnStandardDeviationValue", "Standard deviation for the pixel values in an image");
+        EMDL::addLabel(EMDL_IMAGE_STATS_SKEW, EMDL_DOUBLE, "rlnSkewnessValue", "Skewness (3rd moment) for the pixel values in an image");
+        EMDL::addLabel(EMDL_IMAGE_STATS_KURT, EMDL_DOUBLE, "rlnKurtosisExcessValue", "Kurtosis excess (4th moment - 3) for the pixel values in an image");
+        EMDL::addLabel(EMDL_IMAGE_WEIGHT, EMDL_DOUBLE, "rlnImageWeight", "Relative weight of an image");
+
+        EMDL::addLabel(EMDL_MATRIX_1_1, EMDL_DOUBLE, "rlnMatrix_1_1", "Matrix element (1,1) of a 3x3 matrix");
+        EMDL::addLabel(EMDL_MATRIX_1_2, EMDL_DOUBLE, "rlnMatrix_1_2", "Matrix element (1,2) of a 3x3 matrix");
+        EMDL::addLabel(EMDL_MATRIX_1_3, EMDL_DOUBLE, "rlnMatrix_1_3", "Matrix element (1,3) of a 3x3 matrix");
+        EMDL::addLabel(EMDL_MATRIX_2_1, EMDL_DOUBLE, "rlnMatrix_2_1", "Matrix element (2,1) of a 3x3 matrix");
+        EMDL::addLabel(EMDL_MATRIX_2_2, EMDL_DOUBLE, "rlnMatrix_2_2", "Matrix element (2,1) of a 3x3 matrix");
+        EMDL::addLabel(EMDL_MATRIX_2_3, EMDL_DOUBLE, "rlnMatrix_2_3", "Matrix element (2,1) of a 3x3 matrix");
+        EMDL::addLabel(EMDL_MATRIX_3_1, EMDL_DOUBLE, "rlnMatrix_3_1", "Matrix element (3,1) of a 3x3 matrix");
+        EMDL::addLabel(EMDL_MATRIX_3_2, EMDL_DOUBLE, "rlnMatrix_3_2", "Matrix element (3,1) of a 3x3 matrix");
+        EMDL::addLabel(EMDL_MATRIX_3_3, EMDL_DOUBLE, "rlnMatrix_3_3", "Matrix element (3,1) of a 3x3 matrix");
+
+        EMDL::addLabel(EMDL_MICROGRAPH_ID, EMDL_LONG, "rlnMicrographId", "ID (i.e. a unique number) of a micrograph");
+        EMDL::addLabel(EMDL_MICROGRAPH_NAME, EMDL_STRING, "rlnMicrographName", "Name of a micrograph");
+        EMDL::addLabel(EMDL_MICROGRAPH_TILT_ANGLE, EMDL_DOUBLE, "rlnMicrographTiltAngle", "Tilt angle (in degrees) used to collect a micrograph");
+        EMDL::addLabel(EMDL_MICROGRAPH_TILT_AXIS_DIRECTION, EMDL_DOUBLE, "rlnMicrographTiltAxisDirection", "Direction of the tilt-axis (in degrees) used to collect a micrograph");
+        EMDL::addLabel(EMDL_MICROGRAPH_TILT_AXIS_OUTOFPLANE, EMDL_DOUBLE, "rlnMicrographTiltAxisOutOfPlane", "Out-of-plane angle (in degrees) of the tilt-axis used to collect a micrograph (90=in-plane)");
+
+        EMDL::addLabel(EMDL_MLMODEL_ACCURACY_ROT, EMDL_DOUBLE, "rlnAccuracyRotations", "Estimated accuracy (in degrees) with which rotations can be assigned");
+        EMDL::addLabel(EMDL_MLMODEL_ACCURACY_TRANS, EMDL_DOUBLE, "rlnAccuracyTranslations", "Estimated accuracy (in pixels) with which translations can be assigned");
+        EMDL::addLabel(EMDL_MLMODEL_AVE_PMAX, EMDL_DOUBLE, "rlnAveragePmax", "Average value (over all images) of the maxima of the probability distributions");
+        EMDL::addLabel(EMDL_MLMODEL_CURRENT_RESOLUTION, EMDL_DOUBLE, "rlnCurrentResolution", "Current resolution where SSNR^MAP drops below 1 (in 1/Angstroms)");
+        EMDL::addLabel(EMDL_MLMODEL_CURRENT_SIZE, EMDL_INT, "rlnCurrentImageSize", "Current size of the images used in the refinement");
+        EMDL::addLabel(EMDL_MLMODEL_DATA_VS_PRIOR_REF, EMDL_DOUBLE, "rlnSsnrMap", "Spectral signal-to-noise ratio as defined for MAP estimation (SSNR^MAP)");
+        EMDL::addLabel(EMDL_MLMODEL_DIMENSIONALITY, EMDL_INT, "rlnReferenceDimensionality", "Dimensionality of the references (2D/3D)");
+        EMDL::addLabel(EMDL_MLMODEL_DIMENSIONALITY_DATA, EMDL_INT, "rlnDataDimensionality", "Dimensionality of the data (2D/3D)");
+        EMDL::addLabel(EMDL_MLMODEL_DIFF2_HALVES_REF, EMDL_DOUBLE, "rlnDiff2RandomHalves", "Power of the differences between two independent reconstructions from random halves of the data");
+        EMDL::addLabel(EMDL_MLMODEL_FSC_HALVES_REF, EMDL_DOUBLE, "rlnGoldStandardFsc", "Fourier shell correlation between two independent reconstructions from random halves of the data");
+        EMDL::addLabel(EMDL_MLMODEL_GROUP_NAME, EMDL_STRING, "rlnGroupName", "The name of a group of images (e.g. all images from a micrograph)");
+        EMDL::addLabel(EMDL_MLMODEL_GROUP_NO, EMDL_LONG, "rlnGroupNumber", "The number of a group of images");
+        EMDL::addLabel(EMDL_MLMODEL_GROUP_NR_PARTICLES, EMDL_LONG, "rlnGroupNrParticles", "Number particles in a group of images");
+        EMDL::addLabel(EMDL_MLMODEL_GROUP_SCALE_CORRECTION, EMDL_DOUBLE, "rlnGroupScaleCorrection", "Intensity-scale correction for a group of images");
+        EMDL::addLabel(EMDL_MLMODEL_INTERPOLATOR, EMDL_INT, "rlnFourierSpaceInterpolator", "The kernel used for Fourier-space interpolation (NN=0, linear=1)");
+        EMDL::addLabel(EMDL_MLMODEL_LL, EMDL_DOUBLE, "rlnLogLikelihood", "Value of the log-likelihood target function");
+        EMDL::addLabel(EMDL_MLMODEL_MINIMUM_RADIUS_NN_INTERPOLATION,  EMDL_INT, "rlnMinRadiusNnInterpolation","Minimum radius for NN-interpolation (in Fourier pixels), for smaller radii linear int. is used");
+        EMDL::addLabel(EMDL_MLMODEL_NORM_CORRECTION_AVG, EMDL_DOUBLE, "rlnNormCorrectionAverage", "Average value (over all images) of the normalisation correction values");
+        EMDL::addLabel(EMDL_MLMODEL_NR_CLASSES, EMDL_INT, "rlnNrClasses", "The number of references (i.e. classes) to be used in refinement");
+        EMDL::addLabel(EMDL_MLMODEL_NR_GROUPS, EMDL_INT, "rlnNrGroups", "The number of different groups of images (each group has its own noise spectrum, and intensity-scale correction)");
+        EMDL::addLabel(EMDL_MLMODEL_ORIENTABILITY_CONTRIBUTION, EMDL_DOUBLE, "rlnSpectralOrientabilityContribution", "Spectral SNR contribution to the orientability of individual particles");
+        EMDL::addLabel(EMDL_MLMODEL_ORIGINAL_SIZE, EMDL_INT, "rlnOriginalImageSize", "Original size of the images (in pixels)");
+        EMDL::addLabel(EMDL_MLMODEL_PADDING_FACTOR, EMDL_INT, "rlnPaddingFactor", "Oversampling factor for Fourier transforms of the references");
+        EMDL::addLabel(EMDL_MLMODEL_PDF_CLASS, EMDL_DOUBLE, "rlnClassDistribution", "Probability Density Function of the different classes (i.e. fraction of images assigned to each class)");
+        EMDL::addLabel(EMDL_MLMODEL_PRIOR_OFFX_CLASS, EMDL_DOUBLE, "rlnClassPriorOffsetX", "Prior in the X-offset for a class (in pixels)");
+        EMDL::addLabel(EMDL_MLMODEL_PRIOR_OFFY_CLASS, EMDL_DOUBLE, "rlnClassPriorOffsetY", "Prior in the Y-offset for a class (in pixels)");
+        EMDL::addLabel(EMDL_MLMODEL_PDF_ORIENT, EMDL_DOUBLE, "rlnOrientationDistribution", "Probability Density Function of the orientations  (i.e. fraction of images assigned to each orient)");
+        EMDL::addLabel(EMDL_MLMODEL_PIXEL_SIZE, EMDL_DOUBLE, "rlnPixelSize", "Size of the pixels in the references and images (in Angstroms)");
+        EMDL::addLabel(EMDL_MLMODEL_POWER_REF, EMDL_DOUBLE, "rlnReferenceSpectralPower", "Spherical average of the power of the reference");
+        EMDL::addLabel(EMDL_MLMODEL_PRIOR_MODE, EMDL_INT, "rlnOrientationalPriorMode", "Mode for prior distributions on the orientations (0=no prior; 1=(rot,tilt,psi); 2=(rot,tilt); 3=rot; 4=tilt; 5=psi) ");
+        EMDL::addLabel(EMDL_MLMODEL_REF_IMAGE, EMDL_STRING, "rlnReferenceImage", "Name of a reference image");
+        EMDL::addLabel(EMDL_MLMODEL_SIGMA_OFFSET, EMDL_DOUBLE, "rlnSigmaOffsets","Standard deviation in the origin offsets (in Angstroms)");
+        EMDL::addLabel(EMDL_MLMODEL_SIGMA2_NOISE, EMDL_DOUBLE, "rlnSigma2Noise", "Spherical average of the standard deviation in the noise (sigma)");
+        EMDL::addLabel(EMDL_MLMODEL_SIGMA2_REF, EMDL_DOUBLE, "rlnReferenceSigma2", "Spherical average of the estimated power in the noise of a reference");
+        EMDL::addLabel(EMDL_MLMODEL_SIGMA_ROT, EMDL_DOUBLE, "rlnSigmaPriorRotAngle", "Standard deviation of the prior on the rot (i.e. first Euler) angle");
+        EMDL::addLabel(EMDL_MLMODEL_SIGMA_TILT, EMDL_DOUBLE, "rlnSigmaPriorTiltAngle", "Standard deviation of the prior on the tilt (i.e. second Euler) angle");
+        EMDL::addLabel(EMDL_MLMODEL_SIGMA_PSI, EMDL_DOUBLE, "rlnSigmaPriorPsiAngle", "Standard deviation of the prior on the psi (i.e. third Euler) angle");
+        EMDL::addLabel(EMDL_MLMODEL_SSNR_REF, EMDL_DOUBLE, "rlnSignalToNoiseRatio", "Spectral signal-to-noise ratio for a reference");
+        EMDL::addLabel(EMDL_MLMODEL_TAU2_FUDGE_FACTOR, EMDL_DOUBLE, "rlnTau2FudgeFactor", "Regularisation parameter with which estimates for the power in the references will be multiplied (T in original paper)");
+        EMDL::addLabel(EMDL_MLMODEL_TAU2_REF, EMDL_DOUBLE, "rlnReferenceTau2", "Spherical average of the estimated power in the signal of a reference");
+
+        EMDL::addLabel(EMDL_OPTIMISER_ACCURACY_ROT, EMDL_DOUBLE, "rlnOverallAccuracyRotations", "Overall accuracy of the rotational assignments (in degrees)");
+        EMDL::addLabel(EMDL_OPTIMISER_ACCURACY_TRANS, EMDL_DOUBLE, "rlnOverallAccuracyTranslations", "Overall accuracy of the translational assignments (in pixels)");
+        EMDL::addLabel(EMDL_OPTIMISER_ADAPTIVE_FRACTION, EMDL_DOUBLE, "rlnAdaptiveOversampleFraction", "Fraction of the weights that will be oversampled in a second pass of the adaptive oversampling strategy");
+		EMDL::addLabel(EMDL_OPTIMISER_ADAPTIVE_OVERSAMPLING, EMDL_INT, "rlnAdaptiveOversampleOrder", "Order of the adaptive oversampling (0=no oversampling, 1= 2x oversampling; 2= 4x oversampling, etc)");
+		EMDL::addLabel(EMDL_OPTIMISER_AUTO_LOCAL_HP_ORDER, EMDL_INT, "rlnAutoLocalSearchesHealpixOrder", "Healpix order (before oversampling) from which autosampling procedure will use local angular searches");
+		EMDL::addLabel(EMDL_OPTIMISER_AVAILABLE_MEMORY, EMDL_DOUBLE, "rlnAvailableMemory", "Available memory per computing node (i.e. per MPI-process)");
+        EMDL::addLabel(EMDL_OPTIMISER_BEST_RESOL_THUS_FAR, EMDL_DOUBLE, "rlnBestResolutionThusFar", "The highest resolution that has been obtained in this optimization thus far");
+        EMDL::addLabel(EMDL_OPTIMISER_COARSE_SIZE, EMDL_INT, "rlnCoarseImageSize", "Current size of the images to be used in the first pass of the adaptive oversampling strategy (may be smaller than the original image size)");
+        EMDL::addLabel(EMDL_OPTIMISER_CHANGES_OPTIMAL_OFFSETS, EMDL_DOUBLE, "rlnChangesOptimalOffsets", "The average change in optimal translation in the last iteration (in pixels) ");
+        EMDL::addLabel(EMDL_OPTIMISER_CHANGES_OPTIMAL_ORIENTS, EMDL_DOUBLE, "rlnChangesOptimalOrientations", "The average change in optimal orientation in the last iteration (in degrees) ");
+        EMDL::addLabel(EMDL_OPTIMISER_CHANGES_OPTIMAL_CLASSES, EMDL_DOUBLE, "rlnChangesOptimalClasses", "The number of particles that changed their optimal clsas assignment in the last iteration");
+        EMDL::addLabel(EMDL_OPTIMISER_DATA_ARE_CTF_PHASE_FLIPPED, EMDL_BOOL, "rlnCtfDataArePhaseFlipped", "Flag to indicate that the input images have been phase-flipped");
+        EMDL::addLabel(EMDL_OPTIMISER_DATA_STARFILE, EMDL_STRING, "rlnExperimentalDataStarFile", "STAR file with metadata for the experimental images");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_CORRECT_CTF, EMDL_BOOL, "rlnDoCorrectCtf", "Flag to indicate that CTF-correction should be performed");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_CORRECT_MAGNIFICATION, EMDL_BOOL, "rlnDoCorrectMagnification", "Flag to indicate that (per-group) magnification correction should be performed");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_CORRECT_NORM, EMDL_BOOL, "rlnDoCorrectNorm", "Flag to indicate that (per-image) normalisation-error correction should be performed");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_CORRECT_SCALE, EMDL_BOOL, "rlnDoCorrectScale", "Flag to indicate that internal (per-group) intensity-scale correction should be performed");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_REALIGN_MOVIES, EMDL_BOOL, "rlnDoRealignMovies", "Flag to indicate that individual frames of movies are being re-aligned");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_MAP, EMDL_BOOL, "rlnDoMapEstimation", "Flag to indicate that MAP estimation should be performed (otherwise ML estimation)");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_AUTO_REFINE, EMDL_BOOL, "rlnDoAutoRefine", "Flag to indicate that 3D auto-refine procedure is being used");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_ONLY_FLIP_CTF_PHASES, EMDL_BOOL, "rlnDoOnlyFlipCtfPhases", "Flag to indicate that CTF-correction should only comprise phase-flipping");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_SOLVENT_FLATTEN, EMDL_BOOL, "rlnDoSolventFlattening", "Flag to indicate that the references should be masked to set their solvent areas to a constant density");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_SKIP_ALIGN, EMDL_BOOL, "rlnDoSkipAlign", "Flag to indicate that orientational (i.e. rotational and translational) searches will be omitted from the refinement, only marginalisation over classes will take place");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_SKIP_ROTATE, EMDL_BOOL, "rlnDoSkipRotate", "Flag to indicate that rotational searches will be omitted from the refinement, only marginalisation over classes and translations will take place");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_SPLIT_RANDOM_HALVES, EMDL_BOOL, "rlnDoSplitRandomHalves", "Flag to indicate that the data should be split into two completely separate, random halves");
+        EMDL::addLabel(EMDL_OPTIMISER_DO_ZERO_MASK, EMDL_BOOL, "rlnDoZeroMask", "Flag to indicate that the surrounding solvent area in the experimental particles will be masked to zeros (by default random noise will be used");
+        EMDL::addLabel(EMDL_OPTIMISER_FIX_SIGMA_NOISE, EMDL_BOOL, "rlnFixSigmaNoiseEstimates", "Flag to indicate that the estimates for the power spectra of the noise should be kept constant");
+        EMDL::addLabel(EMDL_OPTIMISER_FIX_SIGMA_OFFSET ,EMDL_BOOL, "rlnFixSigmaOffsetEstimates", "Flag to indicate that the estimates for the stddev in the origin offsets should be kept constant");
+        EMDL::addLabel(EMDL_OPTIMISER_FIX_TAU, EMDL_BOOL, "rlnFixTauEstimates", "Flag to indicate that the estimates for the power spectra of the signal (i.e. the references) should be kept constant");
+        EMDL::addLabel(EMDL_OPTIMISER_HAS_CONVERGED, EMDL_BOOL, "rlnHasConverged", "Flag to indicate that the optimization has converged");
+        EMDL::addLabel(EMDL_OPTIMISER_HAS_HIGH_FSC_AT_LIMIT, EMDL_BOOL, "rlnHasHighFscAtResolLimit", "Flag to indicate that the FSC at the resolution limit is significant");
+        EMDL::addLabel(EMDL_OPTIMISER_HAS_LARGE_INCR_SIZE_ITER_AGO, EMDL_INT, "rlnHasLargeSizeIncreaseIterationsAgo", "How many iterations have passed since the last large increase in image size");
+        EMDL::addLabel(EMDL_OPTIMISER_HIGHRES_LIMIT_EXP, EMDL_DOUBLE, "rlnHighresLimitExpectation", "High-resolution-limit (in Angstrom) for the expectation step");
+        EMDL::addLabel(EMDL_OPTIMISER_IGNORE_CTF_UNTIL_FIRST_PEAK, EMDL_BOOL, "rlnDoIgnoreCtfUntilFirstPeak", "Flag to indicate that the CTFs should be ignored until their first peak");
+        EMDL::addLabel(EMDL_OPTIMISER_INCR_SIZE, EMDL_INT, "rlnIncrementImageSize", "Number of Fourier shells to be included beyond the resolution where SSNR^MAP drops below 1");
+        EMDL::addLabel(EMDL_OPTIMISER_ITERATION_NO, EMDL_INT, "rlnCurrentIteration", "The number of the current iteration");
+        EMDL::addLabel(EMDL_OPTIMISER_LOWRES_JOIN_RANDOM_HALVES, EMDL_DOUBLE, "rlnJoinHalvesUntilThisResolution", "Resolution (in Angstrom) to join the two random half-reconstructions to prevent their diverging orientations (for C-symmetries)");
+        EMDL::addLabel(EMDL_OPTIMISER_MAGNIFICATION_RANGE, EMDL_DOUBLE, "rlnMagnificationSearchRange", "Search range for magnification correction");
+        EMDL::addLabel(EMDL_OPTIMISER_MAGNIFICATION_STEP, EMDL_DOUBLE, "rlnMagnificationSearchStep", "Step size  for magnification correction");
+        EMDL::addLabel(EMDL_OPTIMISER_MAX_COARSE_SIZE, EMDL_INT, "rlnMaximumCoarseImageSize", "Maximum size of the images to be used in the first pass of the adaptive oversampling strategy (may be smaller than the original image size)");
+        EMDL::addLabel(EMDL_OPTIMISER_MAX_NR_POOL, EMDL_INT, "rlnMaxNumberOfPooledParticles", "Maximum number particles that are processed together to speed up calculations");
+        EMDL::addLabel(EMDL_OPTIMISER_MODEL_STARFILE, EMDL_STRING, "rlnModelStarFile", "STAR file with metadata for the model that is being refined");
+        EMDL::addLabel(EMDL_OPTIMISER_MODEL_STARFILE2, EMDL_STRING, "rlnModelStarFile2", "STAR file with metadata for the second model that is being refined (from random halves of the data)");
+        EMDL::addLabel(EMDL_OPTIMISER_NR_ITERATIONS, EMDL_INT, "rlnNumberOfIterations", "Maximum number of iterations to be performed");
+        EMDL::addLabel(EMDL_OPTIMISER_NR_ITER_WO_RESOL_GAIN, EMDL_INT, "rlnNumberOfIterWithoutResolutionGain", "Number of iterations that have passed without a gain in resolution");
+        EMDL::addLabel(EMDL_OPTIMISER_NR_ITER_WO_HIDDEN_VAR_CHANGES, EMDL_INT, "rlnNumberOfIterWithoutChangingAssignments", "Number of iterations that have passed without large changes in orientation and class assignments");
+        EMDL::addLabel(EMDL_OPTIMISER_OUTPUT_ROOTNAME, EMDL_STRING, "rlnOutputRootName", "Rootname for all output files (this may include a directory structure, which should then exist)");
+        EMDL::addLabel(EMDL_OPTIMISER_PARTICLE_DIAMETER, EMDL_DOUBLE, "rlnParticleDiameter", "Diameter of the circular mask to be applied to all experimental images (in Angstroms)");
+        EMDL::addLabel(EMDL_OPTIMISER_RADIUS_MASK_3D_MAP, EMDL_INT, "rlnRadiusMaskMap", "Radius of the spherical mask to be applied to all references (in Angstroms)");
+        EMDL::addLabel(EMDL_OPTIMISER_RADIUS_MASK_EXP_PARTICLES, EMDL_INT, "rlnRadiusMaskExpImages", "Radius of the circular mask to be applied to all experimental images (in Angstroms)");
+        EMDL::addLabel(EMDL_OPTIMISER_RANDOM_SEED, EMDL_INT, "rlnRandomSeed", "Seed (i.e. a number) for the random number generator");
+        EMDL::addLabel(EMDL_OPTIMISER_REFS_ARE_CTF_CORRECTED, EMDL_BOOL, "rlnRefsAreCtfCorrected", "Flag to indicate that the input references have been CTF-amplitude corrected");
+        EMDL::addLabel(EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_CLASSES, EMDL_INT, "rlnSmallestChangesClasses", "Smallest changes thus far in the optimal class assignments (in numer of particles).");
+        EMDL::addLabel(EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_OFFSETS, EMDL_DOUBLE, "rlnSmallestChangesOffsets", "Smallest changes thus far in the optimal offset assignments (in pixels).");
+        EMDL::addLabel(EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_ORIENTS, EMDL_DOUBLE, "rlnSmallestChangesOrientations", "Smallest changes thus far in the optimal orientation assignments (in degrees).");
+        EMDL::addLabel(EMDL_OPTIMISER_SAMPLING_STARFILE, EMDL_STRING, "rlnOrientSamplingStarFile", "STAR file with metadata for the orientational sampling");
+        EMDL::addLabel(EMDL_OPTIMISER_SOLVENT_MASK_NAME, EMDL_STRING, "rlnSolventMaskName", "Name of an image that contains a (possibly soft) mask for the solvent area (values=0 for solvent, values =1 for protein)");
+        EMDL::addLabel(EMDL_OPTIMISER_SOLVENT_MASK2_NAME, EMDL_STRING, "rlnSolventMask2Name", "Name of a secondary solvent mask (e.g. to flatten density inside an icosahedral virus)");
+        EMDL::addLabel(EMDL_OPTIMISER_TAU_SPECTRUM_NAME, EMDL_STRING, "rlnTauSpectrumName", "Name of a STAR file that holds a tau2-spectrum");
+        EMDL::addLabel(EMDL_OPTIMISER_USE_TOO_COARSE_SAMPLING, EMDL_BOOL, "rlnUseTooCoarseSampling", "Flag to indicate that the angular sampling on the sphere will be one step coarser than needed to speed up calculations");
+        EMDL::addLabel(EMDL_OPTIMISER_WIDTH_MASK_EDGE, EMDL_INT, "rlnWidthMaskEdge", "Width (in pixels) of the soft edge for spherical/circular masks to be used for solvent flattening");
+
+        EMDL::addLabel(EMDL_ORIENT_FLIP, EMDL_BOOL, "rlnIsFlip", "Flag to indicate that an image should be mirrored");
+        EMDL::addLabel(EMDL_ORIENT_ID, EMDL_LONG, "rlnOrientationsID", "ID (i.e. a unique number) for an orientation");
+        EMDL::addLabel(EMDL_ORIENT_ORIGIN_X, EMDL_DOUBLE, "rlnOriginX", "X-coordinate (in pixels) for the origin of rotation");
+        EMDL::addLabel(EMDL_ORIENT_ORIGIN_X_PRIOR, EMDL_DOUBLE, "rlnOriginXPrior", "Center of the prior on the X-coordinate (in pixels) for the origin of rotation");
+        EMDL::addLabel(EMDL_ORIENT_ORIGIN_Y, EMDL_DOUBLE, "rlnOriginY", "Y-coordinate (in pixels) for the origin of rotation");
+        EMDL::addLabel(EMDL_ORIENT_ORIGIN_Y_PRIOR, EMDL_DOUBLE, "rlnOriginYPrior", "Center of the prior on the X-coordinate (in pixels) for the origin of rotation");
+        EMDL::addLabel(EMDL_ORIENT_ORIGIN_Z, EMDL_DOUBLE, "rlnOriginZ", "Z-coordinate (in pixels) for the origin of rotation");
+        EMDL::addLabel(EMDL_ORIENT_ORIGIN_Z_PRIOR, EMDL_DOUBLE, "rlnOriginZPrior", "Center of the prior on the X-coordinate (in pixels) for the origin of rotation");
+        EMDL::addLabel(EMDL_ORIENT_ROT, EMDL_DOUBLE, "rlnAngleRot", "First Euler angle (rot, in degrees)");
+        EMDL::addLabel(EMDL_ORIENT_ROT_PRIOR, EMDL_DOUBLE, "rlnAngleRotPrior", "Center of the prior (in degrees) on the first Euler angle (rot)");
+        EMDL::addLabel(EMDL_ORIENT_TILT, EMDL_DOUBLE, "rlnAngleTilt", "Second Euler angle (tilt, in degrees)");
+        EMDL::addLabel(EMDL_ORIENT_TILT_PRIOR, EMDL_DOUBLE, "rlnAngleTiltPrior", "Center of the prior (in degrees) on the second Euler angle (tilt)");
+        EMDL::addLabel(EMDL_ORIENT_PSI, EMDL_DOUBLE, "rlnAnglePsi", "Third Euler, or in-plane angle (psi, in degrees)");
+        EMDL::addLabel(EMDL_ORIENT_PSI_PRIOR, EMDL_DOUBLE, "rlnAnglePsiPrior", "Center of the prior (in degrees) on the third Euler angle (psi)");
+
+        EMDL::addLabel(EMDL_PARTICLE_AUTOPICK_FOM, EMDL_DOUBLE, "rlnAutopickFigureOfMerit", "Autopicking FOM for a particle");
+        EMDL::addLabel(EMDL_PARTICLE_CLASS, EMDL_INT, "rlnClassNumber", "Class number for which a particle has its highest probability");
+        EMDL::addLabel(EMDL_PARTICLE_DLL, EMDL_DOUBLE, "rlnLogLikeliContribution", "Contribution of a particle to the log-likelihood target function");
+        EMDL::addLabel(EMDL_PARTICLE_ID, EMDL_LONG, "rlnParticleId", "ID (i.e. a unique number) for a particle");
+        EMDL::addLabel(EMDL_PARTICLE_FOM, EMDL_DOUBLE, "rlnParticleFigureOfMerit", "Developmental FOM for a particle");
+        EMDL::addLabel(EMDL_PARTICLE_KL_DIVERGENCE, EMDL_DOUBLE, "rlnKullbackLeibnerDivergence", "Kullback-Leibner divergence for a particle");
+        EMDL::addLabel(EMDL_PARTICLE_RANDOM_SUBSET, EMDL_INT, "rlnRandomSubset", "Random subset to which this particle belongs");
+        EMDL::addLabel(EMDL_PARTICLE_NAME, EMDL_STRING, "rlnParticleName", "Name for a particles");
+        EMDL::addLabel(EMDL_PARTICLE_ORI_NAME, EMDL_STRING, "rlnOriginalParticleName", "Original name for a particles");
+        EMDL::addLabel(EMDL_PARTICLE_NR_SIGNIFICANT_SAMPLES, EMDL_INT, "rlnNrOfSignificantSamples", "Number of orientational/class assignments (for a particle) with sign.probabilities in the 1st pass of adaptive oversampling"); /**< particle, Number of orientations contributing to weights*/
+        EMDL::addLabel(EMDL_PARTICLE_NR_FRAMES, EMDL_INT, "rlnNrOfFrames", "Number of movie frames that were collected for this particle");
+        EMDL::addLabel(EMDL_PARTICLE_PMAX, EMDL_DOUBLE, "rlnMaxValueProbDistribution", "Maximum value of the (normalised) probability function for a particle"); /**< particle, Maximum value of probability distribution */
+
+        EMDL::addLabel(EMDL_POSTPROCESS_FINAL_RESOLUTION, EMDL_DOUBLE, "rlnFinalResolution", "Final estimated resolution after postprocessing (in Angstroms)");
+        EMDL::addLabel(EMDL_POSTPROCESS_BFACTOR, EMDL_DOUBLE, "rlnBfactorUsedForSharpening", "Applied B-factor in the sharpening of the map");
+        EMDL::addLabel(EMDL_POSTPROCESS_FSC_TRUE, EMDL_DOUBLE, "rlnFourierShellCorrelationCorrected", "Final FSC value: i.e. after correction based on masking of randomized-phases maps");
+        EMDL::addLabel(EMDL_POSTPROCESS_FSC_MASKED, EMDL_DOUBLE, "rlnFourierShellCorrelationMaskedMaps", "FSC value after masking of the original maps");
+        EMDL::addLabel(EMDL_POSTPROCESS_FSC_UNMASKED, EMDL_DOUBLE, "rlnFourierShellCorrelationUnmaskedMaps", "FSC value before masking of the original maps");
+        EMDL::addLabel(EMDL_POSTPROCESS_FSC_RANDOM_MASKED, EMDL_DOUBLE, "rlnCorrectedFourierShellCorrelationPhaseRandomizedMaskedMaps", "FSC value after masking of the randomized-phases maps");
+        EMDL::addLabel(EMDL_POSTPROCESS_GUINIER_FIT_INTERCEPT, EMDL_DOUBLE, "rlnFittedInterceptGuinierPlot", "The fitted intercept of the Guinier-plot");
+        EMDL::addLabel(EMDL_POSTPROCESS_GUINIER_FIT_SLOPE, EMDL_DOUBLE, "rlnFittedSlopeGuinierPlot", "The fitted slope of the Guinier-plot");
+        EMDL::addLabel(EMDL_POSTPROCESS_GUINIER_FIT_CORRELATION, EMDL_DOUBLE, "rlnCorrelationFitGuinierPlot", "The correlation coefficient of the fitted line through the Guinier-plot");
+        EMDL::addLabel(EMDL_POSTPROCESS_GUINIER_VALUE_IN, EMDL_DOUBLE, "rlnLogAmplitudesOriginal", "Y-value for Guinier plot: the logarithm of the radially averaged amplitudes of the input map");
+        EMDL::addLabel(EMDL_POSTPROCESS_GUINIER_VALUE_INVMTF, EMDL_DOUBLE, "rlnLogAmplitudesMTFCorrected", "Y-value for Guinier plot: the logarithm of the radially averaged amplitudes after MTF correction");
+        EMDL::addLabel(EMDL_POSTPROCESS_GUINIER_VALUE_WEIGHTED, EMDL_DOUBLE, "rlnLogAmplitudesWeighted", "Y-value for Guinier plot: the logarithm of the radially averaged amplitudes after FSC-weighting");
+        EMDL::addLabel(EMDL_POSTPROCESS_GUINIER_VALUE_SHARPENED, EMDL_DOUBLE, "rlnLogAmplitudesSharpened", "Y-value for Guinier plot: the logarithm of the radially averaged amplitudes after sharpening");
+        EMDL::addLabel(EMDL_POSTPROCESS_GUINIER_VALUE_INTERCEPT, EMDL_DOUBLE, "rlnLogAmplitudesIntercept", "Y-value for Guinier plot: the fitted plateau of the logarithm of the radially averaged amplitudes");
+        EMDL::addLabel(EMDL_POSTPROCESS_GUINIER_RESOL_SQUARED, EMDL_DOUBLE, "rlnResolutionSquared", "X-value for Guinier plot: squared resolution in 1/Angstrom^2");
+		EMDL::addLabel(EMDL_POSTPROCESS_MTF_VALUE, EMDL_DOUBLE, "rlnMtfValue", "Value of the detectors modulation transfer function (between 0 and 1)");
+
+        EMDL::addLabel(EMDL_SAMPLING_IS_3D, EMDL_BOOL, "rlnIs3DSampling", "Flag to indicate this concerns a 3D sampling ");
+        EMDL::addLabel(EMDL_SAMPLING_IS_3D_TRANS, EMDL_BOOL, "rlnIs3DTranslationalSampling", "Flag to indicate this concerns a x,y,z-translational sampling ");
+        EMDL::addLabel(EMDL_SAMPLING_HEALPIX_ORDER, EMDL_INT, "rlnHealpixOrder", "Healpix order for the sampling of the first two Euler angles (rot, tilt) on the 3D sphere");
+        EMDL::addLabel(EMDL_SAMPLING_LIMIT_TILT, EMDL_DOUBLE, "rlnTiltAngleLimit", "Values to which to limit the tilt angles (positive for keeping side views, negative for keeping top views)");
+        EMDL::addLabel(EMDL_SAMPLING_OFFSET_RANGE, EMDL_DOUBLE, "rlnOffsetRange", "Search range for the origin offsets (in Angstroms)");
+        EMDL::addLabel(EMDL_SAMPLING_OFFSET_STEP, EMDL_DOUBLE, "rlnOffsetStep", "Step size for the searches in the origin offsets (in Angstroms)");
+        EMDL::addLabel(EMDL_SAMPLING_PERTURB, EMDL_DOUBLE, "rlnSamplingPerturbInstance", "Random instance of the random perturbation on the orientational sampling");
+        EMDL::addLabel(EMDL_SAMPLING_PERTURBATION_FACTOR, EMDL_DOUBLE, "rlnSamplingPerturbFactor", "Factor for random perturbation on the orientational sampling (between 0 no perturbation and 1 very strong perturbation)");
+        EMDL::addLabel(EMDL_SAMPLING_PSI_STEP, EMDL_DOUBLE, "rlnPsiStep", "Step size (in degrees) for the sampling of the in-plane rotation angle (psi)");
+        EMDL::addLabel(EMDL_SAMPLING_SYMMETRY, EMDL_STRING, "rlnSymmetryGroup", "Symmetry group (e.g., C1, D7, I2, I5, etc.)");
+
+        EMDL::addLabel(EMDL_SELECTED, EMDL_BOOL, "rlnSelected", "Flag whether an entry in a metadatatable is selected in the viewer or not");
+        EMDL::addLabel(EMDL_SELECT_PARTICLES_ZSCORE, EMDL_DOUBLE, "rlnParticleSelectZScore", "Sum of Z-scores from particle_select. High Z-scores are likely to be outliers.");
+        EMDL::addLabel(EMDL_SORTED_IDX, EMDL_LONG, "rlnSortedIndex", "Index of a metadata entry after sorting (first sorted index is 0).");
+		EMDL::addLabel(EMDL_PERFRAME_CUMULATIVE_WEIGHT, EMDL_DOUBLE, "rlnPerFrameCumulativeWeight", "Sum of the resolution-dependent relative weights from the first frame until the given frame");
+		EMDL::addLabel(EMDL_PERFRAME_RELATIVE_WEIGHT, EMDL_DOUBLE, "rlnPerFrameRelativeWeight", "The resolution-dependent relative weights for a given frame");
+
+        EMDL::addLabel(EMDL_RESOLUTION, EMDL_DOUBLE, "rlnResolution", "Resolution (in 1/Angstroms)");
+        EMDL::addLabel(EMDL_RESOLUTION_ANGSTROM, EMDL_DOUBLE, "rlnAngstromResolution", "Resolution (in Angstroms)");
+        EMDL::addLabel(EMDL_RESOLUTION_INVPIXEL, EMDL_DOUBLE, "rlnResolutionInversePixel", "Resolution (in 1/pixel, Nyquist = 0.5)");
+        EMDL::addLabel(EMDL_SPECTRAL_IDX, EMDL_INT, "rlnSpectralIndex", "Spectral index (i.e. distance in pixels to the origin in Fourier space) ");
+
+
+     }
+
+    ~StaticInitialization()
+    {
+    }
+    friend class EMDL;
+};
+
+/**Just an utility function */
+bool vectorContainsLabel(const std::vector<EMDLabel>& labelsVector, const EMDLabel label);
+
+
+
+#endif
diff --git a/src/metadata_table.cpp b/src/metadata_table.cpp
new file mode 100644
index 0000000..db5d1fe
--- /dev/null
+++ b/src/metadata_table.cpp
@@ -0,0 +1,801 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:      J.R. Bilbao-Castro (jrbcast at ace.ual.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include "src/metadata_table.h"
+
+MetaDataTable::MetaDataTable()
+{
+    clear();
+}
+
+MetaDataTable::MetaDataTable(const MetaDataTable &MD)
+{
+    clear();
+    this->setComment(MD.getComment());
+    this->setName(MD.getName());
+    this->isList = MD.isList;
+    this->activeLabels = MD.activeLabels;
+    this->objects.clear();
+    this->objects.resize(MD.objects.size());
+    for (unsigned long int idx = 0; idx < MD.objects.size(); idx++)
+    {
+    	 //long int idx = this->addObject();
+    	this->objects[idx] = new MetaDataContainer(*(MD.objects[idx]));
+    }
+	current_objectID = 0;
+
+}
+
+MetaDataTable& MetaDataTable::operator =(const MetaDataTable &MD)
+{
+    if (this != &MD)
+    {
+        clear();
+        this->setComment(MD.getComment());
+        this->setName(MD.getName());
+        this->isList = MD.isList;
+        this->activeLabels = MD.activeLabels;
+        this->objects.clear();
+        this->objects.resize(MD.objects.size());
+        for (long int idx = 0; idx < MD.objects.size(); idx++)
+        {
+        	//long int idx = this->addObject();
+        	this->objects[idx] = new MetaDataContainer(*(MD.objects[idx]));
+        }
+    	current_objectID = 0;
+    }
+    return *this;
+}
+
+void MetaDataTable::setIsList(bool is_list)
+{
+    isList = is_list;
+}
+
+MetaDataTable::~MetaDataTable()
+{
+    clear();
+}
+
+bool MetaDataTable::isEmpty() const
+{
+    return (objects.size()==0);
+}
+
+long int MetaDataTable::numberOfObjects() const
+{
+	return objects.size();
+}
+
+void MetaDataTable::clear()
+{
+    for (unsigned long int i = 0; i < objects.size(); i++)
+    {
+        if (objects[i])
+        {
+        	objects[i]->clear();
+            delete objects[i];
+        }
+    }
+
+    objects.clear();
+    comment.clear();
+    name.clear();
+
+    current_objectID = -1;
+    activeLabels.clear();
+    ignoreLabels.clear();
+
+    isList = false;
+
+}
+
+void MetaDataTable::setComment(const std::string newComment)
+{
+	comment = newComment;
+}
+
+std::string MetaDataTable::getComment() const
+{
+    return comment;
+}
+
+bool MetaDataTable::containsComment() const
+{
+	return (comment != std::string(""));
+}
+
+void MetaDataTable::setName(const std::string newName)
+{
+	name = newName;
+}
+
+std::string MetaDataTable::getName() const
+{
+    return name;
+}
+
+bool MetaDataTable::setValue(const std::string &name, const std::string &value,
+                        long int objectID)
+{
+    EMDLabel label = EMDL::str2Label(name);
+
+    if (!isEmpty() && EMDL::isValidLabel(label))
+    {
+        long int auxID = (objectID == -1) ? current_objectID : objectID;
+
+        if (auxID >= objects.size())
+        	REPORT_ERROR("MetaDataTable::setValue: auxID >= objects.size()");
+
+        MetaDataContainer * aux = objects[auxID];
+
+        // Check whether label is correct (belongs to the enum in the metadata_container header
+        // and whether it is present in the activeLabels vector. If not, add it to all the other
+        // objects with default values
+        std::vector<EMDLabel>::iterator location;
+        location = std::find(activeLabels.begin(), activeLabels.end(), label);
+
+        if (location == activeLabels.end())
+        {
+            activeLabels.push_back(label);
+
+            // Add this label to the rest of the objects in this class
+            for (long int idx = 0; idx < objects.size(); idx++)
+            {
+                if (objects[idx] != aux)
+                	objects[idx]->addDefaultValue(label);
+            }
+        }
+
+        aux->addValue(name, value);
+
+        return true;
+    }
+    else
+    {
+    	// in case of empty objects or invalid label
+        return false;
+    }
+}
+
+bool MetaDataTable::containsLabel(const EMDLabel label) const
+{
+    return vectorContainsLabel(activeLabels, label);
+}
+
+void MetaDataTable::deactivateLabel(EMDLabel label)
+{
+    if (containsLabel(label))
+    {
+    	std::vector<EMDLabel>::iterator location;
+    	location = std::find(activeLabels.begin(), activeLabels.end(), label);
+    	activeLabels.erase(location);
+    }
+}
+
+void MetaDataTable::append(MetaDataTable &app)
+{
+	// Go to the end of the table
+	current_objectID = objects.size();
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(app)
+	{
+		addObject(app.getObject());
+	}
+	// Reset pointer to the beginning of the table
+	current_objectID = 0;
+
+}
+
+bool MetaDataTable::addLabel(const EMDLabel label)
+{
+    if (containsLabel(label))
+        return false;
+    activeLabels.push_back(label);
+    return true;
+}
+
+long int MetaDataTable::addObject(MetaDataContainer * data, long int objectID)
+{
+    long int result;
+
+    if (objectID == -1)
+    {
+        result = objects.size();
+        objects.resize(result+1);
+    }
+    else
+    {
+        if (objectID >= objects.size())
+        	REPORT_ERROR("MetaDataTable::addObject: objectID >= objects.size()");
+
+        result = objectID;
+        // First free memory of old container if it existed
+        if (objects[result])
+        {
+        	objects[result]->clear();
+        	delete objects[result];
+        }
+    }
+
+    if (data == NULL)
+        objects[result] = new MetaDataContainer();
+    else
+        objects[result] = new MetaDataContainer(*(data));
+
+    // Set iterator pointing to the newly added object
+    current_objectID = result;
+
+    // Set default values for the existing labels
+    if (data == NULL)
+    {
+		std::vector<EMDLabel>::iterator It;
+		for (It = activeLabels.begin(); It != activeLabels.end(); It++)
+		{
+			(objects[result])->addDefaultValue(*It);
+		}
+    }
+    else
+    {
+    	// Set all the labels from the data MDC as active
+    	std::vector<EMDLabel> newlabels;
+    	newlabels = data->getLabels();
+    	for (int i = 0; i < newlabels.size(); i++)
+    	{
+    		std::vector<EMDLabel>::iterator location;
+    		EMDLabel label = newlabels[i];
+    		location = std::find(activeLabels.begin(), activeLabels.end(), label);
+    		if (location == activeLabels.end())
+    		{
+    			activeLabels.push_back(label);
+
+                // Add this label to the rest of the objects in this class
+                for (long int idx = 0; idx < objects.size(); idx++ )
+                {
+                    if (idx != result)
+                    	objects[idx]->addDefaultValue(label);
+                }
+    		}
+    	}
+    }
+
+    return result;
+}
+
+long int MetaDataTable::removeObject(long int objectID)
+{
+	long int i = (objectID == -1) ? current_objectID : objectID;
+
+    if (objects[i])
+    {
+    	objects[i]->clear();
+        delete objects[i];
+    }
+    objects.erase(objects.begin() + i);
+
+    return lastObject();
+}
+
+MetaDataContainer * MetaDataTable::getObject(const long int objectID) const
+{
+    if (isEmpty())
+    {
+        // The objects map is empty, error
+        REPORT_ERROR("Requested objectID not found (no objects stored). Exiting... ");
+    }
+
+    MetaDataContainer * aux;
+    if (objectID == -1)
+        aux = objects[current_objectID];
+    else
+    {
+#ifdef DEBUG_CHECKSIZES
+		if (objectID >= objects.size())
+		{
+			std::cerr<< "objectID= "<<objectID<<" objects.size()= "<< objects.size() <<std::endl;
+			REPORT_ERROR("MetaDataTable::getObject: objectID >= objects.size()");
+		}
+#endif
+    	aux = objects[objectID];
+    }
+
+    if (aux == NULL)
+    {
+        // This objectID does not exist, finish execution
+        REPORT_ERROR("Requested objectID not found. Exiting... ");
+    }
+
+    return aux;
+}
+
+void MetaDataTable::setObject(MetaDataContainer * data, long int objectID)
+{
+
+	long int idx = (objectID == -1) ? current_objectID : objectID;
+
+#ifdef DEBUG_CHECKSIZES
+	if (idx >= objects.size())
+		REPORT_ERROR("MetaDataTable::setObject: idx >= objects.size()");
+#endif
+
+        // First delete old container if it exists
+        if (this->objects[idx])
+        {
+        	this->objects[idx]->clear();
+        	delete this->objects[idx];
+        }
+	this->objects[idx] = new MetaDataContainer(*data);
+
+	// Set all the labels from the data MDC as active
+	std::vector<EMDLabel>::iterator location;
+	std::vector<EMDLabel> newlabels;
+	newlabels = data->getLabels();
+	for (int i = 0; i < newlabels.size(); i++)
+	{
+		EMDLabel label = newlabels[i];
+		location = std::find(activeLabels.begin(), activeLabels.end(), label);
+		if (location == activeLabels.end())
+		{
+			activeLabels.push_back(label);
+
+            // Add this label with default values to the rest of the objects in this class
+            for (long int idx2 = 0; idx2 < objects.size(); idx2++ )
+            {
+               if (idx2 != idx)
+              	objects[idx2]->addDefaultValue(label);
+            }
+		}
+	}
+
+
+}
+
+long int MetaDataTable::firstObject()
+{
+    long int result = 0;
+
+    if (!isEmpty())
+    {
+    	current_objectID = 0;
+        result = 0;
+    }
+    else
+    {
+        result = NO_OBJECTS_STORED; // Map is empty
+    }
+
+    return result;
+}
+
+long int MetaDataTable::nextObject()
+{
+    long int result = 0;
+
+    if (!isEmpty())
+    {
+    	current_objectID++;
+
+        if (current_objectID < objects.size())
+        {
+            result = current_objectID;
+        }
+        else
+        {
+            result = NO_MORE_OBJECTS;
+            current_objectID = lastObject();
+        }
+    }
+    else
+    {
+        result = NO_OBJECTS_STORED;
+        current_objectID = -1;
+    }
+
+    return result;
+}
+
+
+long int MetaDataTable::lastObject()
+{
+    long int result = 0;
+
+    if (!isEmpty())
+    {
+        result = objects.size() - 1;
+        current_objectID = result;
+    }
+    else
+    {
+        result = NO_OBJECTS_STORED;
+        current_objectID = -1;
+    }
+
+    return result;
+}
+
+
+long int MetaDataTable::goToObject(long int objectID)
+{
+	if (objectID < objects.size())
+	{
+		current_objectID = objectID;
+		return current_objectID;
+	}
+	else
+	{
+		REPORT_ERROR("MetaDataTable::goToObject: objectID >= objects.size()");
+	}
+}
+
+void MetaDataTable::readStarLoop(std::ifstream& in, std::vector<EMDLabel> *desiredLabels)
+{
+	setIsList(false);
+
+	//Read column labels
+    int labelPosition = 0;
+    EMDLabel label;
+    std::string line, token, value;
+
+    // First read all the column labels
+    while (getline(in, line, '\n'))
+    {
+    	line = simplify(line);
+    	// TODO: handle comments...
+    	if (line[0] == '#' || line[0] == '\0' || line[0] == ';')
+    		continue;
+
+    	if (line[0] == '_') // label definition line
+    	{
+    		//Only take string from "_" until "#"
+    		token = line.substr(line.find("_") + 1, line.find("#") - 2);
+    		label = EMDL::str2Label(token);
+    		//std::cerr << " label= XX" << label << "XX token= XX" << token<<"XX" << std::endl;
+    		if (desiredLabels != NULL && !vectorContainsLabel(*desiredLabels, label))
+    			label = EMDL_UNDEFINED; //ignore if not present in desiredLabels
+
+    		if (label == EMDL_UNDEFINED)
+    		{
+    			//std::cerr << "Warning: ignoring the following (undefined) label:" <<token << std::endl;
+    			REPORT_ERROR("ERROR: Unrecognised metadata label: " + token);
+    			ignoreLabels.push_back(labelPosition);
+    		}
+    		else
+    			activeLabels.push_back(label);
+
+    		labelPosition++;
+    	}
+    	else // found first data line
+    	{
+    		break;
+    	}
+    }
+
+    // Then fill the table (dont read another line until the one from above has been handled)
+    bool is_first= true;
+    while (is_first || getline(in, line, '\n'))
+    {
+    	is_first=false;
+    	line = simplify(line);
+    	// Stop at empty line
+    	if (line[0] == '\0')
+    		break;
+
+    	// Add a new line to the table
+    	addObject();
+
+    	// Parse data values
+    	std::stringstream os2(line);
+    	std::string value;
+		labelPosition = 0;
+		int counterIgnored = 0;
+		while (os2 >> value)
+		{
+			// TODO: handle comments here...
+			if (std::find(ignoreLabels.begin(), ignoreLabels.end(), labelPosition) != ignoreLabels.end())
+			{
+				// Ignore this column
+				counterIgnored++;
+				labelPosition++;
+				continue;
+			}
+			setValue(EMDL::label2Str(activeLabels[labelPosition - counterIgnored]), value);
+			labelPosition++;
+		}
+
+    }
+
+}
+
+bool MetaDataTable::readStarList(std::ifstream& in, std::vector<EMDLabel> *desiredLabels)
+{
+	setIsList(true);
+    long int objectID = addObject();
+    EMDLabel label;
+    std::string line, firstword, value;
+    std::vector<std::string> words;
+    std::stringstream ss;
+    bool also_has_loop = false;
+
+    // Read data and fill structures accordingly
+    while (getline(in, line, '\n'))
+    {
+    	 tokenize(line, words);
+
+    	 // Ignore empty lines
+    	 if (words.size() == 0)
+    		 continue;
+    	 else
+    		 firstword = words[0];
+
+    	 // Get label-value pairs
+    	 if (firstword[0] == '_')
+    	 {
+    		 label = EMDL::str2Label(firstword.substr(1)); // get rid of leading underscore
+        	 if (words.size() != 2)
+        		 REPORT_ERROR("MetaDataTable::readStarList: did not encounter a single word after "+firstword);
+    		 value = words[1];
+
+    		 if (desiredLabels != NULL && !vectorContainsLabel(*desiredLabels, label))
+				label = EMDL_UNDEFINED; //ignore if not present in desiredLabels
+    		 if (label != EMDL_UNDEFINED)
+			 {
+				 activeLabels.push_back(label);
+				 setValue(EMDL::label2Str(label), value, objectID);
+			 }
+    	 }
+    	 // Check whether there is a comment or an empty line
+    	 else if (firstword[0] == '#' || firstword[0] == ';')
+    	 {
+    		 // TODO: handle comments?
+    		 continue;
+    	 }
+    	 // Check whether a loop structure comes after this list
+    	 else if (firstword.find("loop_") == 0)
+    	 {
+    		 also_has_loop = true;
+    		 return also_has_loop;
+    	 }
+    	 // Check whether this data blocks ends (because a next one is there)
+    	 else if (firstword.find("data_") == 0)
+    	 {
+    		 // Should I reverse the pointer one line?
+    		 return also_has_loop;
+    	 }
+     }
+     // Reached the end of the file
+     return also_has_loop;
+}
+
+int MetaDataTable::readStar(std::ifstream& in, const std::string &name, std::vector<EMDLabel> *desiredLabels)
+{
+    std::stringstream ss;
+    std::string line, token, value;
+    std::vector<std::string> tokens;
+    clear();
+    bool also_has_loop;
+
+    // Start reading the ifstream at the top
+    in.seekg(0);
+
+    // Proceed until the next data_ or _loop statement
+    // The loop statement may be necessary for data blocks that have a list AND a table inside them
+    while (getline(in, line, '\n'))
+    {
+    	// Find data_ lines
+    	if (line.find("data_") != std::string::npos)
+    	{
+    		token = line.substr(line.find("data_") + 5);
+    		// If a name has been given, only read data_thatname
+    		// Otherwise, just read the first data_ block
+    		if (name == "" || name == token)
+    		{
+    			setName(token);
+    			// Get the next item that starts with "_somelabel" or with "loop_"
+    			int current_pos = in.tellg();
+    			while (getline(in, line, '\n'))
+    			{
+    				trim(line);
+    				if (line.find("loop_") != std::string::npos)
+    				{
+    					readStarLoop(in, desiredLabels);
+    					return 1;
+    				}
+    				else if (line[0] == '_')
+    				{
+    					// go back one line in the ifstream
+    					in.seekg(current_pos);
+    					also_has_loop = readStarList(in, desiredLabels);
+    					return (also_has_loop) ? 0 : 1;
+    				}
+    			}
+    		}
+    	}
+    }
+
+    return 0;
+}
+
+int MetaDataTable::read(const FileName &filename, const std::string &name, std::vector<EMDLabel> *desiredLabels)
+{
+
+    // Clear current table
+    clear();
+
+    std::ifstream in(filename.data(), std::ios_base::in);
+    if (in.fail())
+        REPORT_ERROR( (std::string) "MetaDataTable::read: File " + filename + " does not exists" );
+
+    FileName ext = filename.getFileFormat();
+    if (ext =="star")
+    {
+        //REPORT_ERROR("readSTAR not implemented yet...");
+        return readStar(in, name, desiredLabels);
+    }
+    else
+    {
+        REPORT_ERROR("MetaDataTable::read ERROR: metadatatable should have .star extension");
+    }
+
+    in.close();
+
+}
+
+void MetaDataTable::write(std::ostream& out)
+{
+
+    // Only write tables that have something in them
+    if (isEmpty())
+        return;
+
+    std::vector<EMDLabel>::iterator strIt;
+    std::string entryComment;
+
+    out << "\n";
+    out << "data_" << getName() <<"\n";
+    if (containsComment())
+    	out << "# "<< comment << "\n";
+    out << "\n";
+
+    if (!isList)
+    {
+        // Write loop header structure
+    	out << "loop_ \n";
+        int ii = 0;
+    	for (strIt = activeLabels.begin(); strIt != activeLabels.end(); strIt++)
+        {
+            ii++;
+            if (*strIt != EMDL_COMMENT && *strIt != EMDL_SORTED_IDX) // EMDL_SORTED_IDX is only for internal use, never write it out!
+    		//if (*strIt != EMDL_COMMENT)
+            {
+                out << "_" << EMDL::label2Str(*strIt) << " #" << ii << " \n";
+            }
+        }
+
+        // Write actual data block
+        for (long int idx = 0; idx < objects.size(); idx++)
+        {
+        	entryComment = "";
+        	for (strIt = activeLabels.begin(); strIt != activeLabels.end(); strIt++)
+            {
+        		if (*strIt != EMDL_COMMENT && *strIt != EMDL_SORTED_IDX)
+            	//if (*strIt != EMDL_COMMENT)
+                {
+                    out.width(10);
+                    objects[idx]->writeValueToStream(out, *strIt);
+                    out << " ";
+                }
+            	if (*strIt == EMDL_COMMENT)
+                {
+                	objects[idx]->getValue(EMDL_COMMENT, entryComment);
+                }
+            }
+            if (entryComment != std::string(""))
+            {
+            	out << "# " << entryComment;
+            }
+            out << "\n";
+        }
+        // Finish table with a white-line
+        out << " \n";
+
+    }
+    else
+    {
+        // Get first object. In this case (row format) there is a single object
+        MetaDataContainer * object = getObject();
+
+        entryComment = "";
+        int maxWidth=10;
+        for (strIt = activeLabels.begin(); strIt != activeLabels.end(); strIt++)
+        {
+            if (*strIt != EMDL_COMMENT)
+            {
+                int w=EMDL::label2Str(*strIt).length();
+                if (w>maxWidth)
+                    maxWidth=w;
+            }
+            else
+            	object->getValue(EMDL_COMMENT, entryComment);
+        }
+
+        for (strIt = activeLabels.begin(); strIt != activeLabels.end(); strIt++)
+        {
+            if (*strIt != EMDL_COMMENT)
+            {
+            	int w = EMDL::label2Str(*strIt).length();
+            	out << "_" << EMDL::label2Str(*strIt) << std::setw(12 + maxWidth - w) << " ";
+                object->writeValueToStream(out, *strIt);
+                out << "\n";
+            }
+        }
+        if (entryComment != std::string(""))
+        {
+        	out << "# " << entryComment << "\n";
+        }
+
+        // End a data block with a white line
+        out << " \n";
+    }
+}
+
+void MetaDataTable::write(const FileName &fn_out)
+{
+    std::ofstream  fh;
+    fh.open((fn_out).c_str(), std::ios::out);
+    if (!fh)
+        REPORT_ERROR( (std::string)"MetaDataTable::write Cannot write to file: " + fn_out);
+    write(fh);
+    fh.close();
+
+}
+
+void MetaDataTable::writeValueToString(std::string & result,
+                                  const std::string &inputLabel)
+{
+    MetaDataContainer * aux = getObject();
+    aux->writeValueToString(result, EMDL::str2Label(inputLabel));
+}
+
+
+
+
diff --git a/src/metadata_table.h b/src/metadata_table.h
new file mode 100644
index 0000000..00c804f
--- /dev/null
+++ b/src/metadata_table.h
@@ -0,0 +1,399 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     J.R. Bilbao-Castro (jrbcast at ace.ual.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef METADATA_TABLE_H
+#define METADATA_TABLE_H
+
+#include <map>
+#include <vector>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+#include <time.h>
+#include <stdio.h>
+#include <sstream>
+#if !defined(__APPLE__)
+#include <malloc.h>
+#endif
+#include "src/funcs.h"
+#include "src/args.h"
+#include "src/metadata_container.h"
+
+/** For all objects.
+ @code
+ FOR_ALL_OBJECTS_IN_METADATA(metadata) {
+   double rot;
+   DF.getValue( EMDL_ANGLEROT, rot);
+ }
+ @endcode
+ */
+#define FOR_ALL_OBJECTS_IN_METADATA_TABLE(kkkk_metadata) \
+        for(long int current_object = (kkkk_metadata).firstObject(); \
+             current_object != MetaDataTable::NO_MORE_OBJECTS && current_object!= MetaDataTable::NO_OBJECTS_STORED; \
+             current_object=(kkkk_metadata).nextObject())
+
+/** MetaDataTable Manager.
+ *
+ */
+class MetaDataTable
+{
+    // Effectively stores all metadata
+    std::vector<MetaDataContainer *> objects;
+
+    // Current object id
+    long int current_objectID;
+
+    // Is this a 2D table or a 1D list?
+    bool isList;
+
+    // Name of the metadata table
+    std::string name;
+
+    // A comment for the metadata table
+    std::string comment;
+
+public:
+
+    /** What labels have been read from a docfile/metadata file
+     *   and/or will be stored on a new metadata file when "save" is
+     *   called
+     **/
+    std::vector<EMDLabel> activeLabels;
+
+    /** When reading a column formated file, if a label is found that
+     *   does not exists as a EMDLabel, it is ignored. For further
+     *   file processing, such columns must be ignored and this structure
+     *   allows to do that
+     **/
+    std::vector<unsigned int> ignoreLabels;
+
+    /** Empty Constructor.
+     *
+     * The MetaDataTable is created with no data stored on it.
+     */
+    MetaDataTable();
+
+    /** Copy constructor
+     *
+     * Created a new MetaDataTable by copying all data from an existing MetaDataTable object.
+     */
+    MetaDataTable(const MetaDataTable & c);
+
+
+    /** Assignment operator
+     * @ingroup MetaDataConstructors
+     *
+     * Copies MetaDataTable from an existing MetaDataTable object.
+     */
+    MetaDataTable& operator =(const MetaDataTable &MD);
+
+    /** Destructor
+     * @ingroup MetaDataTableConstructors
+     *
+     * Frees all used memory and destroys object.
+     */
+    ~MetaDataTable();
+
+    /** Set to false if this is a MetaDataTable
+     *  set to true  if this is a simple list of parameters
+     *
+     */
+    void setIsList(bool is_list);
+
+    // returns true of the metadatatable contains no objects
+    bool isEmpty() const;
+
+    // Returns the number of elements in the table
+    long int numberOfObjects() const;
+
+    // Removes all objects from the metadatatable
+    void clear();
+
+    /**Set Comment
+     */
+    void setComment(const std::string Comment = "");
+
+    /**Get Comment
+     */
+    std::string getComment() const;
+
+    /** Does this table contain a comment?
+     */
+    bool containsComment() const;
+
+    /**Set Name
+     */
+    void setName(const std::string Name = "");
+
+    /**Get Name
+     */
+    std::string getName() const;
+
+    size_t size(void)
+    {
+        return objects.size();
+    }
+
+    /*  Get value for any label.
+     *  If the label does not exist, false is returned
+     *  Otherwise, value is set correctly and true is returned
+     */
+
+    template<class T>
+    bool getValue(EMDLabel name, T &value,
+                  long int objectID = -1) const
+    {
+        if (isEmpty())
+        	return false;
+
+        MetaDataContainer * aux = getObject(objectID);
+
+		// Inside getValue of the container there will be a check of the correct type
+        bool result = aux->getValue(name, value);
+        return result;
+    }
+
+    // Read/set a new pair/value for an specified object. If no objectID is given, that
+    // pointed by the class iterator is used
+    bool setValue(const std::string &name, const std::string &value,
+                  long int objectID = -1);
+
+    template<class T>
+    bool setValue(EMDLabel name, const T &value, long int objectID=-1)
+    {
+        if (!isEmpty() && EMDL::isValidLabel(name))
+        {
+
+            long int auxID = (objectID == -1) ? current_objectID : objectID;
+            MetaDataContainer * aux = objects[auxID];
+
+            // Check whether label is correct (belongs to the enum in the metadata_container header
+            // and whether it is present in the activeLabels vector. If not, add it to all the other
+            // objects with default values
+            std::vector<EMDLabel>::iterator location;
+            std::map<long int, MetaDataContainer *>::iterator It;
+            location = std::find(activeLabels.begin(), activeLabels.end(), name);
+            if (location == activeLabels.end())
+            {
+                activeLabels.push_back(name);
+                // Add this label to the rest of the objects in this class
+                for (long int idx = 0; idx < objects.size(); idx++)
+                {
+                    if (objects[idx] != aux)
+                    {
+                    	objects[idx]->addValue(name, T());
+                    }
+                }
+            }
+            aux->addValue(name, value);
+            return true;
+        }
+        else
+        {
+            std::cerr << " %%WARNING%%: unsuccessful setValue" << std::endl;
+            std::cerr << " isEmpty()= " << isEmpty() << std::endl;
+        	std::cerr << " EMDL::isValidLabel(name)= " << EMDL::isValidLabel(name) << std::endl;
+            std::cerr << " name= " << EMDL::label2Str(name) << " value= " << value <<std::endl;
+            return false;
+        }
+    }
+
+    // Sort the order of the elements based on the values in the input label (only numbers, no strings/bools!)
+    // Have to pass dummy T parameter to get the template thing running?
+    void sort(EMDLabel name, bool do_reverse = false, bool only_set_index = false)
+    {
+    	if ( !(EMDL::isInt(name) || EMDL::isLong(name) || EMDL::isDouble(name)) )
+    		REPORT_ERROR("MetadataTable::sort%% ERROR: can only sorted numbers");
+    	std::vector<std::pair<double,long int> > vp;
+    	vp.reserve(objects.size());
+    	long int i = 0;
+    	FOR_ALL_OBJECTS_IN_METADATA_TABLE(*this)
+    	{
+    		double dval;
+    		if (EMDL::isInt(name))
+    		{
+    			int val;
+    			getValue(name, val);
+    			dval = (double) val;
+    		}
+    		else if (EMDL::isLong(name))
+    		{
+    			long int val;
+    			getValue(name, val);
+    			dval = (double) val;
+    		}
+    		else
+    		{
+    			//  EMDL::isDouble(name)
+    			getValue(name, dval);
+    		}
+    		vp.push_back(std::make_pair(dval, i));
+    		i++;
+    	}
+
+    	std::sort(vp.begin(), vp.end());
+    	if (do_reverse)
+    		std::reverse(vp.begin(), vp.end());
+
+    	if (only_set_index)
+    	{
+    		// Add an extra column with the sorted position of each entry
+			for (long int j = 0; j < vp.size(); j++)
+			{
+				(*this).setValue(EMDL_SORTED_IDX, j, vp[j].second);
+			}
+    	}
+    	else
+    	{
+			// Change the actual order in the MetaDataTable
+    		MetaDataTable MDaux;
+			for (long int j = 0; j < vp.size(); j++)
+			{
+				MDaux.addObject();
+				MDaux.setObject((*this).getObject(vp[j].second));
+			}
+			*this = MDaux;
+    	}
+    	// return pointer to the beginning of the table
+    	firstObject();
+    }
+
+    bool valueExists(EMDLabel name)
+    {
+        return (objects[current_objectID])->valueExists(name);
+    }
+
+    /** Check whether a label is contained in metadata.
+     */
+    bool containsLabel(const EMDLabel label) const;
+
+    /** Deactivate a column from a table, so that it is no longer written out
+      */
+    void deactivateLabel(EMDLabel label);
+
+      /** Append the app table to this one
+     */
+    void append(MetaDataTable &app);
+
+    /** Add a new label to the metadata.
+     */
+    bool addLabel(const EMDLabel label);
+
+    /** Adds a new object to the objects map.
+     *   If objectID == -1 the new ID will be that for the last object inserted + 1, else
+     *   the given objectID is used.
+     *   If there is already an object whose objectID == input objectID, the old one will be replaced by the new one
+     *   If data !=NULL, the object will be set to contain these data
+     **/
+    long int addObject(MetaDataContainer * data = NULL, long int objectID = -1);
+
+    /** Remove an object from the table. If objectID is not given, the current object will be removed
+     * This function resets the current pointer to the last entry and returns the lastObject in the table */
+    long int removeObject(long int objectID = -1);
+
+    /* Get metadatacontainer for objectID (is current_objectID when -1)
+     */
+    MetaDataContainer * getObject(long int objectID = -1) const;
+
+    /* Set metadatacontainer for current metadata object
+     * This function assumes there already exists an object with objectID
+     * If objectID==-1,, then the (assumedly existing) currrent_objectID will be set
+     *
+     * Use addObject() to set an object that does not yet exist
+     */
+    void setObject(MetaDataContainer * data, long int objectID = -1);
+
+    // Possible error codes for the map
+    enum errors
+    {
+        NO_OBJECTS_STORED = -1, // NOTE: Do not change this value (-1)
+        NO_MORE_OBJECTS = -2,
+        NO_OBJECT_FOUND = -3
+    };
+
+    long int firstObject();
+    long int nextObject();
+    long int lastObject();
+    long int goToObject(long int objectID);
+
+    /* Read a STAR loop structure
+      */
+    void readStarLoop(std::ifstream& in, std::vector<EMDLabel> *labelsVector = NULL);
+
+    /* Read a STAR list
+     * The function returns true if the list is followed by a loop, false otherwise
+     */
+    bool readStarList(std::ifstream& in, std::vector<EMDLabel> *labelsVector = NULL);
+
+    /* Read a MetaDataTable from a STAR-format data block
+	 *
+     * If the data block contains a list and a table, the function will return 2,
+     *  the first time it is called and the list is read into the MetaDataTable
+     *  in that case the function needs to be called another time. The second time
+     *  it will read the _loop structure into the MetaDataTable and 1 will be returned
+     *
+     * If the data block contains only a list or a table, it is read in the MetaDataTable and the function will return 1
+     *
+     * If no data block is found the function will return 0 and the MetaDataTable remains empty
+     *
+     */
+    int readStar(std::ifstream& in, const std::string &name = "", std::vector<EMDLabel> *labelsVector = NULL);
+
+    // Read a MetaDataTable (get fileformat from extension)
+    int read(const FileName &filename, const std::string &name = "", std::vector<EMDLabel> *labelsVector = NULL);
+
+    // Write a MetaDataTable in STAR format
+    void write(std::ostream& out = std::cout);
+
+    // Write to a single file
+    void write(const FileName & fn_out);
+
+
+    void writeValueToString(std::string & result,
+                            const std::string & inputLabel);
+
+
+};
+
+#endif
diff --git a/src/ml_model.cpp b/src/ml_model.cpp
new file mode 100644
index 0000000..1b2ff39
--- /dev/null
+++ b/src/ml_model.cpp
@@ -0,0 +1,1272 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include "src/ml_model.h"
+
+void MlModel::initialise()
+{
+
+	// Auxiliary vector with relevant size in Fourier space
+	MultidimArray<double > aux;
+    aux.initZeros(ori_size / 2 + 1);
+
+	// Now resize all relevant vectors
+    Iref.resize(nr_classes);
+    pdf_class.resize(nr_classes, 1./(double)nr_classes);
+    pdf_direction.resize(nr_classes);
+    group_names.resize(nr_groups, "");
+    sigma2_noise.resize(nr_groups, aux);
+    nr_particles_group.resize(nr_groups);
+    tau2_class.resize(nr_classes, aux);
+    fsc_halves_class.resize(nr_classes, aux);
+    sigma2_class.resize(nr_classes, aux);
+    data_vs_prior_class.resize(nr_classes, aux);
+    // TODO handle these two correctly.
+    bfactor_correction.resize(nr_groups, 0.);
+    scale_correction.resize(nr_groups, 1.);
+
+	acc_rot.resize(nr_classes, 0);
+	acc_trans.resize(nr_classes, 0);
+
+	if (ref_dim==2)
+	{
+		Matrix1D<double> empty(2);
+		prior_offset_class.resize(nr_classes, empty);
+	}
+	// These arrays will be resized when they are filled
+	orientability_contrib.resize(nr_classes);
+
+	Projector ref(ori_size, interpolator, padding_factor, r_min_nn);
+    PPref.clear();
+    // Now fill the entire vector with instances of "ref"
+    PPref.resize(nr_classes, ref);
+
+}
+
+// Reading from a file
+void MlModel::read(FileName fn_in)
+{
+
+	// Clear current model
+    clear();
+
+    // Open input file
+    std::ifstream in(fn_in.data(), std::ios_base::in);
+    if (in.fail())
+        REPORT_ERROR( (std::string) "MlModel::readStar: File " + fn_in + " cannot be read." );
+
+    MetaDataTable MDclass, MDgroup, MDlog, MDsigma;
+
+    // Read general stuff
+    MDlog.readStar(in, "model_general");
+
+	if (!MDlog.getValue(EMDL_MLMODEL_DIMENSIONALITY, ref_dim) ||
+		!MDlog.getValue(EMDL_MLMODEL_ORIGINAL_SIZE, ori_size) ||
+		!MDlog.getValue(EMDL_MLMODEL_CURRENT_RESOLUTION, current_resolution) ||
+		!MDlog.getValue(EMDL_MLMODEL_CURRENT_SIZE, current_size) ||
+		!MDlog.getValue(EMDL_MLMODEL_PADDING_FACTOR, padding_factor) ||
+		!MDlog.getValue(EMDL_MLMODEL_INTERPOLATOR, interpolator) ||
+		!MDlog.getValue(EMDL_MLMODEL_MINIMUM_RADIUS_NN_INTERPOLATION, r_min_nn) ||
+		!MDlog.getValue(EMDL_MLMODEL_PIXEL_SIZE, pixel_size) ||
+		!MDlog.getValue(EMDL_MLMODEL_NR_CLASSES, nr_classes) ||
+		!MDlog.getValue(EMDL_MLMODEL_NR_GROUPS, nr_groups) ||
+		!MDlog.getValue(EMDL_MLMODEL_TAU2_FUDGE_FACTOR, tau2_fudge_factor) ||
+		!MDlog.getValue(EMDL_MLMODEL_NORM_CORRECTION_AVG, avg_norm_correction) ||
+		!MDlog.getValue(EMDL_MLMODEL_SIGMA_OFFSET, sigma2_offset) ||
+		!MDlog.getValue(EMDL_MLMODEL_PRIOR_MODE, orientational_prior_mode) ||
+		!MDlog.getValue(EMDL_MLMODEL_SIGMA_ROT, sigma2_rot) ||
+		!MDlog.getValue(EMDL_MLMODEL_SIGMA_TILT, sigma2_tilt) ||
+		!MDlog.getValue(EMDL_MLMODEL_SIGMA_PSI, sigma2_psi) ||
+		!MDlog.getValue(EMDL_MLMODEL_LL, LL) ||
+		!MDlog.getValue(EMDL_MLMODEL_AVE_PMAX, ave_Pmax) )
+		REPORT_ERROR("MlModel::readStar: incorrect model_general table");
+
+    // Take inverse again of current resolution:
+    current_resolution = 1. / current_resolution;
+
+    sigma2_offset *= sigma2_offset;
+	sigma2_rot *= sigma2_rot;
+	sigma2_tilt *= sigma2_tilt;
+	sigma2_psi *= sigma2_psi;
+
+	// Resize vectors
+	initialise();
+
+	// Read classes
+	FileName fn_tmp;
+	Image<double> img;
+	MDclass.readStar(in, "model_classes");
+	int iclass = 0;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDclass)
+	{
+		if (!MDclass.getValue(EMDL_MLMODEL_REF_IMAGE, fn_tmp) ||
+			!MDclass.getValue(EMDL_MLMODEL_PDF_CLASS, pdf_class[iclass])||
+			!MDclass.getValue(EMDL_MLMODEL_ACCURACY_ROT, acc_rot[iclass]) ||
+			!MDclass.getValue(EMDL_MLMODEL_ACCURACY_TRANS, acc_trans[iclass]) 	)
+			REPORT_ERROR("MlModel::readStar: incorrect model_classes table");
+		if (ref_dim==2)
+		{
+			if (!MDclass.getValue(EMDL_MLMODEL_PRIOR_OFFX_CLASS, XX(prior_offset_class[iclass])) ||
+				!MDclass.getValue(EMDL_MLMODEL_PRIOR_OFFY_CLASS, YY(prior_offset_class[iclass])) )
+				REPORT_ERROR("MlModel::readStar: incorrect model_classes table: no offset priors for 2D classes");
+		}
+
+		// Read in actual reference image
+		img.read(fn_tmp);
+		Iref[iclass] = img();
+		iclass++;
+	}
+
+	// Read group stuff
+	MDgroup.readStar(in, "model_groups");
+	long int igroup;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDgroup)
+	{
+        if (!MDgroup.getValue(EMDL_MLMODEL_GROUP_NO, igroup))
+                REPORT_ERROR("MlModel::readStar: incorrect model_groups table");
+        //Start counting of groups at 1, not at 0....
+        if (!MDgroup.getValue(EMDL_MLMODEL_GROUP_SCALE_CORRECTION, scale_correction[igroup-1]) ||
+                !MDgroup.getValue(EMDL_MLMODEL_GROUP_NR_PARTICLES, nr_particles_group[igroup-1]) ||
+                !MDgroup.getValue(EMDL_MLMODEL_GROUP_NAME, group_names[igroup-1]))
+                REPORT_ERROR("MlModel::readStar: incorrect model_groups table");
+	}
+
+	// Read SSNR, noise reduction, tau2_class spectra for each class
+	for (int iclass = 0; iclass < nr_classes; iclass++)
+	{
+		MDsigma.readStar(in, "model_class_" + integerToString(iclass + 1));
+		int idx;
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDsigma)
+		{
+			if (!MDsigma.getValue(EMDL_SPECTRAL_IDX, idx))
+				REPORT_ERROR("MlModel::readStar: incorrect table model_class_"+integerToString(iclass));
+			if (!MDsigma.getValue(EMDL_MLMODEL_DATA_VS_PRIOR_REF, data_vs_prior_class[iclass](idx)) ||
+			    !MDsigma.getValue(EMDL_MLMODEL_TAU2_REF, tau2_class[iclass](idx)) ||
+			    !MDsigma.getValue(EMDL_MLMODEL_FSC_HALVES_REF, fsc_halves_class[iclass](idx)) ||
+			    !MDsigma.getValue(EMDL_MLMODEL_SIGMA2_REF, sigma2_class[iclass](idx)))
+				REPORT_ERROR("MlModel::readStar: incorrect table model_class_"+integerToString(iclass));
+		}
+	}
+
+	// Read sigma models for each group
+	for (int igroup = 0; igroup < nr_groups; igroup++)
+	{
+		if (nr_particles_group[igroup] > 0)
+		{
+			MDsigma.readStar(in, "model_group_" + integerToString(igroup + 1));
+			int idx;
+			FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDsigma)
+			{
+				if (!MDsigma.getValue(EMDL_SPECTRAL_IDX, idx))
+					REPORT_ERROR("MlModel::readStar: incorrect table model_group_"+integerToString(igroup));
+				if (!MDsigma.getValue(EMDL_MLMODEL_SIGMA2_NOISE, sigma2_noise[igroup](idx)))
+					REPORT_ERROR("MlModel::readStar: incorrect table model_group_"+integerToString(igroup));
+			}
+		}
+		else
+		{
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(sigma2_noise[igroup])
+			{
+				DIRECT_MULTIDIM_ELEM(sigma2_noise[igroup], n) = 0.;
+			}
+		}
+	}
+
+	// Read pdf_direction models for each class
+	if (ref_dim == 3)
+	{
+		for (int iclass = 0; iclass < nr_classes; iclass++)
+		{
+			MDclass.readStar(in, "model_pdf_orient_class_" + integerToString(iclass + 1));
+			pdf_direction[iclass].clear();
+			double aux;
+			std::vector<double> vaux;
+			vaux.clear();
+			FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDclass)
+			{
+				if (!MDclass.getValue(EMDL_MLMODEL_PDF_ORIENT, aux))
+					REPORT_ERROR("MlModel::readStar: incorrect table model_pdf_orient_class"+integerToString(iclass));
+				vaux.push_back(aux);
+			}
+			pdf_direction[iclass].resize(vaux.size());
+			FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(pdf_direction[iclass])
+			{
+				DIRECT_A1D_ELEM(pdf_direction[iclass], i) = vaux[i];
+			}
+			nr_directions = vaux.size();
+		}
+	}
+	else
+	{
+		// For 2D case, just fill pdf_direction with ones.
+		for (int iclass = 0; iclass < nr_classes; iclass++)
+		{
+			pdf_direction[iclass].clear();
+			pdf_direction[iclass].resize(1);
+			DIRECT_A1D_ELEM(pdf_direction[iclass], 0) = 1.;
+		}
+		nr_directions = 1;
+	}
+
+	// Close file handler
+	in.close();
+
+}
+
+void MlModel::write(FileName fn_out, HealpixSampling &sampling)
+{
+
+	MetaDataTable MDclass, MDgroup, MDlog, MDsigma;
+    FileName fn_tmp, fn_tmp2;
+    double aux;
+    std::ofstream  fh;
+
+    // A. Write images
+    if (ref_dim == 2)
+    {
+    	Image<double> img(XSIZE(Iref[0]), YSIZE(Iref[0]), 1, nr_classes);
+    	for (int iclass = 0; iclass < nr_classes; iclass++)
+    	{
+    		FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(Iref[iclass])
+			{
+    			DIRECT_NZYX_ELEM(img(), iclass, 0, i, j) = DIRECT_A2D_ELEM(Iref[iclass], i, j);
+			}
+    	}
+    	img.write(fn_out + "_classes.mrcs");
+    }
+    else
+    {
+    	Image<double> img;
+    	// Set correct voxel size in the header
+		img.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_X, pixel_size);
+		img.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Y, pixel_size);
+		img.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Z, pixel_size);
+    	for (int iclass = 0; iclass < nr_classes; iclass++)
+    	{
+    		fn_tmp.compose(fn_out+"_class", iclass+1, "mrc", 3);
+    		img() = Iref[iclass];
+    		img.write(fn_tmp);
+
+
+    	}
+
+    	// Also write out bild files with the orientational distribution of each class
+		// Also write out angular distributions
+		for (int iclass = 0; iclass < nr_classes; iclass++)
+		{
+			FileName fn_bild;
+			fn_bild.compose(fn_out+"_class",iclass+1,"", 3);
+			fn_bild += "_angdist.bild";
+			double offset = ori_size * pixel_size / 2.;
+			sampling.writeBildFileOrientationalDistribution(pdf_direction[iclass], fn_bild, offset, offset);
+		}
+
+	}
+
+    // B. Write STAR file with metadata
+    fn_tmp = fn_out + "_model.star";
+    fh.open((fn_tmp).c_str(), std::ios::out);
+    if (!fh)
+        REPORT_ERROR( (std::string)"MlModel::write: Cannot write file: " + fn_tmp);
+
+    // Write the output STAR file
+	MDlog.setIsList(true);
+	MDlog.addObject();
+	MDlog.setName("model_general");
+	MDlog.setValue(EMDL_MLMODEL_DIMENSIONALITY, ref_dim);
+	MDlog.setValue(EMDL_MLMODEL_ORIGINAL_SIZE, ori_size);
+	MDlog.setValue(EMDL_MLMODEL_CURRENT_RESOLUTION, 1./current_resolution);
+	MDlog.setValue(EMDL_MLMODEL_CURRENT_SIZE, current_size);
+	MDlog.setValue(EMDL_MLMODEL_PADDING_FACTOR, padding_factor);
+	MDlog.setValue(EMDL_MLMODEL_INTERPOLATOR, interpolator);
+	MDlog.setValue(EMDL_MLMODEL_MINIMUM_RADIUS_NN_INTERPOLATION, r_min_nn);
+	MDlog.setValue(EMDL_MLMODEL_PIXEL_SIZE, pixel_size);
+	MDlog.setValue(EMDL_MLMODEL_NR_CLASSES, nr_classes);
+	MDlog.setValue(EMDL_MLMODEL_NR_GROUPS, nr_groups);
+	MDlog.setValue(EMDL_MLMODEL_TAU2_FUDGE_FACTOR, tau2_fudge_factor);
+	MDlog.setValue(EMDL_MLMODEL_NORM_CORRECTION_AVG, avg_norm_correction);
+	MDlog.setValue(EMDL_MLMODEL_SIGMA_OFFSET, sqrt(sigma2_offset));
+	MDlog.setValue(EMDL_MLMODEL_PRIOR_MODE, orientational_prior_mode);
+	MDlog.setValue(EMDL_MLMODEL_SIGMA_ROT, sqrt(sigma2_rot));
+	MDlog.setValue(EMDL_MLMODEL_SIGMA_TILT, sqrt(sigma2_tilt));
+	MDlog.setValue(EMDL_MLMODEL_SIGMA_PSI, sqrt(sigma2_psi));
+	MDlog.setValue(EMDL_MLMODEL_LL, LL);
+	MDlog.setValue(EMDL_MLMODEL_AVE_PMAX, ave_Pmax);
+	MDlog.write(fh);
+
+	// Write metadata and images for all classes
+	MDclass.setName("model_classes");
+	for (int iclass = 0; iclass < nr_classes; iclass++)
+	{
+		MDclass.addObject();
+		if (ref_dim==2)
+		{
+			fn_tmp = fn_out + "_classes.mrcs";
+			fn_tmp.compose(iclass+1, fn_tmp); // fn_tmp = integerToString(iclass) + "@" + fn_tmp;
+		}
+		else
+		{
+			fn_tmp.compose(fn_out+"_class",iclass+1,"mrc", 3); // class number from 1 to K!
+		}
+		MDclass.setValue(EMDL_MLMODEL_REF_IMAGE, fn_tmp);
+		MDclass.setValue(EMDL_MLMODEL_PDF_CLASS, pdf_class[iclass]);
+		MDclass.setValue(EMDL_MLMODEL_ACCURACY_ROT, acc_rot[iclass]);
+		MDclass.setValue(EMDL_MLMODEL_ACCURACY_TRANS, acc_trans[iclass]);
+
+		if (ref_dim==2)
+		{
+			MDclass.setValue(EMDL_MLMODEL_PRIOR_OFFX_CLASS, XX(prior_offset_class[iclass]));
+			MDclass.setValue(EMDL_MLMODEL_PRIOR_OFFY_CLASS, YY(prior_offset_class[iclass]));
+		}
+
+	}
+	MDclass.write(fh);
+
+	// Write radial_average of tau2_class and data_vs_prior_class for each reference
+	for (int iclass = 0; iclass < nr_classes; iclass++)
+	{
+		MDsigma.clear();
+		MDsigma.setName("model_class_"+integerToString(iclass+1));
+		for (int ii = 0; ii < XSIZE(tau2_class[iclass]); ii++)
+		{
+			MDsigma.addObject();
+			MDsigma.setValue(EMDL_SPECTRAL_IDX, ii);
+			MDsigma.setValue(EMDL_RESOLUTION, getResolution(ii));
+			MDsigma.setValue(EMDL_RESOLUTION_ANGSTROM, getResolutionAngstrom(ii));
+			MDsigma.setValue(EMDL_MLMODEL_DATA_VS_PRIOR_REF, data_vs_prior_class[iclass](ii));
+			MDsigma.setValue(EMDL_MLMODEL_FSC_HALVES_REF, fsc_halves_class[iclass](ii));
+			MDsigma.setValue(EMDL_MLMODEL_SIGMA2_REF, sigma2_class[iclass](ii));
+			MDsigma.setValue(EMDL_MLMODEL_TAU2_REF, tau2_class[iclass](ii));
+			// Only write orientabilities if they have been determined
+			if (XSIZE(orientability_contrib[iclass]) == XSIZE(tau2_class[iclass]))
+				MDsigma.setValue(EMDL_MLMODEL_ORIENTABILITY_CONTRIBUTION, orientability_contrib[iclass](ii));
+		}
+		MDsigma.write(fh);
+	}
+
+    // Write scale-correction for all groups
+    MDgroup.setName("model_groups");
+    for (long int igroup = 0; igroup < nr_groups; igroup++)
+    {
+		MDgroup.addObject();
+		//Start counting of groups at 1, not at 0....
+		MDgroup.setValue(EMDL_MLMODEL_GROUP_NO, igroup+1);
+		MDgroup.setValue(EMDL_MLMODEL_GROUP_NAME, group_names[igroup]);
+		MDgroup.setValue(EMDL_MLMODEL_GROUP_NR_PARTICLES, nr_particles_group[igroup]);
+		MDgroup.setValue(EMDL_MLMODEL_GROUP_SCALE_CORRECTION, scale_correction[igroup]);
+    }
+    MDgroup.write(fh);
+
+	// Write sigma models for each group
+	for (int igroup = 0; igroup < nr_groups; igroup++)
+	{
+		MDsigma.clear();
+		MDsigma.setName("model_group_"+integerToString(igroup+1));
+		for (int ii = 0; ii < XSIZE(sigma2_noise[igroup]); ii++)
+		{
+			MDsigma.addObject();
+			// Some points in sigma2_noise arrays are never used...
+			aux = sigma2_noise[igroup](ii);
+			if (aux > 0.)
+			{
+				MDsigma.setValue(EMDL_SPECTRAL_IDX, ii);
+				MDsigma.setValue(EMDL_RESOLUTION, getResolution(ii));
+				MDsigma.setValue(EMDL_MLMODEL_SIGMA2_NOISE, aux);
+			}
+		}
+		MDsigma.write(fh);
+	}
+
+	// Write pdf_direction models for each class
+	if (ref_dim == 3)
+	{
+		for (int iclass = 0; iclass < nr_classes; iclass++)
+		{
+			MDclass.clear();
+			MDclass.setName("model_pdf_orient_class_"+integerToString(iclass+1));
+			for (int ii=0; ii < XSIZE(pdf_direction[iclass]); ii++)
+			{
+				MDclass.addObject();
+				MDclass.setValue(EMDL_MLMODEL_PDF_ORIENT, pdf_direction[iclass](ii));
+			}
+			MDclass.write(fh);
+		}
+	}
+
+}
+
+
+
+
+void  MlModel::readTauSpectrum(FileName fn_tau, int verb)
+{
+	MetaDataTable MDtau;
+	double val;
+	int idx;
+	MDtau.read(fn_tau);
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDtau)
+	{
+		MDtau.getValue(EMDL_SPECTRAL_IDX, idx);
+		MDtau.getValue(EMDL_MLMODEL_TAU2_REF, val);
+		if (idx < XSIZE(tau2_class[0]))
+			tau2_class[0](idx) = tau2_fudge_factor * val;
+	}
+	if (idx < XSIZE(tau2_class[0]) - 1)
+	{
+		if (verb > 0) std::cerr<< " Warning: provided tau2-spectrum has fewer entries ("<<idx+1<<") than needed ("<<XSIZE(tau2_class[0])<<"). Set rest to zero..."<<std::endl;
+	}
+	// Use the same spectrum for all classes
+	for (int iclass = 0; iclass < nr_classes; iclass++)
+		tau2_class[iclass] =  tau2_class[0];
+
+}
+
+// Reading images from disc
+void MlModel::readImages(FileName fn_ref, int _ori_size, Experiment &_mydata,
+			bool &do_average_unaligned, bool &do_generate_seeds, bool &refs_are_ctf_corrected)
+{
+
+	// Set some stuff
+	nr_groups = _mydata.groups.size();
+	ori_size = _ori_size;
+	double avg_norm_correction = 1.;
+
+	// Read references into memory
+	Image<double> img;
+	FileName fn_tmp;
+	if (fn_ref != "None")
+	{
+		// Read the references into memory
+		do_average_unaligned = false;
+		// If this is a STAR file, ignore nr_classes and read all references from this file
+		if (fn_ref.isStarFile())
+		{
+			MetaDataTable MDref;
+			MDref.read(fn_ref);
+			do_generate_seeds = false;
+			// ignore nr_classes from the command line, use number of entries in STAR file
+			nr_classes = 0;
+			Iref.clear();
+			FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDref)
+			{
+				MDref.getValue(EMDL_MLMODEL_REF_IMAGE, fn_tmp);
+				img.read(fn_tmp);
+				ref_dim = img().getDim();
+				if (ori_size != XSIZE(img()) || ori_size != YSIZE(img()))
+				{
+					std::cerr << " ori_size= " << ori_size << " XSIZE(img())= " << XSIZE(img()) << std::endl;
+					REPORT_ERROR("MlOptimiser::read: size of reference images is not the same as the experimental images!");
+				}
+				Iref.push_back(img());
+				nr_classes++;
+			}
+		}
+		// For a single image, read this image as reference and set it in all nr_classes Irefs
+		else
+		{
+			img.read(fn_ref);
+			ref_dim = img().getDim();
+			if (ori_size != XSIZE(img()) || ori_size != YSIZE(img()))
+			{
+				std::cerr << " ori_size= " << ori_size << " XSIZE(img())= " << XSIZE(img()) << std::endl;
+				REPORT_ERROR("MlOptimiser::read: size of reference image is not the same as the experimental images!");
+			}
+			Iref.clear();
+			for (int iclass = 0; iclass < nr_classes; iclass++)
+				Iref.push_back(img());
+			if (nr_classes > 1)
+				do_generate_seeds = true;
+			else
+				do_generate_seeds = false;
+		}
+	}
+	else
+	{
+		// If no -ref is given, assume this is a 2D refinement and calculate average of all unaligned images later on.
+		do_average_unaligned = true;
+		do_generate_seeds = true;
+		refs_are_ctf_corrected = false;
+		img().initZeros(ori_size, ori_size);
+		ref_dim = 2;
+		for (int iclass = 0; iclass < nr_classes; iclass++)
+			Iref.push_back(img());
+	}
+
+	initialise();
+
+	// Now set the group names from the Experiment groups list
+	for (int i=0; i<nr_groups; i++)
+		group_names[i] = _mydata.groups[i].name;
+
+}
+void MlModel::expandToMovieFrames(Experiment &moviedata, int running_avg_side)
+{
+	MlModel moviemodel;
+
+	// Start from all equal model (nr_classes, references etc)
+	moviemodel = (*this);
+	// Reset the average norm correction to one
+	moviemodel.avg_norm_correction = 1.;
+
+	// Then delete the current groups: their numbers, names, scale_corrections and sigma2noise spectra
+	moviemodel.nr_groups = 0;
+	moviemodel.nr_particles_group.clear();
+	moviemodel.group_names.clear();
+	moviemodel.sigma2_noise.clear();
+	moviemodel.scale_correction.clear();
+	moviemodel.bfactor_correction.clear();
+
+	// Now go and look in the (already expanded) moviedata to find the unique groups
+	for (int i=0; i<moviedata.groups.size(); i++)
+	{
+
+		FileName curr_name, movie_name;
+		movie_name = moviedata.groups[i].name;
+
+		// Find the corresponding group_name in the current model
+		int my_curr_group_nr = -1;
+		for (int j=0; j<group_names.size(); j++)
+		{
+			curr_name = group_names[j].withoutExtension();
+			// The moviename should be the current name plus something else...
+			if (movie_name.contains(curr_name))
+			{
+				my_curr_group_nr = j;
+				break;
+			}
+		}
+		if (my_curr_group_nr < 0)
+			REPORT_ERROR("MlModel::expandToMovieFrames ERROR: cannot find rlnMicrographName or rlnGroupName for movie frame: " + movie_name);
+
+		moviemodel.sigma2_noise.push_back(sigma2_noise[my_curr_group_nr]);
+		moviemodel.scale_correction.push_back(scale_correction[my_curr_group_nr]);
+		moviemodel.bfactor_correction.push_back(bfactor_correction[my_curr_group_nr]);
+		moviemodel.group_names.push_back(movie_name);
+		moviemodel.nr_groups++;
+	}
+
+	// Also find the number of particles in this group
+	moviemodel.nr_particles_group.resize(moviemodel.nr_groups);
+	std::vector<int> nr_frames_in_group;
+	nr_frames_in_group.resize(moviemodel.nr_groups, -1);
+
+	for (long int ipart = 0; ipart < moviedata.particles.size(); ipart++)
+	{
+		for (int iimg = 0; iimg < (moviedata.particles[ipart]).images.size(); iimg++)
+		{
+			long int group_id = ((moviedata.particles[ipart]).images[iimg]).group_id;
+			long int img_id = ((moviedata.particles[ipart]).images[iimg]).id;
+			// count the number of particles in this group
+			moviemodel.nr_particles_group[group_id]++;
+			// Get and check the number of frames is constant within one group
+			int nframes = -1;
+			if (!moviedata.MDimg.getValue(EMDL_PARTICLE_NR_FRAMES, nframes, img_id))
+				REPORT_ERROR("MlModel::expandToMovieFrames ERROR: cannot find rlnNrOfFrames in moviedata.");
+			if (nr_frames_in_group[group_id] < 0)
+				nr_frames_in_group[group_id] = nframes;
+			else if (nr_frames_in_group[group_id] != nframes)
+				REPORT_ERROR((std::string)"MlModel::expandToMovieFrames ERROR: unequal number of frames in group" + moviemodel.group_names[group_id]);
+		}
+	}
+
+	// Correct the input sigma2noise spectra by a factor of nframes
+	for (int i=0; i < moviemodel.nr_groups; i++)
+	{
+		moviemodel.sigma2_noise[i] *= (double)nr_frames_in_group[i]/((double)(2 * running_avg_side + 1));
+	}
+
+	// Now replace the current model with the expanded moviemodel
+	(*this) = moviemodel;
+
+}
+
+void MlModel::initialisePdfDirection(int newsize)
+{
+
+	// If the pdf_direction were already filled (size!=0), and newsize=oldsize then leave them as they were
+	// If they were still empty, or if the size changes, then initialise them with an even distribution
+	for (int iclass = 0; iclass < nr_classes; iclass++)
+	{
+		int oldsize = MULTIDIM_SIZE(pdf_direction[iclass]);
+		if (oldsize == 0 || oldsize != newsize)
+		{
+			pdf_direction[iclass].resize(newsize);
+			pdf_direction[iclass].initConstant(1./((double) nr_classes * newsize));
+		}
+	}
+	nr_directions = newsize;
+
+}
+
+void MlModel::setFourierTransformMaps(bool update_tau2_spectra, int nr_threads)
+{
+
+	for (int iclass = 0; iclass < nr_classes; iclass++)
+    {
+        if (update_tau2_spectra)
+        {
+			PPref[iclass].computeFourierTransformMap(Iref[iclass], tau2_class[iclass], current_size, nr_threads);
+        }
+        else
+        {
+        	MultidimArray<double> dummy;
+        	PPref[iclass].computeFourierTransformMap(Iref[iclass], dummy, current_size, nr_threads);
+        }
+    }
+
+}
+
+void MlModel::initialiseDataVersusPrior(bool fix_tau)
+{
+
+    // Get total number of particles
+	double nr_particles = 0.;
+	for (int igroup = 0; igroup < nr_particles_group.size(); igroup++)
+		nr_particles += (double)nr_particles_group[igroup];
+
+	// Calculate average sigma2_noise over all image groups
+	MultidimArray<double> avg_sigma2_noise;
+	avg_sigma2_noise.initZeros(sigma2_noise[0]);
+	for (int igroup = 0; igroup < nr_particles_group.size(); igroup++)
+	{
+		avg_sigma2_noise += (double)(nr_particles_group[igroup]) * sigma2_noise[igroup];
+	}
+	avg_sigma2_noise /= nr_particles;
+
+	// Get the FT of all reference structures
+    // The Fourier Transforms are all "normalised" for 2D transforms of size = ori_size x ori_size
+    // And spectrum is squared, so ori_size*ori_size in the 3D case!
+	double normfft = (ref_dim == 3) ? (double)(ori_size * ori_size) : 1.;
+
+    for (int iclass = 0; iclass < nr_classes; iclass++)
+	{
+		// Initialise output arrays to correct size
+		tau2_class[iclass].resize(sigma2_noise[0]);
+
+		// Get the power spectrum of the reference
+		MultidimArray<double> spectrum(sigma2_noise[0]);
+		getSpectrum(Iref[iclass], spectrum, POWER_SPECTRUM);
+
+		// Factor two because of two-dimensionality of the complex plane
+		// (just like sigma2_noise estimates, the power spectra should be divided by 2)
+		spectrum *= normfft / 2.;
+
+		// Update the tau2_class spectrum for this reference
+		// This is only for writing out in the it000000_model.star file
+		if (!fix_tau)
+		{
+			FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(tau2_class[iclass])
+			{
+				DIRECT_A1D_ELEM(tau2_class[iclass], i) = tau2_fudge_factor * DIRECT_A1D_ELEM(spectrum, i);
+			}
+		}
+
+		// Calculate data_vs_prior_class as spectral_nr_observations_per_class/sigma2_noise vs 1/tau2_class
+		data_vs_prior_class[iclass].resize(sigma2_noise[0]);
+		fsc_halves_class[iclass].initZeros(sigma2_noise[0]);
+		FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(tau2_class[iclass])
+		{
+			double evidence = nr_particles * pdf_class[iclass] / DIRECT_A1D_ELEM(avg_sigma2_noise, i);
+			// empirical accounting for ratio of pixels in 3D shells compared to 2D shells
+			if (ref_dim == 3 && i > 0)
+				evidence /= (2. * (double)i);
+			double prior = 1. /  DIRECT_A1D_ELEM(tau2_class[iclass], i);
+			double myssnr = evidence / prior;
+			DIRECT_A1D_ELEM(data_vs_prior_class[iclass], i ) = myssnr;
+			// Also initialise FSC-halves here (...)
+			//DIRECT_A1D_ELEM(fsc_halves_class[iclass], i ) = myssnr / (myssnr + 1);
+		}
+	} // end loop iclass
+
+}
+
+/////////// MlWsumModel
+void MlWsumModel::initialise(MlModel &_model, FileName fn_sym)
+{
+	nr_classes = _model.nr_classes;
+    nr_groups = _model.nr_groups;
+    nr_directions = _model.nr_directions;
+    ref_dim = _model.ref_dim;
+    ori_size = _model.ori_size;
+    pdf_class = _model.pdf_class;
+    if (ref_dim == 2)
+    	prior_offset_class = _model.prior_offset_class;
+    pdf_direction = _model.pdf_direction;
+    sigma2_offset = _model.sigma2_offset;
+    sigma2_noise = _model.sigma2_noise;
+    sigma2_rot = _model.sigma2_rot;
+    sigma2_tilt = _model.sigma2_tilt;
+    sigma2_psi = _model.sigma2_psi;
+    padding_factor = _model.padding_factor;
+    interpolator = _model.interpolator;
+    r_min_nn = _model.r_min_nn;
+
+    // Don't need forward projectors in MlWsumModel!
+    PPref.clear();
+    // Don't need scale_correction and bfactor_correction, keep wsum_signal_product_spectra and wsum_reference_power_spectra instead
+    scale_correction.clear();
+    bfactor_correction.clear();
+    tau2_class.clear();
+    data_vs_prior_class.clear();
+	acc_rot.clear();
+	acc_trans.clear();
+    orientability_contrib.clear();
+
+
+    MultidimArray<double> aux(ori_size / 2 + 1);
+    wsum_signal_product_spectra.resize(nr_groups, aux);
+    wsum_reference_power_spectra.resize(nr_groups, aux);
+
+    // Resize MlWsumModel-specific vectors
+    BackProjector BP(ori_size, ref_dim, fn_sym, interpolator, padding_factor, r_min_nn,
+    		         ML_BLOB_ORDER, ML_BLOB_RADIUS, ML_BLOB_ALPHA);
+    BPref.clear();
+    BPref.resize(nr_classes, BP);
+    sumw_group.resize(nr_groups);
+
+}
+
+void MlWsumModel::initZeros()
+{
+
+    LL = 0.;
+    ave_Pmax = 0.;
+    sigma2_offset = 0.;
+    avg_norm_correction = 0.;
+    sigma2_rot = 0.;
+    sigma2_tilt = 0.;
+    sigma2_psi = 0.;
+
+    // Set all weighted sums to zero
+    for (int iclass = 0; iclass < nr_classes; iclass++)
+    {
+    	BPref[iclass].initZeros(current_size);
+        pdf_class[iclass] = 0.;
+        // Assume pdf_direction is already of the right size...
+        pdf_direction[iclass].initZeros();
+        if (ref_dim == 2)
+        	prior_offset_class[iclass].initZeros();
+    }
+
+    // Initialise sigma2_noise spectra and sumw_group
+    for (int igroup = 0; igroup < nr_groups; igroup++)
+    {
+        sumw_group[igroup] = 0.;
+        sigma2_noise[igroup].initZeros();
+        wsum_signal_product_spectra[igroup].initZeros();
+        wsum_reference_power_spectra[igroup].initZeros();
+    }
+}
+
+//#define DEBUG_PACK
+#ifdef DEBUG_PACK
+#define MAX_PACK_SIZE     100000
+#else
+// Approximately 1024*1024*1024/8/2 ~ 0.5 Gb
+#define MAX_PACK_SIZE 671010000
+#endif
+
+void MlWsumModel::pack(MultidimArray<double> &packed)
+{
+	// for LL & avePmax & sigma2_offset & avg_norm_correction & sigma2_rot & sigma2_tilt & sigma2_psi
+	long long int packed_size = 0;
+    int spectral_size = (ori_size / 2) + 1;
+
+    packed_size += 7 ;
+    // for all group-related stuff
+    packed_size += nr_groups * spectral_size;
+    packed_size += nr_groups * spectral_size;
+    packed_size += nr_groups * spectral_size;
+    // for sumw_group
+    packed_size += nr_groups;
+    // for all class-related stuff
+    // data is complex: multiply by two!
+    packed_size += nr_classes * 2 * BPref[0].getSize();
+    packed_size += nr_classes * BPref[0].getSize();
+    packed_size += nr_classes * nr_directions;
+    // for pdf_class
+    packed_size += nr_classes;
+    // for priors for each class
+    if (ref_dim==2)
+    	packed_size += nr_classes*2;
+
+    // Get memory for the packed array
+    packed.clear();
+    packed.resize(packed_size);
+
+    // Start packing
+    long long int idx = 0;
+
+    DIRECT_MULTIDIM_ELEM(packed, idx++) = LL;
+    DIRECT_MULTIDIM_ELEM(packed, idx++) = ave_Pmax;
+    DIRECT_MULTIDIM_ELEM(packed, idx++) = sigma2_offset;
+    DIRECT_MULTIDIM_ELEM(packed, idx++) = avg_norm_correction;
+    DIRECT_MULTIDIM_ELEM(packed, idx++) = sigma2_rot;
+    DIRECT_MULTIDIM_ELEM(packed, idx++) = sigma2_tilt;
+    DIRECT_MULTIDIM_ELEM(packed, idx++) = sigma2_psi;
+
+    for (int igroup = 0; igroup < nr_groups; igroup++)
+    {
+    	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(sigma2_noise[igroup])
+        {
+            DIRECT_MULTIDIM_ELEM(packed, idx++) =DIRECT_MULTIDIM_ELEM(sigma2_noise[igroup], n);
+        }
+    	sigma2_noise[igroup].clear();
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(wsum_signal_product_spectra[igroup])
+        {
+        	DIRECT_MULTIDIM_ELEM(packed, idx++) =DIRECT_MULTIDIM_ELEM(wsum_signal_product_spectra[igroup], n);
+        }
+        wsum_signal_product_spectra[igroup].clear();
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(wsum_reference_power_spectra[igroup])
+        {
+            DIRECT_MULTIDIM_ELEM(packed, idx++) =DIRECT_MULTIDIM_ELEM(wsum_reference_power_spectra[igroup], n);
+        }
+        wsum_reference_power_spectra[igroup].clear();
+
+        DIRECT_MULTIDIM_ELEM(packed, idx++) = sumw_group[igroup];
+
+    }
+    for (int iclass = 0; iclass < nr_classes; iclass++)
+    {
+
+    	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(BPref[iclass].data)
+        {
+            DIRECT_MULTIDIM_ELEM(packed, idx++) = (DIRECT_MULTIDIM_ELEM(BPref[iclass].data, n)).real;
+            DIRECT_MULTIDIM_ELEM(packed, idx++) = (DIRECT_MULTIDIM_ELEM(BPref[iclass].data, n)).imag;
+        }
+    	BPref[iclass].data.clear();
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(BPref[iclass].weight)
+        {
+            DIRECT_MULTIDIM_ELEM(packed, idx++) = DIRECT_MULTIDIM_ELEM(BPref[iclass].weight, n);
+        }
+        BPref[iclass].weight.clear();
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(pdf_direction[iclass])
+        {
+            DIRECT_MULTIDIM_ELEM(packed, idx++) = DIRECT_MULTIDIM_ELEM(pdf_direction[iclass], n);
+        }
+        pdf_direction[iclass].clear();
+
+        DIRECT_MULTIDIM_ELEM(packed, idx++) = pdf_class[iclass];
+
+        if (ref_dim==2)
+        {
+        	DIRECT_MULTIDIM_ELEM(packed, idx++) = XX(prior_offset_class[iclass]);
+        	DIRECT_MULTIDIM_ELEM(packed, idx++) = YY(prior_offset_class[iclass]);
+        }
+    }
+#ifdef DEBUG_PACK
+    std::cerr << " idx= " << idx << " packed_size= " << packed_size << std::endl;
+#endif
+
+    // Just to check whether we went outside our memory...
+    if (idx != packed_size)
+    {
+       	std::cerr << "idx= " << idx << "packed_size= " << packed_size << std::endl;
+        REPORT_ERROR("MlWsumModel::pack: idx != packed_size");
+    }
+
+}
+void MlWsumModel::unpack(MultidimArray<double> &packed)
+{
+    int spectral_size = (ori_size / 2) + 1;
+
+    long long int idx = 0;
+
+    LL = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    ave_Pmax = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    sigma2_offset = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    avg_norm_correction = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    sigma2_rot = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    sigma2_tilt = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    sigma2_psi = DIRECT_MULTIDIM_ELEM(packed, idx++);
+
+    for (int igroup = 0; igroup < nr_groups; igroup++)
+    {
+    	sigma2_noise[igroup].resize(spectral_size);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(sigma2_noise[igroup])
+        {
+        	DIRECT_MULTIDIM_ELEM(sigma2_noise[igroup], n) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        }
+        wsum_signal_product_spectra[igroup].resize(spectral_size);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(wsum_signal_product_spectra[igroup])
+        {
+        	DIRECT_MULTIDIM_ELEM(wsum_signal_product_spectra[igroup], n) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        }
+        wsum_reference_power_spectra[igroup].resize(spectral_size);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(wsum_reference_power_spectra[igroup])
+        {
+        	DIRECT_MULTIDIM_ELEM(wsum_reference_power_spectra[igroup], n) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        }
+        sumw_group[igroup] = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    }
+
+    for (int iclass = 0; iclass < nr_classes; iclass++)
+    {
+    	BPref[iclass].initialiseDataAndWeight(current_size);
+    	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(BPref[iclass].data)
+        {
+    		(DIRECT_MULTIDIM_ELEM(BPref[iclass].data, n)).real = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    		(DIRECT_MULTIDIM_ELEM(BPref[iclass].data, n)).imag = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        }
+    	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(BPref[iclass].weight)
+        {
+    		DIRECT_MULTIDIM_ELEM(BPref[iclass].weight, n) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        }
+    	pdf_direction[iclass].resize(nr_directions);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(pdf_direction[iclass])
+        {
+        	DIRECT_MULTIDIM_ELEM(pdf_direction[iclass], n) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        }
+        pdf_class[iclass] = DIRECT_MULTIDIM_ELEM(packed, idx++);
+
+        if (ref_dim==2)
+        {
+        	XX(prior_offset_class[iclass]) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        	YY(prior_offset_class[iclass]) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        }
+    }
+
+    long long int packed_size = MULTIDIM_SIZE(packed);
+    packed.clear();
+
+    // Just to check whether we went outside our memory...
+    if (idx != packed_size)
+    {
+       	std::cerr << "idx= " << idx << " packed_size= " << packed_size << std::endl;
+        REPORT_ERROR("MlWsumModel::unpack: idx != idx_stop-idx_start");
+    }
+}
+
+
+void MlWsumModel::pack(MultidimArray<double> &packed, int &piece, int &nr_pieces, bool do_clear)
+{
+
+
+    // Determine size of the packed array
+    int nr_groups = sigma2_noise.size();
+    int nr_classes = BPref.size();
+    int spectral_size = (ori_size / 2) + 1;
+    long long int packed_size = 0;
+    long long int idx_start, idx_stop;
+
+	// for LL & avePmax & sigma2_offset & avg_norm_correction & sigma2_rot & sigma2_tilt & sigma2_psi
+    packed_size += 7 ;
+    // for all group-related stuff
+    packed_size += nr_groups * spectral_size;
+    packed_size += nr_groups * spectral_size;
+    packed_size += nr_groups * spectral_size;
+    // for sumw_group
+    packed_size += nr_groups;
+    // for all class-related stuff
+    // data is complex: multiply by two!
+    packed_size += nr_classes * 2 * BPref[0].getSize();
+    packed_size += nr_classes * BPref[0].getSize();
+    packed_size += nr_classes * nr_directions;
+    // for pdf_class
+    packed_size += nr_classes;
+    // for priors for each class
+    if (ref_dim==2)
+    	packed_size += nr_classes*2;
+
+    if (piece < 0 && nr_pieces < 0)
+    {
+    	// Special case: prevent making multiple pieces if input piece and nr_pieces are both negative
+        idx_start = 0;
+        idx_stop = packed_size;
+    }
+    else if (packed_size > MAX_PACK_SIZE)
+    {
+        idx_start = piece * MAX_PACK_SIZE;
+        idx_stop = XMIPP_MIN(idx_start + MAX_PACK_SIZE, packed_size);
+        nr_pieces = CEIL((double)packed_size/(double)MAX_PACK_SIZE);
+    }
+    else
+    {
+        idx_start = 0;
+        idx_stop = packed_size;
+        nr_pieces = 1;
+    }
+
+    // increment piece so that pack will be called again
+    piece++;
+#ifdef DEBUG_PACK
+    std::cerr << " PACK: idx_start= " << idx_start << " idx_stop= " << idx_stop << " piece= " << piece << " nr_pieces= " << nr_pieces <<" packed_size= "<<packed_size<< std::endl;
+    std::cerr << " nr_classes= " << nr_classes << " nr_groups= " << nr_groups << " packed_size= " << packed_size << std::endl;
+    std::cerr << " MULTIDIM_SIZE(sigma2_noise[0])= " << MULTIDIM_SIZE(sigma2_noise[0]) << " MULTIDIM_SIZE(wsum_signal_product_spectra[0])= " << MULTIDIM_SIZE(wsum_signal_product_spectra[0]) << " MULTIDIM_SIZE(wsum_reference_power_spectra[0])= " << MULTIDIM_SIZE(wsum_reference_power_spectra[0]) << std::endl;
+    std::cerr << " sigma2_noise.size()= " << sigma2_noise.size() << " wsum_signal_product_spectra.size()= " << wsum_signal_product_spectra.size() << " wsum_signal_product_spectra.size()= " << wsum_signal_product_spectra.size() << std::endl;
+    std::cerr << " MULTIDIM_SIZE(pdf_direction[0])= " << MULTIDIM_SIZE(pdf_direction[0]) << " pdf_direction.size()= " << pdf_direction.size()<<std::endl;
+#endif
+
+    // Get memory for the packed array
+    packed.clear();
+    packed.resize(idx_stop - idx_start);
+
+    long long int idx = 0;
+    long long int ori_idx = 0;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = LL;
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = ave_Pmax;
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = sigma2_offset;
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = avg_norm_correction;
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = sigma2_rot;
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = sigma2_tilt;
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = sigma2_psi;
+    ori_idx++;
+
+    for (int igroup = 0; igroup < nr_groups; igroup++)
+    {
+    	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(sigma2_noise[igroup])
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) =DIRECT_MULTIDIM_ELEM(sigma2_noise[igroup], n);
+            ori_idx++;
+        }
+    	if (idx == ori_idx && do_clear)
+            sigma2_noise[igroup].clear();
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(wsum_signal_product_spectra[igroup])
+        {
+        	if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) =DIRECT_MULTIDIM_ELEM(wsum_signal_product_spectra[igroup], n);
+        	ori_idx++;
+        }
+        if (idx == ori_idx && do_clear)
+            wsum_signal_product_spectra[igroup].clear();
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(wsum_reference_power_spectra[igroup])
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) =DIRECT_MULTIDIM_ELEM(wsum_reference_power_spectra[igroup], n);
+            ori_idx++;
+        }
+        if (idx == ori_idx && do_clear)
+            wsum_reference_power_spectra[igroup].clear();
+
+        if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = sumw_group[igroup];
+        ori_idx++;
+
+    }
+    for (int iclass = 0; iclass < nr_classes; iclass++)
+    {
+
+    	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(BPref[iclass].data)
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = (DIRECT_MULTIDIM_ELEM(BPref[iclass].data, n)).real;
+            ori_idx++;
+            if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = (DIRECT_MULTIDIM_ELEM(BPref[iclass].data, n)).imag;
+            ori_idx++;
+        }
+        // Only clear after the whole array has been packed... i.e. not when we reached the pack_size halfway through
+        if (idx == ori_idx && do_clear)
+            BPref[iclass].data.clear();
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(BPref[iclass].weight)
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = DIRECT_MULTIDIM_ELEM(BPref[iclass].weight, n);
+            ori_idx++;
+        }
+        if (idx == ori_idx && do_clear)
+            BPref[iclass].weight.clear();
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(pdf_direction[iclass])
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = DIRECT_MULTIDIM_ELEM(pdf_direction[iclass], n);
+            ori_idx++;
+        }
+        if (idx == ori_idx && do_clear)
+        	pdf_direction[iclass].clear();
+
+        if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = pdf_class[iclass];
+        ori_idx++;
+
+        if (ref_dim==2)
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = XX(prior_offset_class[iclass]);
+            ori_idx++;
+            if (ori_idx >= idx_start && ori_idx < idx_stop) DIRECT_MULTIDIM_ELEM(packed, idx++) = YY(prior_offset_class[iclass]);
+            ori_idx++;
+        }
+    }
+#ifdef DEBUG_PACK
+    std::cerr << " idx= " << idx << " packed_size= " << packed_size << std::endl;
+#endif
+
+    // Just to check whether we went outside our memory...
+    //std::cerr << " PACK piece= " << piece-1 << " nr_pieces= " << nr_pieces << " ori_idx= " << ori_idx<< " packed_size= " << packed_size << std::endl;
+    //std::cerr << " PACK idx= " << idx << " idx_stop-idx_start= " << idx_stop-idx_start << " idx_start= " << idx_start << " idx_stop= " << idx_stop    << std::endl;
+    if (idx != idx_stop-idx_start)
+    {
+       	std::cerr << "idx= " << idx << "ori_idx= " << ori_idx << " idx_start= " << idx_start << " idx_stop= " << idx_stop << " packed_size= " << packed_size << std::endl;
+        REPORT_ERROR("MlWsumModel::pack: idx != idx_stop-idx_start");
+
+    }
+
+}
+
+void MlWsumModel::unpack(MultidimArray<double> &packed, int piece, bool do_clear)
+{
+
+
+    int nr_groups = sigma2_noise.size();
+    int nr_classes = BPref.size();
+    int spectral_size = (ori_size / 2) + 1;
+    long long int idx_start;
+    long long int idx_stop;
+    if (piece < 0)
+    {
+    	// Special case: prevent making multiple pieces if input piece is negative
+        idx_start = 0;
+        idx_stop  = MULTIDIM_SIZE(packed);
+    }
+    else
+    {
+    	idx_start = piece * MAX_PACK_SIZE;
+    	idx_stop  = idx_start + MULTIDIM_SIZE(packed);
+    }
+    long long int ori_idx = 0;
+    long long int idx = 0;
+#ifdef DEBUG_PACK
+    std::cerr << " UNPACK piece= " << piece << " idx_start= " << idx_start << " idx_stop= " << idx_stop << std::endl;
+#endif
+
+    if (ori_idx >= idx_start && ori_idx < idx_stop) LL = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) ave_Pmax = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) sigma2_offset = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) avg_norm_correction = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) sigma2_rot = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) sigma2_tilt = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    ori_idx++;
+    if (ori_idx >= idx_start && ori_idx < idx_stop) sigma2_psi = DIRECT_MULTIDIM_ELEM(packed, idx++);
+    ori_idx++;
+
+    for (int igroup = 0; igroup < nr_groups; igroup++)
+    {
+
+    	if (idx == ori_idx)
+    		sigma2_noise[igroup].resize(spectral_size);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(sigma2_noise[igroup])
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop)
+            	DIRECT_MULTIDIM_ELEM(sigma2_noise[igroup], n) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+            ori_idx++;
+        }
+
+        if (idx == ori_idx)
+    		wsum_signal_product_spectra[igroup].resize(spectral_size);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(wsum_signal_product_spectra[igroup])
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop)
+            	DIRECT_MULTIDIM_ELEM(wsum_signal_product_spectra[igroup], n) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+            ori_idx++;
+        }
+
+        if (idx == ori_idx)
+    		wsum_reference_power_spectra[igroup].resize(spectral_size);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(wsum_reference_power_spectra[igroup])
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop)
+            	DIRECT_MULTIDIM_ELEM(wsum_reference_power_spectra[igroup], n) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+            ori_idx++;
+        }
+
+        if (ori_idx >= idx_start && ori_idx < idx_stop)
+        	sumw_group[igroup] = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        ori_idx++;
+
+    }
+
+    for (int iclass = 0; iclass < nr_classes; iclass++)
+    {
+    	if (idx == ori_idx)
+    		BPref[iclass].initialiseDataAndWeight(current_size);
+
+    	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(BPref[iclass].data)
+        {
+        	if (ori_idx >= idx_start && ori_idx < idx_stop)
+				(DIRECT_MULTIDIM_ELEM(BPref[iclass].data, n)).real = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        	ori_idx++;
+
+        	if (ori_idx >= idx_start && ori_idx < idx_stop)
+            	(DIRECT_MULTIDIM_ELEM(BPref[iclass].data, n)).imag = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        	ori_idx++;
+            //DIRECT_MULTIDIM_ELEM(BPref[iclass].data, n) = Complex(re, im);
+        }
+
+    	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(BPref[iclass].weight)
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop)
+				DIRECT_MULTIDIM_ELEM(BPref[iclass].weight, n) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+            ori_idx++;
+        }
+
+    	if (idx == ori_idx)
+    		pdf_direction[iclass].resize(nr_directions);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(pdf_direction[iclass])
+        {
+            if (ori_idx >= idx_start && ori_idx < idx_stop)
+				DIRECT_MULTIDIM_ELEM(pdf_direction[iclass], n) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+            ori_idx++;
+        }
+
+        if (ori_idx >= idx_start && ori_idx < idx_stop)
+        	pdf_class[iclass] = DIRECT_MULTIDIM_ELEM(packed, idx++);
+        ori_idx++;
+
+        if (ref_dim == 2)
+        {
+			if (ori_idx >= idx_start && ori_idx < idx_stop)
+				XX(prior_offset_class[iclass]) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+			ori_idx++;
+			if (ori_idx >= idx_start && ori_idx < idx_stop)
+				YY(prior_offset_class[iclass]) = DIRECT_MULTIDIM_ELEM(packed, idx++);
+			ori_idx++;
+        }
+    }
+
+
+    long long int packed_size = MULTIDIM_SIZE(packed);
+    // Free memory
+    if (do_clear)
+        packed.clear();
+
+    // Just to check whether we went outside our memory...
+    //std::cerr << " UNPACK piece= " << piece << " idx= " << idx << " idx_stop-idx_start= " << idx_stop-idx_start << " idx_start= " << idx_start << " idx_stop= " << idx_stop    << std::endl;
+    if (idx != idx_stop-idx_start)
+    {
+       	std::cerr << "idx= " << idx << "ori_idx= " << ori_idx << " idx_start= " << idx_start << " idx_stop= " << idx_stop << " packed_size= " << packed_size << std::endl;
+        REPORT_ERROR("MlWsumModel::unpack: idx != idx_stop-idx_start");
+    }
+
+
+}
+
+
+
diff --git a/src/ml_model.h b/src/ml_model.h
new file mode 100644
index 0000000..c232484
--- /dev/null
+++ b/src/ml_model.h
@@ -0,0 +1,293 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef ML_MODEL_H_
+#define ML_MODEL_H_
+#include "src/projector.h"
+#include "src/backprojector.h"
+#include "src/metadata_table.h"
+#include "src/exp_model.h"
+#include "src/healpix_sampling.h"
+
+#define ML_BLOB_ORDER 0
+#define ML_BLOB_RADIUS 1.9
+#define ML_BLOB_ALPHA 15
+
+class MlModel
+{
+public:
+
+	// Dimension of the references (2D or 3D)
+	int ref_dim;
+
+	// Original size of the images
+	int ori_size;
+
+	// Pixel size (in Angstrom)
+	double pixel_size;
+
+	// Current size of the images to be used in the expectation
+	int current_size;
+
+	// Current resolution (in 1/Ang)
+	double current_resolution;
+
+	// Number of classes
+	int nr_classes;
+
+	// Number of image groups with separate sigma2_noise spectra
+	int nr_groups;
+
+	// Number of particles in each group
+	std::vector<long int> nr_particles_group;
+
+	// Number of directions (size of pdf_direction);
+	int nr_directions;
+
+	// Log-likelihood target value
+	double LL;
+
+	// Padding factor
+	int padding_factor;
+
+	// Fourier space interpolator
+	int interpolator;
+
+	// Minimum number of shells to perform linear interpolation
+	int r_min_nn;
+
+	// Average Pmax of the normalised probability distributions
+	double ave_Pmax;
+
+	// Average normalisation correction factor
+	double avg_norm_correction;
+
+	// Variance in the origin offsets
+	double sigma2_offset;
+
+	// Fudge factor to adjust estimated tau2_class spectra
+	double tau2_fudge_factor;
+
+	// Vector with all reference images
+	std::vector<MultidimArray<double> > Iref;
+
+	// One projector for each class;
+	std::vector<Projector > PPref;
+
+	// One name for each group
+	std::vector<FileName> group_names;
+
+	// One noise spectrum for each group
+	std::vector<MultidimArray<double > > sigma2_noise;
+
+	// One intensity scale for each group
+	std::vector<double> scale_correction;
+
+	// One intensity B-factor for each group
+	std::vector<double> bfactor_correction;
+
+	// Prior information: one restrained power_class spectrum for each class (inverse of right-hand side in Wiener-filter-like update formula)
+	std::vector<MultidimArray<double > > tau2_class;
+
+	// Radial average of the estimated variance in the reconstruction (inverse of left-hand side in Wiener-filter-like update formula)
+	std::vector<MultidimArray<double > > sigma2_class;
+
+	// FSC spectra between random halves of the data
+	std::vector<MultidimArray<double > > fsc_halves_class;
+
+	// One likelihood vs prior ratio spectrum for each class
+	std::vector<MultidimArray<double > > data_vs_prior_class;
+
+	// One value for each class
+	std::vector<double > pdf_class;
+
+	// One array for each class
+	std::vector<MultidimArray<double> > pdf_direction;
+
+	// Priors for offsets for each class (only in 2D)
+	std::vector<Matrix1D<double> > prior_offset_class;
+
+	// Mode for orientational prior distributions
+	int orientational_prior_mode;
+
+	// Variance in rot angle for the orientational pdf
+	double sigma2_rot;
+
+	// Variance in tilt angle for the orientational pdf
+	double sigma2_tilt;
+
+	// Variance in psi angle for the orientational pdf
+	double sigma2_psi;
+
+	// Estimated accuracy at which rotations can be assigned, one for each class
+	std::vector<double> acc_rot;
+
+	// Estimated accuracy at which translations can be assigned, one for each class
+	std::vector<double> acc_trans;
+
+	// Spectral contribution to orientability of individual particles, one for each class
+	std::vector<MultidimArray<double > > orientability_contrib;
+
+
+public:
+
+	// Constructor
+	MlModel()
+	{
+		clear();
+	}
+
+	// Destructor
+	~MlModel()
+	{
+		clear();
+	}
+
+	// Clear everything
+	void clear()
+	{
+		Iref.clear();
+		PPref.clear();
+		group_names.clear();
+		sigma2_noise.clear();
+		scale_correction.clear();
+		bfactor_correction.clear();
+		tau2_class.clear();
+		fsc_halves_class.clear();
+		sigma2_class.clear();
+		data_vs_prior_class.clear();
+		pdf_class.clear();
+		pdf_direction.clear();
+		nr_particles_group.clear();
+		ref_dim = ori_size = nr_classes = nr_groups = nr_directions = interpolator = r_min_nn = padding_factor = 0;
+		ave_Pmax = avg_norm_correction = LL = sigma2_offset = tau2_fudge_factor = 0.;
+		sigma2_rot = sigma2_tilt = sigma2_psi = 0.;
+		acc_rot.clear();
+		acc_trans.clear();
+		orientability_contrib.clear();
+	}
+
+	// Initialise vectors with the right size
+	void initialise();
+
+	//Read a model from a file
+	void read(FileName fn_in);
+
+	// Write a model to disc
+	void write(FileName fn_out, HealpixSampling &sampling);
+
+	//Read a tau-spectrum from a STAR file
+	void readTauSpectrum(FileName fn_tau, int verb);
+
+	// Read images from disc and initialise
+	// Also set do_average_unaligned and do_generate_seeds flags
+	void readImages(FileName fn_ref, int _ori_size, Experiment &_mydata,
+			bool &do_average_unaligned, bool &do_generate_seeds, bool &refs_are_ctf_corrected);
+
+	// Given the Experiment of the already expanded dataset of movieframes, expand the current MlModel to contain all movie frames
+	// Make a new group for each unique rlnGroupName in the expanded Experiment, copying the values from the groups in the current MlModel
+	// For that: remove "00000i@" as well as movie extension from the rlnGroupName in the expanded Experiment and compare with group_names in current MlModel
+	void expandToMovieFrames(Experiment &moviedataexpand, int running_avg_side);
+
+	double getResolution(int ipix)	{ return (double)ipix/(pixel_size * ori_size); }
+
+	double getResolutionAngstrom(int ipix)	{ return (ipix==0) ? 999. : (pixel_size * ori_size)/(double)ipix; }
+
+	int getPixelFromResolution(double resol)	{ return (int)(resol * pixel_size * ori_size); }
+
+	/** Initialise pdf_orient arrays to the given size
+	* If the pdf_orient vectors were empty, resize them to the given size and initialise with an even distribution
+	* If they were not empty, check that the new size is equal to the old one, and otherwise throw an exception
+	* because one cannot use an old pdf_orient with size unequal to the new one
+	*/
+	void initialisePdfDirection(int newsize);
+
+	// Set FourierTransforms in Projector of each class
+	// current_size will determine the size of the transform (in number of Fourier shells) to be held in the projector
+	void setFourierTransformMaps(bool update_tau2_spectra, int nr_threads = 1);
+
+	/* Initialises the radial average of the data-versus-prior ratio
+	 */
+	void initialiseDataVersusPrior(bool fix_tau);
+
+};
+
+class MlWsumModel: public MlModel
+{
+public:
+	// One backprojector for CTF-corrected estimate of each class;
+	std::vector<BackProjector > BPref;
+
+	// Store the sum of the weights inside each group
+	// That is the number of particles inside each group
+	std::vector<double> sumw_group;
+
+	// For the refinement of group intensity scales and bfactors
+	// For each group store weighted sums of experimental image times reference image as a function of resolution
+	std::vector<MultidimArray<double > > wsum_signal_product_spectra;
+
+	// For each group store weighted sums of squared reference as a function of resolution
+	std::vector<MultidimArray<double > > wsum_reference_power_spectra;
+
+	// Constructor
+	MlWsumModel()
+	{
+		clear();
+	}
+
+	// Destructor
+	~MlWsumModel()
+	{
+		clear();
+	}
+
+	// Clear everything
+	void clear()
+	{
+		BPref.clear();
+		sumw_group.clear();
+		MlModel::clear();
+	}
+
+	// Initialise all weighted sums (according to size of corresponding model
+	void initialise(MlModel &_model, FileName fn_sym = "c1");
+
+	// Initialize all weighted sums to zero (with resizing the BPrefs to current_size)
+	void initZeros();
+
+	// Pack entire structure into one large MultidimArray<double> for reading/writing to disc
+	// To save memory, the model itself will be cleared after packing.
+	void pack(MultidimArray<double> &packed);
+
+	// Fill the model again using unpack (this is the inverse operation from pack)
+	void unpack(MultidimArray<double> &packed);
+
+	// Pack entire structure into one large MultidimArray<double> for shipping over with MPI
+	// To save memory, the model itself will be cleared after packing.
+    // If the whole thing becomes bigger than 1Gb (see MAX_PACK_SIZE in ml_model.cpp), then break it up into pieces because MPI cannot handle very large messages
+	// When broken up: nr_pieces > 1
+	void pack(MultidimArray<double> &packed, int &piece, int &nr_pieces, bool do_clear=true);
+
+	// Fill the model again using unpack (this is the inverse operation from pack)
+	void unpack(MultidimArray<double> &packed, int piece, bool do_clear=true);
+
+};
+
+#endif /* ML_MODEL_H_ */
diff --git a/src/ml_optimiser.cpp b/src/ml_optimiser.cpp
new file mode 100644
index 0000000..f49f3a0
--- /dev/null
+++ b/src/ml_optimiser.cpp
@@ -0,0 +1,5784 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/ml_optimiser.h"
+//#define DEBUG
+//#define DEBUG_CHECKSIZES
+//#define CHECKSIZES
+//Some global threads management variables
+Mutex global_mutex, global_mutex2;
+Barrier * global_barrier;
+ThreadManager * global_ThreadManager;
+
+
+// Global functions to work with threads
+void globalGetFourierTransformsAndCtfs(ThreadArgument &thArg)
+{
+	((MlOptimiser*)thArg.workClass)->doThreadGetFourierTransformsAndCtfs(thArg.thread_id);
+}
+
+void globalThreadPrecalculateShiftedImagesCtfsAndInvSigma2s(ThreadArgument &thArg)
+{
+	((MlOptimiser*)thArg.workClass)->doThreadPrecalculateShiftedImagesCtfsAndInvSigma2s(thArg.thread_id);
+}
+
+void globalThreadGetSquaredDifferencesAllOrientations(ThreadArgument &thArg)
+{
+	((MlOptimiser*)thArg.workClass)->doThreadGetSquaredDifferencesAllOrientations(thArg.thread_id);
+}
+
+void globalThreadConvertSquaredDifferencesToWeightsAllOrientations(ThreadArgument &thArg)
+{
+	((MlOptimiser*)thArg.workClass)->doThreadConvertSquaredDifferencesToWeightsAllOrientations(thArg.thread_id);
+}
+
+void globalThreadStoreWeightedSumsAllOrientations(ThreadArgument &thArg)
+{
+	((MlOptimiser*)thArg.workClass)->doThreadStoreWeightedSumsAllOrientations(thArg.thread_id);
+}
+
+
+/** ========================== I/O operations  =========================== */
+
+
+void MlOptimiser::usage()
+{
+
+	parser.writeUsage(std::cerr);
+}
+
+void MlOptimiser::read(int argc, char **argv, int rank)
+{
+//#define DEBUG_READ
+
+	parser.setCommandLine(argc, argv);
+
+	if (checkParameter(argc, argv, "--continue"))
+	{
+		parser.addSection("Continue options");
+		FileName fn_in = parser.getOption("--continue", "_optimiser.star file of the iteration after which to continue");
+		// Read in previously calculated parameters
+		if (fn_in != "")
+			read(fn_in, rank);
+		// And look for additional command-line options...
+		parseContinue(argc, argv);
+	}
+	else
+	{
+		// Start a new run from scratch
+		parseInitial(argc, argv);
+	}
+
+}
+
+void MlOptimiser::parseContinue(int argc, char **argv)
+{
+#ifdef DEBUG
+	std::cerr << "Entering parseContinue" << std::endl;
+#endif
+
+	int general_section = parser.addSection("General options");
+	// Not all parameters are accessible here...
+	FileName fn_out_new = parser.getOption("--o", "Output rootname", "OLD_ctX");
+	if (fn_out_new == "OLD_ctX" || fn_out_new == fn_out )
+		fn_out += "_ct" + integerToString(iter);
+	else
+		fn_out = fn_out_new;
+
+	std::string fnt;
+	fnt = parser.getOption("--iter", "Maximum number of iterations to perform", "OLD");
+	if (fnt != "OLD")
+		nr_iter = textToInteger(fnt);
+
+	fnt = parser.getOption("--tau2_fudge", "Regularisation parameter (values higher than 1 give more weight to the data)", "OLD");
+	if (fnt != "OLD")
+		mymodel.tau2_fudge_factor = textToFloat(fnt);
+
+	// Solvent flattening
+	if (parser.checkOption("--flatten_solvent", "Switch on masking on the references?", "OLD"))
+		do_solvent = true;
+
+	// Check whether the mask has changed
+	fnt = parser.getOption("--solvent_mask", "User-provided mask for the references", "OLD");
+	if (fnt != "OLD")
+		fn_mask = fnt;
+
+	// Check whether the secondary mask has changed
+	fnt = parser.getOption("--solvent_mask2", "User-provided secondary mask", "OLD");
+	if (fnt != "OLD")
+		fn_mask2 = fnt;
+
+	// Check whether tau2-spectrum has changed
+	fnt = parser.getOption("--tau", "STAR file with input tau2-spectrum (to be kept constant)", "OLD");
+	if (fnt != "OLD")
+		fn_tau = fnt;
+
+	// Check whether particle diameter has changed
+	fnt = parser.getOption("--particle_diameter", "Diameter of the circular mask that will be applied to the experimental images (in Angstroms)", "OLD");
+	if (fnt != "OLD")
+		particle_diameter = textToFloat(fnt);
+
+	// Check whether to join the random halves again
+	do_join_random_halves = parser.checkOption("--join_random_halves", "Join previously split random halves again (typically to perform a final reconstruction).");
+
+	// Re-align movie frames
+	int movie_section = parser.addSection("Re-align movie frames");
+
+	fn_data_movie = parser.getOption("--realign_movie_frames", "Input STAR file with the movie frames", "");
+
+	// TODO: add this to EMDL_OPTIMISER and read/write of optimiser.star
+	nr_frames_per_prior = textToInteger(parser.getOption("--nr_frames_prior", "Number of movie frames to calculate running-average priors", "5"));
+
+	// (integer-) divide running average width by 2 to have the side only
+	// TODO: add this to EMDL_OPTIMISER and read/write of optimiser.star
+	movie_frame_running_avg_side = textToInteger(parser.getOption("--movie_frames_running_avg", "Number of movie frames in each running average", "3")) / 2;
+
+	// ORIENTATIONS
+	int orientations_section = parser.addSection("Orientations");
+
+	fnt = parser.getOption("--oversampling", "Adaptive oversampling order to speed-up calculations (0=no oversampling, 1=2x, 2=4x, etc)", "OLD");
+	if (fnt != "OLD")
+		adaptive_oversampling = textToInteger(fnt);
+
+	// Check whether angular sampling has changed
+	// Do not do this for auto_refine, but make sure to do this when realigning movies!
+	if (!do_auto_refine || fn_data_movie != "")
+	{
+		directions_have_changed = false;
+		fnt = parser.getOption("--healpix_order", "Healpix order for the angular sampling rate on the sphere (before oversampling): hp2=15deg, hp3=7.5deg, etc", "OLD");
+		if (fnt != "OLD")
+		{
+			int _order = textToInteger(fnt);
+			if (_order != sampling.healpix_order)
+			{
+				directions_have_changed = true;
+				sampling.healpix_order = _order;
+			}
+		}
+
+		fnt = parser.getOption("--psi_step", "Angular sampling (before oversampling) for the in-plane angle (default=10deg for 2D, hp sampling for 3D)", "OLD");
+		if (fnt != "OLD")
+			sampling.psi_step = textToFloat(fnt);
+
+		fnt = parser.getOption("--offset_range", "Search range for origin offsets (in pixels)", "OLD");
+		if (fnt != "OLD")
+			sampling.offset_range = textToFloat(fnt);
+
+		fnt = parser.getOption("--offset_step", "Sampling rate for origin offsets (in pixels)", "OLD");
+		if (fnt != "OLD")
+			sampling.offset_step = textToFloat(fnt);
+	}
+
+	fnt = parser.getOption("--auto_local_healpix_order", "Minimum healpix order (before oversampling) from which auto-refine procedure will use local searches", "OLD");
+	if (fnt != "OLD")
+		autosampling_hporder_local_searches = textToInteger(fnt);
+
+	// Check whether the prior mode changes
+	double _sigma_rot, _sigma_tilt, _sigma_psi, _sigma_off;
+	int _mode;
+	fnt = parser.getOption("--sigma_ang", "Stddev on all three Euler angles for local angular searches (of +/- 3 stddev)", "OLD");
+	if (fnt != "OLD")
+	{
+		mymodel.orientational_prior_mode = PRIOR_ROTTILT_PSI;
+		mymodel.sigma2_rot = mymodel.sigma2_tilt = mymodel.sigma2_psi = textToFloat(fnt) * textToFloat(fnt);
+	}
+	fnt = parser.getOption("--sigma_rot", "Stddev on the first Euler angle for local angular searches (of +/- 3 stddev)", "OLD");
+	if (fnt != "OLD")
+	{
+		mymodel.orientational_prior_mode = PRIOR_ROTTILT_PSI;
+		mymodel.sigma2_rot = textToFloat(fnt) * textToFloat(fnt);
+	}
+	fnt = parser.getOption("--sigma_tilt", "Stddev on the first Euler angle for local angular searches (of +/- 3 stddev)", "OLD");
+	if (fnt != "OLD")
+	{
+		mymodel.orientational_prior_mode = PRIOR_ROTTILT_PSI;
+		mymodel.sigma2_tilt = textToFloat(fnt) * textToFloat(fnt);
+	}
+	fnt = parser.getOption("--sigma_psi", "Stddev on the in-plane angle for local angular searches (of +/- 3 stddev)", "OLD");
+	if (fnt != "OLD")
+	{
+		mymodel.orientational_prior_mode = PRIOR_ROTTILT_PSI;
+		mymodel.sigma2_psi = textToFloat(fnt) * textToFloat(fnt);
+	}
+	fnt = parser.getOption("--sigma_off", "Stddev. on the translations", "OLD");
+	if (fnt != "OLD")
+	{
+		mymodel.sigma2_offset = textToFloat(fnt) * textToFloat(fnt);
+	}
+
+	if (parser.checkOption("--skip_align", "Skip orientational assignment (only classify)?"))
+		do_skip_align = true;
+
+	if (parser.checkOption("--skip_rotate", "Skip rotational assignment (only translate and classify)?"))
+		do_skip_rotate = true;
+	else
+		do_skip_rotate = false; // do_skip_rotate should normally be false...
+
+	do_skip_maximization = parser.checkOption("--skip_maximize", "Skip maximization step (only write out data.star file)?");
+
+	int corrections_section = parser.addSection("Corrections");
+
+	// Can only switch the following option ON, not OFF
+	if (parser.checkOption("--scale", "Switch on intensity-scale corrections on image groups", "OLD"))
+		do_scale_correction = true;
+
+	// Can only switch the following option ON, not OFF
+	if (parser.checkOption("--norm", "Switch on normalisation-error correction","OLD"))
+		do_norm_correction = true;
+
+	int computation_section = parser.addSection("Computation");
+
+	nr_threads = textToInteger(parser.getOption("--j", "Number of threads to run in parallel (only useful on multi-core machines)", "1"));
+
+	fnt = parser.getOption("--pool", "Number of images to be processed together", "OLD");
+	if (fnt != "OLD")
+		max_nr_pool = textToInteger(fnt);
+
+	combine_weights_thru_disc = !parser.checkOption("--dont_combine_weights_via_disc", "Send the large arrays of summed weights through the MPI network, instead of writing large files to disc");
+
+	verb = textToInteger(parser.getOption("--verb", "Verbosity (1=normal, 0=silent)", "1"));
+
+	int expert_section = parser.addSection("Expert options");
+
+	fnt = parser.getOption("--strict_highres_exp", "Resolution limit (in Angstrom) to restrict probability calculations in the expectation step", "OLD");
+	if (fnt != "OLD")
+		strict_highres_exp = textToFloat(fnt);
+
+	// Debugging/analysis/hidden stuff
+	do_map = !checkParameter(argc, argv, "--no_map");
+	minres_map = textToInteger(getParameter(argc, argv, "--minres_map", "5"));
+    gridding_nr_iter = textToInteger(getParameter(argc, argv, "--gridding_iter", "10"));
+	debug1 = textToFloat(getParameter(argc, argv, "--debug1", "0."));
+	debug2 = textToFloat(getParameter(argc, argv, "--debug2", "0."));
+    do_bfactor = checkParameter(argc, argv, "--bfactor");
+	// Read in initial sigmaNoise spectrum
+	fn_sigma = getParameter(argc, argv, "--sigma","");
+	sigma2_fudge = textToFloat(getParameter(argc, argv, "--sigma2_fudge", "1."));
+	do_acc_currentsize_despite_highres_exp = checkParameter(argc, argv, "--accuracy_current_size");
+	do_sequential_halves_recons  = checkParameter(argc, argv, "--sequential_halves_recons");
+	do_always_join_random_halves = checkParameter(argc, argv, "--always_join_random_halves");
+	do_use_all_data = checkParameter(argc, argv, "--use_all_data");
+	do_always_cc  = checkParameter(argc, argv, "--always_cc");
+
+	do_print_metadata_labels = false;
+	do_print_symmetry_ops = false;
+#ifdef DEBUG
+	std::cerr << "Leaving parseContinue" << std::endl;
+#endif
+
+}
+
+void MlOptimiser::parseInitial(int argc, char **argv)
+{
+#ifdef DEBUG_READ
+    std::cerr<<"MlOptimiser::parseInitial Entering "<<std::endl;
+#endif
+
+	// Read/initialise mymodel and sampling from a STAR file
+    FileName fn_model = getParameter(argc, argv, "--model", "None");
+	if (fn_model != "None")
+	{
+		mymodel.read(fn_model);
+	}
+	// Read in the sampling information from a _sampling.star file
+    FileName fn_sampling = getParameter(argc, argv, "--sampling", "None");
+	if (fn_sampling != "None")
+	{
+		sampling.read(fn_sampling);
+	}
+
+	// General optimiser I/O stuff
+    int general_section = parser.addSection("General options");
+    fn_data = parser.getOption("--i", "Input images (in a star-file or a stack)");
+    fn_out = parser.getOption("--o", "Output rootname");
+    nr_iter = textToInteger(parser.getOption("--iter", "Maximum number of iterations to perform", "50"));
+	mymodel.pixel_size = textToFloat(parser.getOption("--angpix", "Pixel size (in Angstroms)"));
+	mymodel.tau2_fudge_factor = textToFloat(parser.getOption("--tau2_fudge", "Regularisation parameter (values higher than 1 give more weight to the data)", "1"));
+	mymodel.nr_classes = textToInteger(parser.getOption("--K", "Number of references to be refined", "1"));
+    particle_diameter = textToFloat(parser.getOption("--particle_diameter", "Diameter of the circular mask that will be applied to the experimental images (in Angstroms)", "-1"));
+	do_zero_mask = parser.checkOption("--zero_mask","Mask surrounding background in particles to zero (by default the solvent area is filled with random noise)");
+	do_solvent = parser.checkOption("--flatten_solvent", "Perform masking on the references as well?");
+	fn_mask = parser.getOption("--solvent_mask", "User-provided mask for the references (default is to use spherical mask with particle_diameter)", "None");
+	fn_mask2 = parser.getOption("--solvent_mask2", "User-provided secondary mask (with its own average density)", "None");
+	fn_tau = parser.getOption("--tau", "STAR file with input tau2-spectrum (to be kept constant)", "None");
+	do_split_random_halves = parser.checkOption("--split_random_halves", "Refine two random halves of the data completely separately");
+	low_resol_join_halves = textToFloat(parser.getOption("--low_resol_join_halves", "Resolution (in Angstrom) up to which the two random half-reconstructions will not be independent to prevent diverging orientations","-1"));
+
+	// Initialisation
+	int init_section = parser.addSection("Initialisation");
+	fn_ref = parser.getOption("--ref", "Image, stack or star-file with the reference(s). (Compulsory for 3D refinement!)", "None");
+	mymodel.sigma2_offset = textToFloat(parser.getOption("--offset", "Initial estimated stddev for the origin offsets", "3"));
+	mymodel.sigma2_offset *= mymodel.sigma2_offset;
+
+	// Perform cross-product comparison at first iteration
+	do_firstiter_cc = parser.checkOption("--firstiter_cc", "Perform CC-calculation in the first iteration (use this if references are not on the absolute intensity scale)");
+	ini_high = textToFloat(parser.getOption("--ini_high", "Resolution (in Angstroms) to which to limit refinement in the first iteration ", "-1"));
+
+	// Set the orientations
+    int orientations_section = parser.addSection("Orientations");
+	// Move these to sampling
+	adaptive_oversampling = textToInteger(parser.getOption("--oversampling", "Adaptive oversampling order to speed-up calculations (0=no oversampling, 1=2x, 2=4x, etc)", "1"));
+	sampling.healpix_order = textToInteger(parser.getOption("--healpix_order", "Healpix order for the angular sampling (before oversampling) on the (3D) sphere: hp2=15deg, hp3=7.5deg, etc", "2"));
+	sampling.psi_step = textToFloat(parser.getOption("--psi_step", "Sampling rate (before oversampling) for the in-plane angle (default=10deg for 2D, hp sampling for 3D)", "-1"));
+	sampling.limit_tilt = textToFloat(parser.getOption("--limit_tilt", "Limited tilt angle: positive for keeping side views, negative for keeping top views", "-91"));
+	sampling.fn_sym = parser.getOption("--sym", "Symmetry group", "c1");
+	sampling.offset_range = textToFloat(parser.getOption("--offset_range", "Search range for origin offsets (in pixels)", "6"));
+	sampling.offset_step = textToFloat(parser.getOption("--offset_step", "Sampling rate (before oversampling) for origin offsets (in pixels)", "2"));
+	sampling.perturbation_factor = textToFloat(parser.getOption("--perturb", "Perturbation factor for the angular sampling (0=no perturb; 0.5=perturb)", "0.5"));
+	do_auto_refine = parser.checkOption("--auto_refine", "Perform 3D auto-refine procedure?");
+	autosampling_hporder_local_searches = textToInteger(parser.getOption("--auto_local_healpix_order", "Minimum healpix order (before oversampling) from which autosampling procedure will use local searches", "4"));
+	parser.setSection(orientations_section);
+	double _sigma_ang = textToFloat(parser.getOption("--sigma_ang", "Stddev on all three Euler angles for local angular searches (of +/- 3 stddev)", "-1"));
+	double _sigma_rot = textToFloat(parser.getOption("--sigma_rot", "Stddev on the first Euler angle for local angular searches (of +/- 3 stddev)", "-1"));
+	double _sigma_tilt = textToFloat(parser.getOption("--sigma_tilt", "Stddev on the second Euler angle for local angular searches (of +/- 3 stddev)", "-1"));
+	double _sigma_psi = textToFloat(parser.getOption("--sigma_psi", "Stddev on the in-plane angle for local angular searches (of +/- 3 stddev)", "-1"));
+	if (_sigma_ang > 0.)
+	{
+		mymodel.orientational_prior_mode = PRIOR_ROTTILT_PSI;
+		// the sigma-values for the orientational prior are in model (and not in sampling) because one might like to estimate them
+		// from the data by calculating weighted sums of all angular differences: therefore it needs to be in wsum_model and thus in mymodel.
+		mymodel.sigma2_rot = mymodel.sigma2_tilt = mymodel.sigma2_psi = _sigma_ang * _sigma_ang;
+	}
+	else if (_sigma_rot > 0. || _sigma_tilt > 0. || _sigma_psi > 0.)
+	{
+		mymodel.orientational_prior_mode = PRIOR_ROTTILT_PSI;
+		mymodel.sigma2_rot  = (_sigma_rot > 0. ) ? _sigma_rot * _sigma_rot   : 0.;
+		mymodel.sigma2_tilt = (_sigma_tilt > 0.) ? _sigma_tilt * _sigma_tilt : 0.;
+		mymodel.sigma2_psi  = (_sigma_psi > 0. ) ? _sigma_psi * _sigma_psi   : 0.;
+	}
+	else
+	{
+		//default
+		mymodel.orientational_prior_mode = NOPRIOR;
+		mymodel.sigma2_rot = mymodel.sigma2_tilt = mymodel.sigma2_psi = 0.;
+	}
+	do_skip_align = parser.checkOption("--skip_align", "Skip orientational assignment (only classify)?");
+	do_skip_rotate = parser.checkOption("--skip_rotate", "Skip rotational assignment (only translate and classify)?");
+	do_skip_maximization = false;
+
+	// CTF, norm, scale, bfactor correction etc.
+	int corrections_section = parser.addSection("Corrections");
+	do_ctf_correction = parser.checkOption("--ctf", "Perform CTF correction?");
+	intact_ctf_first_peak = parser.checkOption("--ctf_intact_first_peak", "Ignore CTFs until their first peak?");
+	refs_are_ctf_corrected = parser.checkOption("--ctf_corrected_ref", "Have the input references been CTF-amplitude corrected?");
+	ctf_phase_flipped = parser.checkOption("--ctf_phase_flipped", "Have the data been CTF phase-flipped?");
+	only_flip_phases = parser.checkOption("--only_flip_phases", "Only perform CTF phase-flipping? (default is full amplitude-correction)");
+	do_norm_correction = parser.checkOption("--norm", "Perform normalisation-error correction?");
+	do_scale_correction = parser.checkOption("--scale", "Perform intensity-scale corrections on image groups?");
+
+	// Computation stuff
+	// The number of threads is always read from the command line
+	int computation_section = parser.addSection("Computation");
+	nr_threads = textToInteger(parser.getOption("--j", "Number of threads to run in parallel (only useful on multi-core machines)", "1"));
+	available_memory = textToFloat(parser.getOption("--memory_per_thread", "Available RAM (in Gb) for each thread", "2"));
+	max_nr_pool = textToInteger(parser.getOption("--pool", "Number of images to be processed together", "8"));
+	combine_weights_thru_disc = !parser.checkOption("--dont_combine_weights_via_disc", "Send the large arrays of summed weights through the MPI network, instead of writing large files to disc");
+
+	// Expert options
+	int expert_section = parser.addSection("Expert options");
+	mymodel.padding_factor = textToInteger(parser.getOption("--pad", "Oversampling factor for the Fourier transforms of the references", "2"));
+	mymodel.interpolator = (parser.checkOption("--NN", "Perform nearest-neighbour instead of linear Fourier-space interpolation?")) ? NEAREST_NEIGHBOUR : TRILINEAR;
+	mymodel.r_min_nn = textToInteger(parser.getOption("--r_min_nn", "Minimum number of Fourier shells to perform linear Fourier-space interpolation", "10"));
+	verb = textToInteger(parser.getOption("--verb", "Verbosity (1=normal, 0=silent)", "1"));
+	random_seed = textToInteger(parser.getOption("--random_seed", "Number for the random seed generator", "-1"));
+	max_coarse_size = textToInteger(parser.getOption("--coarse_size", "Maximum image size for the first pass of the adaptive sampling approach", "-1"));
+	adaptive_fraction = textToFloat(parser.getOption("--adaptive_fraction", "Fraction of the weights to be considered in the first pass of adaptive oversampling ", "0.999"));
+	width_mask_edge = textToInteger(parser.getOption("--maskedge", "Width of the soft edge of the spherical mask (in pixels)", "5"));
+	fix_sigma_noise = parser.checkOption("--fix_sigma_noise", "Fix the experimental noise spectra?");
+	fix_sigma_offset = parser.checkOption("--fix_sigma_offset", "Fix the stddev in the origin offsets?");
+	incr_size = textToInteger(parser.getOption("--incr_size", "Number of Fourier shells beyond the current resolution to be included in refinement", "10"));
+	do_print_metadata_labels = parser.checkOption("--print_metadata_labels", "Print a table with definitions of all metadata labels, and exit");
+	do_print_symmetry_ops = parser.checkOption("--print_symmetry_ops", "Print all symmetry transformation matrices, and exit");
+	strict_highres_exp = textToFloat(parser.getOption("--strict_highres_exp", "Resolution limit (in Angstrom) to restrict probability calculations in the expectation step", "-1"));
+	dont_raise_norm_error = parser.checkOption("--dont_check_norm", "Skip the check whether the images are normalised correctly");
+
+
+
+	// TODO: read/write do_always_cc in optmiser.star file!!!
+	// SA-stuff
+	do_sim_anneal = parser.checkOption("--sim_anneal", "Perform simulated-annealing to improve overall convergence of random starting models?");
+	temp_ini = textToFloat(parser.getOption("--temp_ini", "Initial temperature (K) for simulated annealing", "1000"));
+	temp_fin = textToFloat(parser.getOption("--temp_fin", "Initial temperature (K) for simulated annealing", "1"));
+	do_always_cc  = parser.checkOption("--always_cc", "Perform CC-calculation in all iterations (useful for faster denovo model generation?)");
+
+	///////////////// Special stuff for first iteration (only accessible via CL, not through readSTAR ////////////////////
+
+	// When reading from the CL: always start at iteration 1
+	iter = 0;
+    // When starting from CL: always calculate initial sigma_noise
+    do_calculate_initial_sigma_noise = true;
+    // Start average norm correction at 1!
+    mymodel.avg_norm_correction = 1.;
+    // Always initialise the PDF of the directions
+    directions_have_changed = true;
+
+    // Only reconstruct and join random halves are only available when continuing an old run
+    do_join_random_halves = false;
+
+    // For auto-sampling and convergence check
+    nr_iter_wo_resol_gain = 0;
+    nr_iter_wo_large_hidden_variable_changes = 0;
+    current_changes_optimal_classes = 9999999;
+    current_changes_optimal_offsets = 999.;
+    current_changes_optimal_orientations = 999.;
+    smallest_changes_optimal_classes = 9999999;
+    smallest_changes_optimal_offsets = 999.;
+    smallest_changes_optimal_orientations = 999.;
+    acc_rot = acc_trans = 999.;
+
+    best_resol_thus_far = 1./999.;
+    has_converged = false;
+    has_high_fsc_at_limit = false;
+    has_large_incr_size_iter_ago = 0;
+
+    // Never realign movies from the start
+    do_realign_movies = false;
+
+    // Debugging/analysis/hidden stuff
+	do_map = !checkParameter(argc, argv, "--no_map");
+	minres_map = textToInteger(getParameter(argc, argv, "--minres_map", "5"));
+    do_bfactor = checkParameter(argc, argv, "--bfactor");
+    gridding_nr_iter = textToInteger(getParameter(argc, argv, "--gridding_iter", "10"));
+	debug1 = textToFloat(getParameter(argc, argv, "--debug1", "0"));
+	debug2 = textToFloat(getParameter(argc, argv, "--debug2", "0"));
+	// Read in initial sigmaNoise spectrum
+	fn_sigma = getParameter(argc, argv, "--sigma","");
+	do_calculate_initial_sigma_noise = (fn_sigma == "") ? true : false;
+	sigma2_fudge = textToFloat(getParameter(argc, argv, "--sigma2_fudge", "1"));
+	do_acc_currentsize_despite_highres_exp = checkParameter(argc, argv, "--accuracy_current_size");
+	do_sequential_halves_recons  = checkParameter(argc, argv, "--sequential_halves_recons");
+	do_always_join_random_halves = checkParameter(argc, argv, "--always_join_random_halves");
+	do_use_all_data = checkParameter(argc, argv, "--use_all_data");
+
+#ifdef DEBUG_READ
+    std::cerr<<"MlOptimiser::parseInitial Done"<<std::endl;
+#endif
+
+}
+
+
+void MlOptimiser::read(FileName fn_in, int rank)
+{
+
+#ifdef DEBUG_READ
+    std::cerr<<"MlOptimiser::readStar entering ..."<<std::endl;
+#endif
+
+    // Open input file
+    std::ifstream in(fn_in.data(), std::ios_base::in);
+    if (in.fail())
+        REPORT_ERROR( (std::string) "MlOptimiser::readStar: File " + fn_in + " cannot be read." );
+
+    MetaDataTable MD;
+
+    // Read general stuff
+    FileName fn_model, fn_model2, fn_sampling;
+    MD.readStar(in, "optimiser_general");
+    in.close();
+
+    if (!MD.getValue(EMDL_OPTIMISER_OUTPUT_ROOTNAME, fn_out) ||
+        !MD.getValue(EMDL_OPTIMISER_MODEL_STARFILE, fn_model) ||
+		!MD.getValue(EMDL_OPTIMISER_DATA_STARFILE, fn_data) ||
+		!MD.getValue(EMDL_OPTIMISER_SAMPLING_STARFILE, fn_sampling) ||
+        !MD.getValue(EMDL_OPTIMISER_ITERATION_NO, iter) ||
+        !MD.getValue(EMDL_OPTIMISER_NR_ITERATIONS, nr_iter) ||
+        !MD.getValue(EMDL_OPTIMISER_DO_SPLIT_RANDOM_HALVES, do_split_random_halves) ||
+        !MD.getValue(EMDL_OPTIMISER_LOWRES_JOIN_RANDOM_HALVES, low_resol_join_halves) ||
+        !MD.getValue(EMDL_OPTIMISER_ADAPTIVE_OVERSAMPLING, adaptive_oversampling) ||
+		!MD.getValue(EMDL_OPTIMISER_ADAPTIVE_FRACTION, adaptive_fraction) ||
+		!MD.getValue(EMDL_OPTIMISER_RANDOM_SEED, random_seed) ||
+		!MD.getValue(EMDL_OPTIMISER_PARTICLE_DIAMETER, particle_diameter) ||
+		!MD.getValue(EMDL_OPTIMISER_WIDTH_MASK_EDGE, width_mask_edge) ||
+		!MD.getValue(EMDL_OPTIMISER_DO_ZERO_MASK, do_zero_mask) ||
+		!MD.getValue(EMDL_OPTIMISER_DO_SOLVENT_FLATTEN, do_solvent) ||
+		!MD.getValue(EMDL_OPTIMISER_SOLVENT_MASK_NAME, fn_mask) ||
+		!MD.getValue(EMDL_OPTIMISER_SOLVENT_MASK2_NAME, fn_mask2) ||
+		!MD.getValue(EMDL_OPTIMISER_TAU_SPECTRUM_NAME, fn_tau) ||
+		!MD.getValue(EMDL_OPTIMISER_COARSE_SIZE, coarse_size) ||
+		!MD.getValue(EMDL_OPTIMISER_MAX_COARSE_SIZE, max_coarse_size) ||
+		!MD.getValue(EMDL_OPTIMISER_HIGHRES_LIMIT_EXP, strict_highres_exp) ||
+		!MD.getValue(EMDL_OPTIMISER_INCR_SIZE, incr_size) ||
+		!MD.getValue(EMDL_OPTIMISER_DO_MAP, do_map) ||
+		!MD.getValue(EMDL_OPTIMISER_DO_AUTO_REFINE, do_auto_refine) ||
+		!MD.getValue(EMDL_OPTIMISER_AUTO_LOCAL_HP_ORDER, autosampling_hporder_local_searches) ||
+	    !MD.getValue(EMDL_OPTIMISER_NR_ITER_WO_RESOL_GAIN, nr_iter_wo_resol_gain) ||
+	    !MD.getValue(EMDL_OPTIMISER_BEST_RESOL_THUS_FAR, best_resol_thus_far) ||
+	    !MD.getValue(EMDL_OPTIMISER_NR_ITER_WO_HIDDEN_VAR_CHANGES, nr_iter_wo_large_hidden_variable_changes) ||
+		!MD.getValue(EMDL_OPTIMISER_DO_SKIP_ALIGN, do_skip_align) ||
+		//!MD.getValue(EMDL_OPTIMISER_DO_SKIP_ROTATE, do_skip_rotate) ||
+	    !MD.getValue(EMDL_OPTIMISER_ACCURACY_ROT, acc_rot) ||
+	    !MD.getValue(EMDL_OPTIMISER_ACCURACY_TRANS, acc_trans) ||
+	    !MD.getValue(EMDL_OPTIMISER_CHANGES_OPTIMAL_ORIENTS, current_changes_optimal_orientations) ||
+	    !MD.getValue(EMDL_OPTIMISER_CHANGES_OPTIMAL_OFFSETS, current_changes_optimal_offsets) ||
+	    !MD.getValue(EMDL_OPTIMISER_CHANGES_OPTIMAL_CLASSES, current_changes_optimal_classes) ||
+	    !MD.getValue(EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_ORIENTS, smallest_changes_optimal_orientations) ||
+	    !MD.getValue(EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_OFFSETS, smallest_changes_optimal_offsets) ||
+	    !MD.getValue(EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_CLASSES, smallest_changes_optimal_classes) ||
+	    !MD.getValue(EMDL_OPTIMISER_HAS_CONVERGED, has_converged) ||
+	    !MD.getValue(EMDL_OPTIMISER_HAS_HIGH_FSC_AT_LIMIT, has_high_fsc_at_limit) ||
+	    !MD.getValue(EMDL_OPTIMISER_HAS_LARGE_INCR_SIZE_ITER_AGO, has_large_incr_size_iter_ago) ||
+		!MD.getValue(EMDL_OPTIMISER_DO_CORRECT_NORM, do_norm_correction) ||
+		!MD.getValue(EMDL_OPTIMISER_DO_CORRECT_SCALE, do_scale_correction) ||
+		!MD.getValue(EMDL_OPTIMISER_DO_CORRECT_CTF, do_ctf_correction) ||
+		!MD.getValue(EMDL_OPTIMISER_DO_REALIGN_MOVIES, do_realign_movies) ||
+		!MD.getValue(EMDL_OPTIMISER_IGNORE_CTF_UNTIL_FIRST_PEAK, intact_ctf_first_peak) ||
+		!MD.getValue(EMDL_OPTIMISER_DATA_ARE_CTF_PHASE_FLIPPED, ctf_phase_flipped) ||
+		!MD.getValue(EMDL_OPTIMISER_DO_ONLY_FLIP_CTF_PHASES, only_flip_phases) ||
+		!MD.getValue(EMDL_OPTIMISER_REFS_ARE_CTF_CORRECTED, refs_are_ctf_corrected) ||
+		!MD.getValue(EMDL_OPTIMISER_FIX_SIGMA_NOISE, fix_sigma_noise) ||
+		!MD.getValue(EMDL_OPTIMISER_FIX_SIGMA_OFFSET, fix_sigma_offset) ||
+		!MD.getValue(EMDL_OPTIMISER_MAX_NR_POOL, max_nr_pool) ||
+		!MD.getValue(EMDL_OPTIMISER_AVAILABLE_MEMORY, available_memory))
+    	REPORT_ERROR("MlOptimiser::readStar: incorrect optimiser_general table");
+
+    if (do_split_random_halves &&
+    		!MD.getValue(EMDL_OPTIMISER_MODEL_STARFILE2, fn_model2))
+    	REPORT_ERROR("MlOptimiser::readStar: splitting data into two random halves, but rlnModelStarFile2 not found in optimiser_general table");
+
+    // Initialise some stuff for first-iteration only (not relevant here...)
+    do_calculate_initial_sigma_noise = false;
+    do_average_unaligned = false;
+    do_generate_seeds = false;
+    do_firstiter_cc = false;
+    ini_high = 0;
+
+    // Initialise some of the other, hidden or debugging stuff
+    minres_map = 5;
+    do_bfactor = false;
+    gridding_nr_iter = 10;
+    debug1 = debug2 = 0.;
+
+    // Then read in sampling, mydata and mymodel stuff
+    mydata.read(fn_data);
+    if (do_split_random_halves)
+    {
+		if (rank % 2 == 1)
+			mymodel.read(fn_model);
+		else
+			mymodel.read(fn_model2);
+    }
+    else
+    {
+    	mymodel.read(fn_model);
+    }
+	sampling.read(fn_sampling);
+
+#ifdef DEBUG_READ
+    std::cerr<<"MlOptimiser::readStar done."<<std::endl;
+#endif
+
+}
+
+
+void MlOptimiser::write(bool do_write_sampling, bool do_write_data, bool do_write_optimiser, bool do_write_model, int random_subset)
+{
+
+	FileName fn_root, fn_tmp, fn_model, fn_model2, fn_data, fn_sampling;
+	std::ofstream  fh;
+	if (iter > -1)
+		fn_root.compose(fn_out+"_it", iter, "", 3);
+	else
+		fn_root = fn_out;
+
+	// First write "main" STAR file with all information from this run
+	// Do this for random_subset==0 and random_subset==1
+	if (do_write_optimiser && random_subset < 2)
+	{
+		fn_tmp = fn_root+"_optimiser.star";
+		fh.open((fn_tmp).c_str(), std::ios::out);
+		if (!fh)
+			REPORT_ERROR( (std::string)"MlOptimiser::write: Cannot write file: " + fn_tmp);
+
+		// Write the command line as a comment in the header
+		fh << "# RELION optimiser"<<std::endl;
+		fh << "# ";
+		parser.writeCommandLine(fh);
+
+		if (do_split_random_halves && !do_join_random_halves)
+		{
+			fn_model  = fn_root + "_half1_model.star";
+			fn_model2 = fn_root + "_half2_model.star";
+		}
+		else
+		{
+			fn_model = fn_root + "_model.star";
+		}
+		fn_data = fn_root + "_data.star";
+		fn_sampling = fn_root + "_sampling.star";
+
+		MetaDataTable MD;
+		MD.setIsList(true);
+		MD.setName("optimiser_general");
+		MD.addObject();
+		MD.setValue(EMDL_OPTIMISER_OUTPUT_ROOTNAME, fn_out);
+		if (do_split_random_halves)
+		{
+			MD.setValue(EMDL_OPTIMISER_MODEL_STARFILE, fn_model);
+			MD.setValue(EMDL_OPTIMISER_MODEL_STARFILE2, fn_model2);
+		}
+		else
+		{
+			MD.setValue(EMDL_OPTIMISER_MODEL_STARFILE, fn_model);
+		}
+		MD.setValue(EMDL_OPTIMISER_DATA_STARFILE, fn_data);
+		MD.setValue(EMDL_OPTIMISER_SAMPLING_STARFILE, fn_sampling);
+		MD.setValue(EMDL_OPTIMISER_ITERATION_NO, iter);
+		MD.setValue(EMDL_OPTIMISER_NR_ITERATIONS, nr_iter);
+		MD.setValue(EMDL_OPTIMISER_DO_SPLIT_RANDOM_HALVES, do_split_random_halves);
+		MD.setValue(EMDL_OPTIMISER_LOWRES_JOIN_RANDOM_HALVES, low_resol_join_halves);
+		MD.setValue(EMDL_OPTIMISER_ADAPTIVE_OVERSAMPLING, adaptive_oversampling);
+		MD.setValue(EMDL_OPTIMISER_ADAPTIVE_FRACTION, adaptive_fraction);
+		MD.setValue(EMDL_OPTIMISER_RANDOM_SEED, random_seed);
+		MD.setValue(EMDL_OPTIMISER_PARTICLE_DIAMETER, particle_diameter);
+		MD.setValue(EMDL_OPTIMISER_WIDTH_MASK_EDGE, width_mask_edge);
+		MD.setValue(EMDL_OPTIMISER_DO_ZERO_MASK, do_zero_mask);
+		MD.setValue(EMDL_OPTIMISER_DO_SOLVENT_FLATTEN, do_solvent);
+		MD.setValue(EMDL_OPTIMISER_SOLVENT_MASK_NAME, fn_mask);
+		MD.setValue(EMDL_OPTIMISER_SOLVENT_MASK2_NAME, fn_mask2);
+		MD.setValue(EMDL_OPTIMISER_TAU_SPECTRUM_NAME, fn_tau);
+		MD.setValue(EMDL_OPTIMISER_COARSE_SIZE, coarse_size);
+		MD.setValue(EMDL_OPTIMISER_MAX_COARSE_SIZE, max_coarse_size);
+		MD.setValue(EMDL_OPTIMISER_HIGHRES_LIMIT_EXP, strict_highres_exp);
+		MD.setValue(EMDL_OPTIMISER_INCR_SIZE, incr_size);
+		MD.setValue(EMDL_OPTIMISER_DO_MAP, do_map);
+		MD.setValue(EMDL_OPTIMISER_DO_AUTO_REFINE, do_auto_refine);
+		MD.setValue(EMDL_OPTIMISER_AUTO_LOCAL_HP_ORDER, autosampling_hporder_local_searches);
+	    MD.setValue(EMDL_OPTIMISER_NR_ITER_WO_RESOL_GAIN, nr_iter_wo_resol_gain);
+	    MD.setValue(EMDL_OPTIMISER_BEST_RESOL_THUS_FAR,best_resol_thus_far);
+	    MD.setValue(EMDL_OPTIMISER_NR_ITER_WO_HIDDEN_VAR_CHANGES, nr_iter_wo_large_hidden_variable_changes);
+		MD.setValue(EMDL_OPTIMISER_DO_SKIP_ALIGN, do_skip_align);
+		MD.setValue(EMDL_OPTIMISER_DO_SKIP_ROTATE, do_skip_rotate);
+	    MD.setValue(EMDL_OPTIMISER_ACCURACY_ROT, acc_rot);
+	    MD.setValue(EMDL_OPTIMISER_ACCURACY_TRANS, acc_trans);
+	    MD.setValue(EMDL_OPTIMISER_CHANGES_OPTIMAL_ORIENTS, current_changes_optimal_orientations);
+	    MD.setValue(EMDL_OPTIMISER_CHANGES_OPTIMAL_OFFSETS, current_changes_optimal_offsets);
+	    MD.setValue(EMDL_OPTIMISER_CHANGES_OPTIMAL_CLASSES, current_changes_optimal_classes);
+	    MD.setValue(EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_ORIENTS, smallest_changes_optimal_orientations);
+	    MD.setValue(EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_OFFSETS, smallest_changes_optimal_offsets);
+	    MD.setValue(EMDL_OPTIMISER_SMALLEST_CHANGES_OPT_CLASSES, smallest_changes_optimal_classes);
+	    MD.setValue(EMDL_OPTIMISER_HAS_CONVERGED, has_converged);
+	    MD.setValue(EMDL_OPTIMISER_HAS_HIGH_FSC_AT_LIMIT, has_high_fsc_at_limit);
+	    MD.setValue(EMDL_OPTIMISER_HAS_LARGE_INCR_SIZE_ITER_AGO, has_large_incr_size_iter_ago);
+		MD.setValue(EMDL_OPTIMISER_DO_CORRECT_NORM, do_norm_correction);
+		MD.setValue(EMDL_OPTIMISER_DO_CORRECT_SCALE, do_scale_correction);
+		MD.setValue(EMDL_OPTIMISER_DO_CORRECT_CTF, do_ctf_correction);
+		MD.setValue(EMDL_OPTIMISER_DO_REALIGN_MOVIES, do_realign_movies);
+		MD.setValue(EMDL_OPTIMISER_IGNORE_CTF_UNTIL_FIRST_PEAK, intact_ctf_first_peak);
+		MD.setValue(EMDL_OPTIMISER_DATA_ARE_CTF_PHASE_FLIPPED, ctf_phase_flipped);
+		MD.setValue(EMDL_OPTIMISER_DO_ONLY_FLIP_CTF_PHASES, only_flip_phases);
+		MD.setValue(EMDL_OPTIMISER_REFS_ARE_CTF_CORRECTED, refs_are_ctf_corrected);
+		MD.setValue(EMDL_OPTIMISER_FIX_SIGMA_NOISE, fix_sigma_noise);
+		MD.setValue(EMDL_OPTIMISER_FIX_SIGMA_OFFSET, fix_sigma_offset);
+		MD.setValue(EMDL_OPTIMISER_MAX_NR_POOL, max_nr_pool);
+		MD.setValue(EMDL_OPTIMISER_AVAILABLE_MEMORY, available_memory);
+
+		MD.write(fh);
+		fh.close();
+	}
+
+	// Then write the mymodel to file
+	if (do_write_model)
+	{
+		if (do_split_random_halves && !do_join_random_halves)
+			mymodel.write(fn_root + "_half" + integerToString(random_subset), sampling);
+		else
+			mymodel.write(fn_root, sampling);
+	}
+
+	// And write the mydata to file
+	if (do_write_data)
+		mydata.write(fn_root);
+
+	// And write the sampling object
+	if (do_write_sampling)
+		sampling.write(fn_root);
+
+}
+
+/** ========================== Initialisation  =========================== */
+
+void MlOptimiser::initialise()
+{
+#ifdef DEBUG
+    std::cerr<<"MlOptimiser::initialise Entering"<<std::endl;
+#endif
+
+    initialiseGeneral();
+
+    initialiseWorkLoad();
+
+	if (fn_sigma != "")
+	{
+		// Read in sigma_noise spetrum from file DEVELOPMENTAL!!! FOR DEBUGGING ONLY....
+		MetaDataTable MDsigma;
+		double val;
+		int idx;
+		MDsigma.read(fn_sigma);
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDsigma)
+		{
+			MDsigma.getValue(EMDL_SPECTRAL_IDX, idx);
+			MDsigma.getValue(EMDL_MLMODEL_SIGMA2_NOISE, val);
+			if (idx < XSIZE(mymodel.sigma2_noise[0]))
+				mymodel.sigma2_noise[0](idx) = val;
+		}
+		if (idx < XSIZE(mymodel.sigma2_noise[0]) - 1)
+		{
+			if (verb > 0) std::cout<< " WARNING: provided sigma2_noise-spectrum has fewer entries ("<<idx+1<<") than needed ("<<XSIZE(mymodel.sigma2_noise[0])<<"). Set rest to zero..."<<std::endl;
+		}
+		// Use the same spectrum for all classes
+		for (int igroup = 0; igroup< mymodel.nr_groups; igroup++)
+			mymodel.sigma2_noise[igroup] =  mymodel.sigma2_noise[0];
+
+	}
+	else if (do_calculate_initial_sigma_noise || do_average_unaligned)
+	{
+		MultidimArray<double> Mavg;
+
+		// Calculate initial sigma noise model from power_class spectra of the individual images
+		calculateSumOfPowerSpectraAndAverageImage(Mavg);
+
+		// Set sigma2_noise and Iref from averaged poser spectra and Mavg
+		setSigmaNoiseEstimatesAndSetAverageImage(Mavg);
+	}
+
+    // First low-pass filter the initial references
+	if (iter == 0)
+		initialLowPassFilterReferences();
+
+	// Initialise the data_versus_prior ratio to get the initial current_size right
+	if (iter == 0)
+		mymodel.initialiseDataVersusPrior(fix_tau); // fix_tau was set in initialiseGeneral
+
+	// Check minimum group size of 10 particles
+	if (verb > 0)
+	{
+		bool do_warn = false;
+		for (int igroup = 0; igroup< mymodel.nr_groups; igroup++)
+		{
+			if (mymodel.nr_particles_group[igroup] < 10)
+			{
+				std:: cout << "WARNING: There are only " << mymodel.nr_particles_group[igroup] << " particles in group " << igroup + 1 << std::endl;
+				do_warn = true;
+			}
+		}
+		if (do_warn)
+		{
+			std:: cout << "WARNING: You may want to consider joining some micrographs into larger groups to obtain more robust noise estimates. " << std::endl;
+			std:: cout << "         You can do so by using the same rlnMicrographName label for particles from multiple different micrographs in the input STAR file. " << std::endl;
+		}
+	}
+
+	// Write out initial mymodel
+	write(DONT_WRITE_SAMPLING, DO_WRITE_DATA, DO_WRITE_OPTIMISER, DO_WRITE_MODEL, 0);
+
+
+	// Do this after writing out the model, so that still the random halves are written in separate files.
+	if (do_realign_movies)
+	{
+		// Resolution seems to decrease again after 1 iteration. Therefore, just perform a single iteration until we figure out what exactly happens here...
+		has_converged = true;
+		// Then use join random halves
+		do_join_random_halves = true;
+
+		// If we skip the maximization step, then there is no use in using all data
+		if (!do_skip_maximization)
+		{
+			// Use all data out to Nyquist because resolution gains may be substantial
+			do_use_all_data = true;
+		}
+	}
+
+#ifdef DEBUG
+    std::cerr<<"MlOptimiser::initialise Done"<<std::endl;
+#endif
+}
+
+void MlOptimiser::initialiseGeneral(int rank)
+{
+
+#ifdef DEBUG
+	std::cerr << "Entering initialiseGeneral" << std::endl;
+#endif
+
+#ifdef TIMING
+	//DIFFF = timer.setNew("difff");
+	TIMING_EXP =           timer.setNew("expectation");
+	TIMING_MAX =           timer.setNew("maximization");
+	TIMING_RECONS =        timer.setNew("reconstruction");
+	TIMING_ESP =           timer.setNew("expectationSomeParticles");
+	TIMING_ESP_READ  =     timer.setNew(" - ESP: read");
+	TIMING_ESP_DIFF1 =     timer.setNew(" - ESP: getAllSquaredDifferences1");
+	TIMING_ESP_DIFF2 =     timer.setNew(" - ESP: getAllSquaredDifferences2");
+	TIMING_DIFF_PROJ =     timer.setNew(" -  - ESPdiff2: project");
+	TIMING_DIFF_SHIFT =    timer.setNew(" -  - ESPdiff2: shift");
+	TIMING_DIFF_DIFF2 =    timer.setNew(" -  - ESPdiff2: diff2");
+	TIMING_ESP_WEIGHT1 =   timer.setNew(" - ESP: convertDiff2ToWeights1");
+	TIMING_ESP_WEIGHT2 =   timer.setNew(" - ESP: convertDiff2ToWeights2");
+	TIMING_WEIGHT_EXP =    timer.setNew(" -  - ESPweight: exp");
+	TIMING_WEIGHT_SORT =   timer.setNew(" -  - ESPweight: sort");
+	TIMING_ESP_WSUM =      timer.setNew(" - ESP: storeWeightedSums");
+	TIMING_WSUM_PROJ =     timer.setNew("  - - ESPwsum: project");
+	TIMING_WSUM_DIFF2 =    timer.setNew(" -  - ESPwsum: diff2");
+	TIMING_WSUM_SUMSHIFT = timer.setNew(" -  - ESPwsum: shift");
+	TIMING_WSUM_BACKPROJ = timer.setNew(" -  - ESPwsum: backproject");
+#endif
+
+	if (do_print_metadata_labels)
+	{
+		if (verb > 0)
+			EMDL::printDefinitions(std::cout);
+		exit(0);
+	}
+
+	// Print symmetry operators to cout
+	if (do_print_symmetry_ops)
+	{
+		if (verb > 0)
+		{
+			SymList SL;
+			SL.writeDefinition(std::cout, sampling.symmetryGroup());
+		}
+		exit(0);
+	}
+
+	// Check for errors in the command-line option
+	if (parser.checkForErrors(verb))
+		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+	nr_threads_original = nr_threads;
+	// If we are not continuing an old run, now read in the data and the reference images
+	if (iter == 0)
+	{
+
+		// Read in the experimental image metadata
+		mydata.read(fn_data);
+
+		// Also get original size of the images to pass to mymodel.read()
+		int ori_size = -1;
+		mydata.MDexp.getValue(EMDL_IMAGE_SIZE, ori_size);
+		if (ori_size%2 != 0)
+			REPORT_ERROR("This program only works with even values for the image dimensions!");
+    	mymodel.readImages(fn_ref, ori_size, mydata,
+    			do_average_unaligned, do_generate_seeds, refs_are_ctf_corrected);
+
+    	// Check consistency of EMDL_CTF_MAGNIFICATION and MEBL_CTF_DETECTOR_PIXEL_SIZE with mymodel.pixel_size
+    	double mag, dstep, first_angpix, my_angpix;
+    	bool has_magn = false;
+    	if (mydata.MDimg.containsLabel(EMDL_CTF_MAGNIFICATION) && mydata.MDimg.containsLabel(EMDL_CTF_DETECTOR_PIXEL_SIZE))
+    	{
+    		FOR_ALL_OBJECTS_IN_METADATA_TABLE(mydata.MDimg)
+			{
+    			mydata.MDimg.getValue(EMDL_CTF_MAGNIFICATION, mag);
+    			mydata.MDimg.getValue(EMDL_CTF_DETECTOR_PIXEL_SIZE, dstep);
+    			my_angpix = 10000. * dstep / mag;
+    			if (!has_magn)
+    			{
+    				first_angpix = my_angpix;
+    				has_magn = true;
+    			}
+    			else if (ABS(first_angpix - my_angpix) > 0.01)
+    				REPORT_ERROR("MlOptimiser::initialiseGeneral: ERROR inconsistent magnification and detector pixel sizes in images in input STAR file");
+			}
+    	}
+    	if (mydata.MDmic.containsLabel(EMDL_CTF_MAGNIFICATION) && mydata.MDmic.containsLabel(EMDL_CTF_DETECTOR_PIXEL_SIZE))
+    	{
+    		FOR_ALL_OBJECTS_IN_METADATA_TABLE(mydata.MDmic)
+			{
+    			mydata.MDimg.getValue(EMDL_CTF_MAGNIFICATION, mag);
+    			mydata.MDimg.getValue(EMDL_CTF_DETECTOR_PIXEL_SIZE, dstep);
+    			my_angpix = 10000. * dstep / mag;
+    			if (!has_magn)
+    			{
+    				first_angpix = my_angpix;
+    				has_magn = true;
+    			}
+    			else if (ABS(first_angpix - my_angpix) > 0.01)
+    				REPORT_ERROR("MlOptimiser::initialiseGeneral: ERROR inconsistent magnification and detector pixel sizes in micrographs in input STAR file");
+			}
+    	}
+    	if (has_magn && ABS(first_angpix - mymodel.pixel_size) > 0.01)
+    	{
+    		if (verb > 0)
+    			std::cout << "MlOptimiser::initialiseGeneral: WARNING modifying pixel size from " << mymodel.pixel_size <<" to "<<first_angpix << " based on magnification information in the input STAR file" << std::endl;
+    		mymodel.pixel_size = first_angpix;
+    	}
+
+	}
+	// Expand movies if fn_data_movie is given AND we were not doing expanded movies already
+	else if (fn_data_movie != "" && !do_realign_movies)
+	{
+
+		if (verb > 0)
+			std::cout << " Expanding current model for movie frames... " << std::endl;
+
+		do_realign_movies = true;
+		nr_iter_wo_resol_gain = -1;
+		nr_iter_wo_large_hidden_variable_changes = 0;
+		smallest_changes_optimal_offsets = 999.;
+		smallest_changes_optimal_orientations = 999.;
+		current_changes_optimal_orientations = 999.;
+		current_changes_optimal_offsets = 999.;
+
+		// If we're realigning movie frames, then now read in the metadata of the movie frames and combine with the metadata of the average images
+		mydata.expandToMovieFrames(fn_data_movie);
+
+		// Now also modify the model to contain many more groups....
+		// each groups has to become Nframes groups (get Nframes from new mydata)
+		mymodel.expandToMovieFrames(mydata, movie_frame_running_avg_side);
+
+		// Don't do norm correction for realignment of movies.
+		do_norm_correction = false;
+
+	}
+
+	if (mymodel.nr_classes > 1 && do_split_random_halves)
+		REPORT_ERROR("ERROR: One cannot use --split_random_halves with more than 1 reference... You could first classify, and then refine each class separately using --random_halves.");
+
+	if (do_join_random_halves && !do_split_random_halves)
+		REPORT_ERROR("ERROR: cannot join random halves because they were not split in the previous run");
+
+	if (do_always_join_random_halves)
+		std::cout << " Joining half-reconstructions at each iteration: this is a developmental option to test sub-optimal FSC usage only! " << std::endl;
+
+	// If fn_tau is provided, read in the tau spectrum
+	fix_tau = false;
+	if (fn_tau != "None")
+	{
+		fix_tau = true;
+		mymodel.readTauSpectrum(fn_tau, verb);
+	}
+
+
+	// Initialise the sampling object (sets prior mode and fills translations and rotations inside sampling object)
+	sampling.initialise(mymodel.orientational_prior_mode, mymodel.ref_dim, false);
+
+	// Default max_coarse_size is original size
+	if (max_coarse_size < 0)
+		max_coarse_size = mymodel.ori_size;
+
+	if (particle_diameter < 0.)
+    	particle_diameter = (mymodel.ori_size - width_mask_edge) * mymodel.pixel_size;
+
+	if (do_auto_refine)
+	{
+		nr_iter = 999;
+		has_fine_enough_angular_sampling = false;
+	}
+
+    // For do_average_unaligned, always use initial low_pass filter
+    if (do_average_unaligned && ini_high < 0.)
+    {
+    	// By default, use 0.07 dig.freq. low-pass filter
+    	// See S.H.W. Scheres (2010) Meth Enzym.
+    	ini_high = 1./mymodel.getResolution(ROUND(0.07 * mymodel.ori_size));
+    }
+
+    // Fill tabulated sine and cosine tables
+    tab_sin.initialise(5000);
+    tab_cos.initialise(5000);
+
+	// For skipped alignments: set nr_pool to one to have each thread work on one particle (with its own unique sampling arrays of 1 orientation and translation)
+	// Also do not perturb this orientation, nor do oversampling or priors
+	if (do_skip_align || do_skip_rotate)
+	{
+		mymodel.orientational_prior_mode = NOPRIOR;
+		sampling.orientational_prior_mode = NOPRIOR;
+		adaptive_oversampling = 0;
+		nr_pool = max_nr_pool = 1;
+		sampling.perturbation_factor = 0.;
+		sampling.random_perturbation = 0.;
+		sampling.setOneOrientation(0.,0.,0.);
+		directions_have_changed = true;
+		if (do_realign_movies)
+			nr_threads = 1; // use only one thread, as there are no particles/orientations to parallelise anyway...
+		if (do_skip_align)
+		{
+			Matrix1D<double> offset(2);
+			sampling.setOneTranslation(offset);
+		}
+	}
+
+	// Resize the pdf_direction arrays to the correct size and fill with an even distribution
+	if (directions_have_changed)
+		mymodel.initialisePdfDirection(sampling.NrDirections(0, true));
+
+	// Initialise the wsum_model according to the mymodel
+	wsum_model.initialise(mymodel, sampling.symmetryGroup());
+
+	// Check that number of pooled particles is not larger than 1 for local angular searches
+	// Because for local searches, each particle has a different set of nonzeroprior orientations, and thus a differently sized Mweight
+	// If larger than 1, just reset to 1
+	if (mymodel.orientational_prior_mode != NOPRIOR && max_nr_pool > 1)
+	{
+		if (verb > 0)
+			std::cout << " Performing local angular searches! Lowering max_nr_pool from "<<max_nr_pool<<" to 1!" << std::endl;
+		max_nr_pool = 1;
+	}
+
+	// Initialise sums of hidden variable changes
+	// In later iterations, this will be done in updateOverallChangesInHiddenVariables
+	sum_changes_optimal_orientations = 0.;
+	sum_changes_optimal_offsets = 0.;
+	sum_changes_optimal_classes = 0.;
+	sum_changes_count = 0.;
+
+	// Skip scale correction if there are nor groups
+	if (mymodel.nr_groups == 1)
+		do_scale_correction = false;
+
+	// Check for rlnReconstructImageName in the data.star file. If it is present, set do_use_reconstruct_images to true
+	do_use_reconstruct_images = mydata.MDimg.containsLabel(EMDL_IMAGE_RECONSTRUCT_NAME);
+	if (do_use_reconstruct_images && verb > 0)
+		std::cout <<" Using rlnReconstructImageName from the input data.star file!" << std::endl;
+
+#ifdef DEBUG
+	std::cerr << "Leaving initialiseGeneral" << std::endl;
+#endif
+
+}
+
+void MlOptimiser::initialiseWorkLoad()
+{
+
+	// Note, this function is overloaded in ml_optimiser_mpi...
+
+	// Randomise the order of the particles
+	if (random_seed == -1) random_seed = time(NULL);
+    // This is for the division into random classes
+	mydata.randomiseOriginalParticlesOrder(random_seed);
+    // Also randomize random-number-generator for perturbations on the angles
+    init_random_generator(random_seed);
+
+    divide_equally(mydata.numberOfOriginalParticles(), 1, 0, my_first_ori_particle_id, my_last_ori_particle_id);
+
+}
+
+void MlOptimiser::calculateSumOfPowerSpectraAndAverageImage(MultidimArray<double> &Mavg, bool myverb)
+{
+
+#ifdef DEBUG_INI
+    std::cerr<<"MlOptimiser::calculateSumOfPowerSpectraAndAverageImage Entering"<<std::endl;
+#endif
+
+    int barstep, my_nr_ori_particles = my_last_ori_particle_id - my_first_ori_particle_id + 1;
+	if (myverb > 0)
+	{
+		std::cout << " Estimating initial noise spectra " << std::endl;
+		init_progress_bar(my_nr_ori_particles);
+		barstep = XMIPP_MAX(1, my_nr_ori_particles / 60);
+	}
+
+	// Note the loop over the particles (part_id) is MPI-parallelized
+	int nr_ori_particles_done = 0;
+	Image<double> img;
+	FileName fn_img;
+	MultidimArray<double> ind_spectrum, sum_spectrum, count;
+	// For spectrum calculation: recycle the transformer (so do not call getSpectrum all the time)
+	MultidimArray<Complex > Faux;
+    Matrix1D<double> f(3);
+    FourierTransformer transformer;
+	MetaDataTable MDimg;
+
+	for (long int ori_part_id = my_first_ori_particle_id; ori_part_id <= my_last_ori_particle_id; ori_part_id++, nr_ori_particles_done++)
+	{
+
+		for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++)
+		{
+			long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+
+			for (int iseries = 0; iseries < mydata.getNrImagesInSeries(part_id); iseries++)
+			{
+
+				long int group_id = mydata.getGroupId(part_id, iseries);
+				// TMP test for debuging
+				if (group_id < 0 || group_id >= mymodel.nr_groups)
+				{
+					std::cerr << " group_id= " << group_id << std::endl;
+					REPORT_ERROR("MlOptimiser::calculateSumOfPowerSpectraAndAverageImage: bad group_id");
+				}
+
+				// Extract the relevant MetaDataTable row from MDimg
+				MDimg = mydata.getMetaDataImage(part_id, iseries);
+
+				// Get the image filename
+				MDimg.getValue(EMDL_IMAGE_NAME, fn_img);
+
+				// Read image from disc
+				img.read(fn_img);
+				img().setXmippOrigin();
+
+				// Check that the average in the noise area is approximately zero and the stddev is one
+				if (!dont_raise_norm_error)
+				{
+					int bg_radius2 = ROUND(particle_diameter / (2. * mymodel.pixel_size));
+					bg_radius2 *= bg_radius2;
+					double sum = 0.;
+					double sum2 = 0.;
+					double nn = 0.;
+					FOR_ALL_ELEMENTS_IN_ARRAY3D(img())
+					{
+						if (k*k+i*i+j*j > bg_radius2)
+						{
+							sum += A3D_ELEM(img(), k, i, j);
+							sum2 += A3D_ELEM(img(), k, i, j) * A3D_ELEM(img(), k, i, j);
+							nn += 1.;
+						}
+					}
+					// stddev
+					sum2 -= sum*sum/nn;
+					sum2 = sqrt(sum2/nn);
+					//average
+					sum /= nn;
+
+					// Average should be close to zero, i.e. max +/-50% of stddev...
+					// Stddev should be close to one, i.e. larger than 0.5 and smaller than 2)
+					if (ABS(sum/sum2) > 0.5 || sum2 < 0.5 || sum2 > 2.0)
+					{
+						std::cerr << " fn_img= " << fn_img << " bg_avg= " << sum << " bg_stddev= " << sum2 << std::endl;
+						REPORT_ERROR("ERROR: It appears that these images have not been normalised to an average background value of 0 and a stddev value of 1. \n \
+								Note that the average and stddev values for the background are calculated outside a circle with the particle diameter \n \
+								You can use the relion_preprocess program to normalise your images \n \
+								If you are sure you have normalised the images correctly (also see the RELION Wiki), you can switch off this error message using the --dont_check_norm command line option");
+					}
+				}
+
+				// Apply a similar softMask as below (assume zero translations)
+				if (do_zero_mask)
+					softMaskOutsideMap(img(), particle_diameter / (2. * mymodel.pixel_size), width_mask_edge);
+
+				// Calculate this image's power spectrum in: ind_spectrum
+				ind_spectrum.initZeros(XSIZE(img()));
+			    count.initZeros(XSIZE(img()));
+			    // recycle the same transformer for all images
+			    transformer.FourierTransform(img(), Faux, false);
+			    FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Faux)
+			    {
+			    	long int idx = ROUND(sqrt(kp*kp + ip*ip + jp*jp));
+			    	ind_spectrum(idx) += norm(dAkij(Faux, k, i, j));
+			        count(idx) += 1.;
+			    }
+			    ind_spectrum /= count;
+
+				// Resize the power_class spectrum to the correct size and keep sum
+				ind_spectrum.resize(wsum_model.sigma2_noise[0]); // Store sum of all groups in group 0
+				wsum_model.sigma2_noise[0] += ind_spectrum;
+				wsum_model.sumw_group[0] += 1.;
+				mymodel.nr_particles_group[group_id] += 1;
+
+
+				// Also calculate average image
+				if (part_id == mydata.ori_particles[my_first_ori_particle_id].particles_id[0])
+					Mavg = img();
+				else
+					Mavg += img();
+
+			} // end loop iseries
+		} // end loop part_id (i)
+
+		if (myverb > 0 && nr_ori_particles_done % barstep == 0)
+			progress_bar(nr_ori_particles_done);
+
+	} // end loop ori_part_id
+
+
+	// Clean up the fftw object completely
+	// This is something that needs to be done manually, as among multiple threads only one of them may actually do this
+	transformer.cleanup();
+
+	if (myverb > 0)
+		progress_bar(my_nr_ori_particles);
+
+#ifdef DEBUG_INI
+    std::cerr<<"MlOptimiser::calculateSumOfPowerSpectraAndAverageImage Leaving"<<std::endl;
+#endif
+
+}
+
+void MlOptimiser::setSigmaNoiseEstimatesAndSetAverageImage(MultidimArray<double> &Mavg)
+{
+
+#ifdef DEBUG_INI
+    std::cerr<<"MlOptimiser::setSigmaNoiseEstimatesAndSetAverageImage Entering"<<std::endl;
+#endif
+
+	// First calculate average image
+	Mavg /= wsum_model.sumw_group[0];
+
+	// for 2D refinements set 2D average to all references
+	if (do_average_unaligned)
+	{
+		for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+			mymodel.Iref[iclass] = Mavg;
+	}
+
+	// Calculate sigma2_noise estimates as average of power class spectra, and subtract power spectrum of the average image from that
+	if (do_calculate_initial_sigma_noise)
+	{
+		// Factor 2 because of 2-dimensionality of the complex plane
+		mymodel.sigma2_noise[0] = wsum_model.sigma2_noise[0] / ( 2. * wsum_model.sumw_group[0] );
+
+		// Calculate power spectrum of the average image
+		MultidimArray<double> spect;
+		getSpectrum(Mavg, spect, POWER_SPECTRUM);
+		spect /= 2.; // because of 2-dimensionality of the complex plane
+
+		// Now subtract power spectrum of the average image from the average power spectrum of the individual images
+		spect.resize(mymodel.sigma2_noise[0]);
+		mymodel.sigma2_noise[0] -= spect;
+
+		// Set the same spectrum for all groups
+		for (int igroup = 0; igroup < mymodel.nr_groups; igroup++)
+			mymodel.sigma2_noise[igroup] = mymodel.sigma2_noise[0];
+	}
+
+
+#ifdef DEBUG_INI
+    std::cerr<<"MlOptimiser::setSigmaNoiseEstimatesAndSetAverageImage Leaving"<<std::endl;
+#endif
+
+}
+
+void MlOptimiser::initialLowPassFilterReferences()
+{
+	if (ini_high > 0.)
+	{
+
+		// Make a soft (raised cosine) filter in Fourier space to prevent artefacts in real-space
+		// The raised cosine goes through 0.5 at the filter frequency and has a width of width_mask_edge fourier pixels
+		double radius = mymodel.ori_size * mymodel.pixel_size / ini_high;
+		radius -= WIDTH_FMASK_EDGE / 2.;
+		double radius_p = radius + WIDTH_FMASK_EDGE;
+		FourierTransformer transformer;
+		MultidimArray<Complex > Faux;
+		for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+		{
+			transformer.FourierTransform(mymodel.Iref[iclass], Faux);
+			FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Faux)
+			{
+				double r = sqrt((double)(kp*kp + ip*ip + jp*jp));
+				if (r < radius)
+					continue;
+				else if (r > radius_p)
+					DIRECT_A3D_ELEM(Faux, k, i, j) = 0.;
+				else
+				{
+					DIRECT_A3D_ELEM(Faux, k, i, j) *= 0.5 - 0.5 * cos(PI * (radius_p - r) / WIDTH_FMASK_EDGE);
+				}
+			}
+			transformer.inverseFourierTransform(Faux, mymodel.Iref[iclass]);
+		}
+
+	}
+
+}
+
+/** ========================== EM-Iteration  ================================= */
+
+void MlOptimiser::iterateSetup()
+{
+
+	// Make a barrier where all working threads wait
+	global_barrier = new Barrier(nr_threads - 1);
+
+    // Create threads to start working
+	global_ThreadManager = new ThreadManager(nr_threads, this);
+
+	// Set up the thread task distributors for the particles and the orientations (will be resized later on)
+	exp_ipart_ThreadTaskDistributor = new ThreadTaskDistributor(1, 1);
+	exp_iorient_ThreadTaskDistributor = new ThreadTaskDistributor(1, 1);
+
+}
+void MlOptimiser::iterateWrapUp()
+{
+
+	// delete barrier, threads and task distributors
+    delete global_barrier;
+	delete global_ThreadManager;
+    delete exp_iorient_ThreadTaskDistributor;
+    delete exp_ipart_ThreadTaskDistributor;
+
+}
+
+void MlOptimiser::iterate()
+{
+
+	if (do_split_random_halves)
+		REPORT_ERROR("ERROR: Cannot split data into random halves without using MPI!");
+
+
+	// launch threads etc
+	iterateSetup();
+
+	// Update the current resolution and image sizes, and precalculate resolution pointers
+	// The rest of the time this will be done after maximization and before writing output files,
+	// so that current resolution is in the output files of the current iteration
+	updateCurrentResolution();
+
+	bool has_already_reached_convergence = false;
+	for (iter = iter + 1; iter <= nr_iter; iter++)
+    {
+
+#ifdef TIMING
+		timer.tic(TIMING_EXP);
+#endif
+
+		// SA-stuff
+		if (do_sim_anneal)
+		{
+			double tau = -nr_iter / (std::log(temp_fin/temp_ini));
+			temperature = temp_ini * exp(-iter/tau);
+			std::cout << " temperature= " << temperature << std::endl;
+		}
+
+		if (do_auto_refine)
+			printConvergenceStats();
+
+		expectation();
+
+#ifdef TIMING
+		timer.toc(TIMING_EXP);
+		timer.tic(TIMING_MAX);
+#endif
+
+		if (do_skip_maximization)
+		{
+			// Only write data.star file and break from the iteration loop
+			write(DONT_WRITE_SAMPLING, DO_WRITE_DATA, DONT_WRITE_OPTIMISER, DONT_WRITE_MODEL, 0);
+			break;
+		}
+
+		maximization();
+
+#ifdef TIMING
+		timer.toc(TIMING_MAX);
+#endif
+
+		// Apply masks to the reference images
+		// At the last iteration, do not mask the map for validation purposes
+		if (do_solvent && !has_converged)
+			solventFlatten();
+
+		// Re-calculate the current resolution, do this before writing to get the correct values in the output files
+		updateCurrentResolution();
+
+		// Write output files
+		write(DO_WRITE_SAMPLING, DO_WRITE_DATA, DO_WRITE_OPTIMISER, DO_WRITE_MODEL, 0);
+
+		if (do_auto_refine && has_converged)
+		{
+			if (verb > 0)
+			{
+				std::cout << " Auto-refine: Refinement has converged, stopping now... " << std::endl;
+				std::cout << " Auto-refine: + Final reconstruction from all particles is saved as: " <<  fn_out << "_class001.mrc" << std::endl;
+				std::cout << " Auto-refine: + Final model parameters are stored in: " << fn_out << "_model.star" << std::endl;
+				std::cout << " Auto-refine: + Final data parameters are stored in: " << fn_out << "_data.star" << std::endl;
+				std::cout << " Auto-refine: + Final resolution (without masking) is: " << 1./mymodel.current_resolution << std::endl;
+				if (acc_rot < 10.)
+					std::cout << " Auto-refine: + But you may want to run relion_postprocess to mask the unfil.mrc maps and calculate a higher resolution FSC" << std::endl;
+				else
+				{
+					std::cout << " Auto-refine: + WARNING: The angular accuracy is worse than 10 degrees, so basically you cannot align your particles!" << std::endl;
+					std::cout << " Auto-refine: + WARNING: This has been observed to lead to spurious FSC curves, so be VERY wary of inflated resolution estimates..." << std::endl;
+					std::cout << " Auto-refine: + WARNING: You most probably do NOT want to publish these results!" << std::endl;
+					std::cout << " Auto-refine: + WARNING: Sometimes it is better to tune resolution yourself by adjusting T in a 3D-classification with a single class." << std::endl;
+				}
+			}
+			break;
+		}
+
+		// Check whether we have converged by now
+		// If we have, set do_join_random_halves and do_use_all_data for the next iteration
+		if (do_auto_refine)
+			checkConvergence();
+
+#ifdef TIMING
+    	if (verb > 0)
+    		timer.printTimes(false);
+#endif
+
+    }
+
+	// delete threads etc
+	iterateWrapUp();
+}
+
+void MlOptimiser::expectation()
+{
+
+//#define DEBUG_EXP
+#ifdef DEBUG_EXP
+	std::cerr << "Entering expectation" << std::endl;
+#endif
+
+	// Initialise some stuff
+	// A. Update current size (may have been changed to ori_size in autoAdjustAngularSampling) and resolution pointers
+	updateImageSizeAndResolutionPointers();
+
+	// B. Initialise Fouriertransform, set weights in wsum_model to zero, etc
+	expectationSetup();
+
+#ifdef DEBUG_EXP
+	std::cerr << "Expectation: done setup" << std::endl;
+#endif
+
+	// C. Calculate expected minimum angular errors (only for 3D refinements)
+	// And possibly update orientational sampling automatically
+	// TODO: also implement estimate angular sampling for 3D refinements
+	if (!((iter==1 && do_firstiter_cc) || do_always_cc) && !do_skip_align)
+	{
+		// Set the exp_metadata (but not the exp_imagedata which is not needed for calculateExpectedAngularErrors)
+		int n_trials_acc = (mymodel.ref_dim==3) ? 100 : 10;
+		n_trials_acc = XMIPP_MIN(n_trials_acc, mydata.numberOfOriginalParticles());
+		getMetaAndImageDataSubset(0, n_trials_acc-1, false);
+		calculateExpectedAngularErrors(0, n_trials_acc-1);
+	}
+
+	// D. Update the angular sampling (all nodes except master)
+	if ( iter > 1 && (do_auto_refine) )
+		updateAngularSampling();
+
+	// E. Check whether everything fits into memory, possibly adjust nr_pool and setup thread task managers
+	expectationSetupCheckMemory();
+
+#ifdef DEBUG_EXP
+	std::cerr << "Expectation: done setupCheckMemory" << std::endl;
+#endif
+	if (verb > 0)
+	{
+		std::cout << " Expectation iteration " << iter;
+		if (!do_auto_refine)
+			std::cout << " of " << nr_iter;
+		std::cout << std::endl;
+		init_progress_bar(mydata.numberOfOriginalParticles());
+	}
+
+	int barstep = XMIPP_MAX(1, mydata.numberOfOriginalParticles() / 60);
+	long int prev_barstep = 0, nr_ori_particles_done = 0;
+
+	// Now perform real expectation over all particles
+	// Use local parameters here, as also done in the same overloaded function in MlOptimiserMpi
+	long int my_first_ori_particle, my_last_ori_particle;
+	while (nr_ori_particles_done < mydata.numberOfOriginalParticles())
+	{
+
+		my_first_ori_particle = nr_ori_particles_done;
+		my_last_ori_particle = XMIPP_MIN(mydata.numberOfOriginalParticles() - 1, my_first_ori_particle + nr_pool - 1);
+
+		// Get the metadata for these particles
+		getMetaAndImageDataSubset(my_first_ori_particle, my_last_ori_particle);
+
+		// perform the actual expectation step on several particles
+		expectationSomeParticles(my_first_ori_particle, my_last_ori_particle);
+
+		// Set the metadata for these particles
+		setMetaDataSubset(my_first_ori_particle, my_last_ori_particle);
+
+		// Also monitor the changes in the optimal orientations and classes
+		monitorHiddenVariableChanges(my_first_ori_particle, my_last_ori_particle);
+
+		nr_ori_particles_done += my_last_ori_particle - my_first_ori_particle + 1;
+
+		if (verb > 0 && nr_ori_particles_done - prev_barstep > barstep)
+		{
+			prev_barstep = nr_ori_particles_done;
+			progress_bar(nr_ori_particles_done);
+		}
+	}
+
+	if (verb > 0)
+		progress_bar(mydata.numberOfOriginalParticles());
+
+	// Clean up some memory
+	for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+		mymodel.PPref[iclass].data.clear();
+#ifdef DEBUG_EXP
+	std::cerr << "Expectation: done " << std::endl;
+#endif
+
+}
+
+
+void MlOptimiser::expectationSetup()
+{
+#ifdef DEBUG
+	std::cerr << "Entering expectationSetup" << std::endl;
+#endif
+
+	// Re-initialise the random seed, because with a noisy_mask, inside the previous iteration different timings of different MPI nodes may have given rise to different number of calls to ran1
+	// Use the iteration number so that each iteration has a different random seed
+	init_random_generator(random_seed + iter);
+
+	// Reset the random perturbation for this sampling
+	sampling.resetRandomlyPerturbedSampling();
+
+    // Initialise Projectors and fill vector with power_spectra for all classes
+	mymodel.setFourierTransformMaps(!fix_tau, nr_threads);
+
+	// Initialise all weighted sums to zero
+	wsum_model.initZeros();
+
+}
+
+void MlOptimiser::expectationSetupCheckMemory(bool myverb)
+{
+
+	if (mymodel.orientational_prior_mode != NOPRIOR)
+	{
+		// First select one random direction and psi-angle for selectOrientationsWithNonZeroPriorProbability
+		// This is to get an idea how many non-zero probabilities there will be
+		double ran_rot, ran_tilt, ran_psi;
+		int randir = (int)(rnd_unif() * sampling.NrDirections(0, true) );
+		int ranpsi = (int)(rnd_unif() * sampling.NrPsiSamplings(0, true) );
+		if (randir == sampling.NrDirections(0, true))
+		{
+			//TMP
+			REPORT_ERROR("RANDIR WAS TOO BIG!!!!");
+			randir--;
+		}
+		if (ranpsi == sampling.NrPsiSamplings(0, true))
+		{
+			//TMP
+			REPORT_ERROR("RANPSI WAS TOO BIG!!!!");
+			ranpsi--;
+		}
+		sampling.getDirection(randir, ran_rot, ran_tilt);
+		sampling.getPsiAngle(ranpsi, ran_psi);
+		// Calculate local searches for these angles
+		sampling.selectOrientationsWithNonZeroPriorProbability(ran_rot, ran_tilt, ran_psi,
+								sqrt(mymodel.sigma2_rot), sqrt(mymodel.sigma2_tilt), sqrt(mymodel.sigma2_psi));
+	}
+
+	// Check whether things will fit into memory
+	// Each double takes 8 bytes, and their are mymodel.nr_classes references, express in Gb
+	double Gb = sizeof(double) / (1024. * 1024. * 1024.);
+	// A. Calculate approximate size of the reference maps
+	// Forward projector has complex data, backprojector has complex data and real weight
+	double mem_references = Gb * mymodel.nr_classes * (2 * MULTIDIM_SIZE((mymodel.PPref[0]).data) + 3 * MULTIDIM_SIZE((wsum_model.BPref[0]).data));
+	// B. Calculate size of the exp_Mweight matrices with (YSIZE=nr_pool, XSIZE=mymodel.nr_classes * sampling.NrSamplingPoints(adaptive_oversampling)
+	nr_pool = max_nr_pool;
+
+	if (mydata.maxNumberOfImagesPerOriginalParticle() > 1)
+	{
+		// Make sure that all particles in the data set have the same number of images
+		// with the same transformation matrices so that their exp_R_mic can be re-used for pooled particles
+		// If there are some particles with different transformations, then just set nr_pool to one
+		// TODO: optimize this for randomised particle order.....
+		// Currently that will lead to pretty bad efficiency IF there are multiple different tilt angles....
+		// Or perhaps just forget about pooling. If we're re-refining the orientations that will be screwed anyway...
+
+		// First find a particle with the maxNumberOfImagesPerParticle
+		long int ref_part;
+		long int maxn = mydata.maxNumberOfImagesPerOriginalParticle();
+		for (ref_part = 0; ref_part < mydata.numberOfParticles(); ref_part++)
+		{
+			if (mydata.getNrImagesInSeries(ref_part) == maxn)
+				break;
+		}
+
+		// Then check the transformation matrices for all the other particles are all the same
+		// Note that particles are allowed to have fewer images in their series...
+		Matrix2D<double> first_R_mic, test_R_mic;
+		bool is_ok = true;
+		for (long int ipart = 0; ipart < mydata.numberOfParticles(); ipart++)
+		{
+			for (int iseries = 0; iseries < mydata.getNrImagesInSeries(ipart); iseries++)
+			{
+				first_R_mic = mydata.getMicrographTransformationMatrix(ref_part, iseries);
+				test_R_mic = mydata.getMicrographTransformationMatrix(ipart, iseries);
+				if (!first_R_mic.equal(test_R_mic))
+				{
+					is_ok = false;
+					break;
+				}
+			}
+		}
+		if (!is_ok)
+		{
+			// Don't pool particles to prevent trouble when re-using exp_R_mic...
+			nr_pool = 1;
+			if (myverb > 0)
+				std::cout << " Switching off the pooling of particles because there are some series with distinct transformation matrices present in the data... ";
+		}
+	}
+
+	double mem_pool = Gb * nr_pool * mymodel.nr_classes * sampling.NrSamplingPoints(adaptive_oversampling, false);
+	// Estimate the rest of the program at 0.1 Gb?
+	double mem_rest = 0.1;
+	double total_mem_Gb_exp = mem_references + mem_pool + mem_rest;
+	// Each reconstruction has to store 1 extra complex array (Fconv) and 4 extra double arrays (Fweight, Fnewweight. vol_out and Mconv in convoluteBlobRealSpace),
+	// in adddition to the double weight-array and the complex data-array of the BPref
+	// That makes a total of 2*2 + 5 = 9 * a double array of size BPref
+	double total_mem_Gb_max = Gb * 9 * MULTIDIM_SIZE((wsum_model.BPref[0]).data);
+
+	bool exp_does_not_fit = false;
+	if (total_mem_Gb_exp > available_memory * nr_threads_original)
+	{
+		double mem_for_pool = (available_memory * nr_threads_original) - mem_rest - mem_references;
+		int suggested_nr_pool = FLOOR(mem_for_pool / (Gb * mymodel.nr_classes * sampling.NrSamplingPoints(adaptive_oversampling, true)));
+		if (suggested_nr_pool > 0)
+		{
+			if (myverb > 0)
+			{
+				std::cout << "Reducing nr_pool to "<< suggested_nr_pool<<" to still fit into memory" << std::endl;
+			}
+			nr_pool = suggested_nr_pool;
+			mem_pool = Gb * nr_pool * mymodel.nr_classes * sampling.NrSamplingPoints(adaptive_oversampling, false);
+			total_mem_Gb_exp = mem_references + mem_pool + mem_rest;
+		}
+		else
+		{
+			exp_does_not_fit = true;
+		}
+	}
+
+	if (myverb > 0)
+	{
+		// Calculate number of sampled hidden variables:
+		int nr_ang_steps = CEIL(PI * particle_diameter * mymodel.current_resolution);
+		double myresol_angstep = 360. / nr_ang_steps;
+		std::cout << " CurrentResolution= " << 1./mymodel.current_resolution << " Angstroms, which requires orientationSampling of at least "<< myresol_angstep
+				   <<" degrees for a particle of diameter "<< particle_diameter << " Angstroms"<< std::endl;
+		for (int oversampling = 0; oversampling <= adaptive_oversampling; oversampling++)
+		{
+			std::cout << " Oversampling= " << oversampling << " NrHiddenVariableSamplingPoints= " << mymodel.nr_classes * sampling.NrSamplingPoints(oversampling, true) << std::endl;
+			std::cout << " OrientationalSampling= " << sampling.getAngularSampling(oversampling)
+				<< " NrOrientations= "<<sampling.NrDirections(oversampling, false)*sampling.NrPsiSamplings(oversampling, false)<<std::endl;
+			std::cout << " TranslationalSampling= " << sampling.getTranslationalSampling(oversampling)
+				<< " NrTranslations= "<<sampling.NrTranslationalSamplings(oversampling)<< std::endl;
+			std::cout << "=============================" << std::endl;
+		}
+	}
+
+	if (myverb > 0)
+	{
+		std::cout << " Estimated memory for expectation step  > " << total_mem_Gb_exp << " Gb, available memory = "<<available_memory * nr_threads_original<<" Gb."<<std::endl;
+		std::cout << " Estimated memory for maximization step > " << total_mem_Gb_max << " Gb, available memory = "<<available_memory * nr_threads_original<<" Gb."<<std::endl;
+
+		if (total_mem_Gb_max > available_memory * nr_threads_original || exp_does_not_fit)
+		{
+			if (exp_does_not_fit)
+			std::cout << " WARNING!!! Expected to run out of memory during expectation step ...." << std::endl;
+			if (total_mem_Gb_max > available_memory * nr_threads_original)
+			std::cout << " WARNING!!! Expected to run out of memory during maximization step ...." << std::endl;
+			std::cout << " WARNING!!! Did you set --memory_per_thread to reflect the number of Gb per core on your computer?" << std::endl;
+			std::cout << " WARNING!!! If so, then check your processes are not swapping and consider running fewer MPI processors per node." << std::endl;
+			std::cout << " + Available memory for each thread, as given by --memory_per_thread      : " << available_memory << " Gb" << std::endl;
+			std::cout << " + Number of threads used per MPI process, as given by --j                : " << nr_threads_original << std::endl;
+			std::cout << " + Available memory per MPI process 										: " << available_memory * nr_threads_original << " Gb" << std::endl;
+		}
+	}
+
+	// Now that we also have nr_pool, resize the task manager for the particles
+
+	/// When there are multiple particles for each ori_particle, then this ThreadTaskDistributor will again be resized somewhere below
+	exp_ipart_ThreadTaskDistributor->resize(nr_pool, 1);
+
+	// Also resize task manager for the orientations in case of NOPRIOR (otherwise resizing is done in doThreadGetFourierTransformsAndCtfs)
+	if (do_skip_align || do_skip_rotate)
+	{
+		exp_iorient_ThreadTaskDistributor->resize(1, 1);
+	}
+	else if (mymodel.orientational_prior_mode == NOPRIOR)
+	{
+		long int nr_orients = sampling.NrDirections() * sampling.NrPsiSamplings();
+		int threadBlockSize = (nr_orients > 100) ? 10 : 1;
+		exp_iorient_ThreadTaskDistributor->resize(nr_orients, threadBlockSize);
+	}
+#ifdef DEBUG
+	std::cerr << "Leaving expectationSetup" << std::endl;
+#endif
+
+}
+
+void MlOptimiser::expectationSomeParticles(long int my_first_ori_particle, long int my_last_ori_particle)
+{
+
+#ifdef TIMING
+	timer.tic(TIMING_ESP);
+#endif
+
+//#define DEBUG_EXPSINGLE
+#ifdef DEBUG_EXPSINGLE
+	std::cerr << "Entering expectationSomeParticles..." << std::endl;
+#endif
+
+#ifdef TIMING
+    timer.tic(TIMING_ESP);
+    timer.tic(TIMING_ESP_READ);
+#endif
+
+    // Use global variables for thread visibility
+	exp_my_first_ori_particle = my_first_ori_particle;
+    exp_my_last_ori_particle = my_last_ori_particle;
+    exp_nr_ori_particles = exp_my_last_ori_particle - exp_my_first_ori_particle + 1;
+
+    // Find out how many particles there are in these ori_particles
+    exp_nr_particles = 0;
+    for (long int i = my_first_ori_particle; i <= my_last_ori_particle; i++)
+    	exp_nr_particles += mydata.ori_particles[i].particles_id.size();
+
+    // If there are more than one particle in each ori_particle, then do these in parallel with threads
+    if (nr_pool == 1 && exp_nr_particles/exp_nr_ori_particles > 1)
+    {
+    	int my_pool = exp_nr_particles/exp_nr_ori_particles;
+    	exp_ipart_ThreadTaskDistributor->resize(my_pool, 1);
+    }
+
+    // TODO: MAKE SURE THAT ALL PARTICLES IN SomeParticles ARE FROM THE SAME AREA, SO THAT THE R_mic CAN BE RE_USED!!!
+
+	// In the first iteration, multiple seeds will be generated
+	// A single random class is selected for each pool of images, and one does not marginalise over the orientations
+	// The optimal orientation is based on signal-product (rather than the signal-intensity sensitive Gaussian)
+    // If do_firstiter_cc, then first perform a single iteration with K=1 and cross-correlation criteria, afterwards
+
+    // Generally: use all references
+    iclass_min = 0;
+    iclass_max = mymodel.nr_classes - 1;
+    // low-pass filter again and generate the seeds
+    if (do_generate_seeds)
+    {
+    	if (do_firstiter_cc && iter == 1)
+    	{
+    		// In first (CC) iter, use a single reference (and CC)
+    		iclass_min = iclass_max = 0;
+    	}
+    	else if ( (do_firstiter_cc && iter == 2) || (!do_firstiter_cc && iter == 1))
+		{
+			// In second CC iter, or first iter without CC: generate the seeds
+    		// Now select a single random class
+    		// exp_part_id is already in randomized order (controlled by -seed)
+    		// WARNING: USING SAME iclass_min AND iclass_max FOR SomeParticles!!
+			iclass_min = iclass_max = divide_equally_which_group(mydata.numberOfOriginalParticles(), mymodel.nr_classes, exp_my_first_ori_particle);
+		}
+    }
+
+	// TODO: think of a way to have the different images in a single series have DIFFERENT offsets!!!
+	// Right now, they are only centered with a fixed relative translation!!!!
+
+// Thid debug is a good one to step through the separate steps of the expectation to see where trouble lies....
+//#define DEBUG_ESP_MEM
+#ifdef DEBUG_ESP_MEM
+	char c;
+	std::cerr << "Before getFourierTransformsAndCtfs, press any key to continue... " << std::endl;
+	std::cin >> c;
+#endif
+
+	// Read all image of this series into memory, apply old origin offsets and store Fimg, Fctf, exp_old_xoff and exp_old_yoff in vectors./
+
+	exp_ipart_ThreadTaskDistributor->reset();
+	global_ThreadManager->run(globalGetFourierTransformsAndCtfs);
+
+	if (do_realign_movies )//&& movie_frame_running_avg_side > 0)
+	{
+		calculateRunningAveragesOfMovieFrames();
+	}
+
+#ifdef DEBUG_ESP_MEM
+	std::cerr << "After getFourierTransformsAndCtfs, press any key to continue... " << std::endl;
+	std::cin >> c;
+#endif
+
+	#ifdef TIMING
+    timer.toc(TIMING_ESP_READ);
+#endif
+
+	// Initialise significant weight to minus one, so that all coarse sampling points will be handled in the first pass
+	exp_significant_weight.clear();
+	exp_significant_weight.resize(exp_nr_particles);
+	for (int n = 0; n < exp_nr_particles; n++)
+		exp_significant_weight[n] = -1.;
+
+	// Number of rotational and translational sampling points
+	exp_nr_trans = sampling.NrTranslationalSamplings();
+
+	exp_nr_dir = sampling.NrDirections();
+	exp_nr_psi = sampling.NrPsiSamplings();
+	exp_nr_rot = exp_nr_dir * exp_nr_psi;
+
+	// Only perform a second pass when using adaptive oversampling
+	int nr_sampling_passes = (adaptive_oversampling > 0) ? 2 : 1;
+
+	// Pass twice through the sampling of the entire space of rot, tilt and psi
+	// The first pass uses a coarser angular sampling and possibly smaller FFTs than the second pass.
+	// Only those sampling points that contribute to the highest x% of the weights in the first pass are oversampled in the second pass
+	// Only those sampling points will contribute to the weighted sums in the third loop below
+	for (exp_ipass = 0; exp_ipass < nr_sampling_passes; exp_ipass++)
+	{
+
+		if (strict_highres_exp > 0.)
+			// Use smaller images in both passes and keep a maximum on coarse_size, just like in FREALIGN
+			exp_current_image_size = coarse_size;
+		else if (adaptive_oversampling > 0)
+			// Use smaller images in the first pass, larger ones in the second pass
+			exp_current_image_size = (exp_ipass == 0) ? coarse_size : mymodel.current_size;
+		else
+			exp_current_image_size = mymodel.current_size;
+
+		// Use coarse sampling in the first pass, oversampled one the second pass
+		exp_current_oversampling = (exp_ipass == 0) ? 0 : adaptive_oversampling;
+		exp_nr_oversampled_rot = sampling.oversamplingFactorOrientations(exp_current_oversampling);
+		exp_nr_oversampled_trans = sampling.oversamplingFactorTranslations(exp_current_oversampling);
+
+
+#ifdef DEBUG_ESP_MEM
+
+	std::cerr << "Before getAllSquaredDifferences, use top to see memory usage and then press any key to continue... " << std::endl;
+	std::cin >> c;
+#endif
+
+		// Calculate the squared difference terms inside the Gaussian kernel for all hidden variables
+		getAllSquaredDifferences();
+
+#ifdef DEBUG_ESP_MEM
+	std::cerr << "After getAllSquaredDifferences, use top to see memory usage and then press any key to continue... " << std::endl;
+	std::cin >> c;
+#endif
+
+		// Now convert the squared difference terms to weights,
+		// also calculate exp_sum_weight, and in case of adaptive oversampling also exp_significant_weight
+		convertAllSquaredDifferencesToWeights();
+
+#ifdef DEBUG_ESP_MEM
+	std::cerr << "After convertAllSquaredDifferencesToWeights, press any key to continue... " << std::endl;
+	std::cin >> c;
+#endif
+
+	}// end loop over 2 exp_ipass iterations
+
+
+	// For the reconstruction step use mymodel.current_size!
+	exp_current_image_size = mymodel.current_size;
+
+#ifdef DEBUG_ESP_MEM
+	std::cerr << "Before storeWeightedSums, press any key to continue... " << std::endl;
+	std::cin >> c;
+#endif
+	storeWeightedSums();
+
+	// Now calculate the optimal translation for each of the individual images in the series
+	//if (mydata.maxNumberOfImagesPerOriginalParticle(my_first_ori_particle, my_last_ori_particle) > 1 && !(do_firstiter_cc && iter == 1))
+	//	getOptimalOrientationsForIndividualImagesInSeries();
+
+#ifdef DEBUG_ESP_MEM
+	std::cerr << "After storeWeightedSums, press any key to continue... " << std::endl;
+	std::cin >> c;
+#endif
+#ifdef DEBUG_EXPSINGLE
+		std::cerr << "Leaving expectationSingleParticle..." << std::endl;
+#endif
+
+#ifdef TIMING
+	timer.toc(TIMING_ESP);
+#endif
+
+}
+
+void MlOptimiser::maximization()
+{
+
+	if (verb > 0)
+	{
+		std::cout << " Maximization ..." << std::endl;
+		init_progress_bar(mymodel.nr_classes);
+	}
+
+	// First reconstruct the images for each class
+	for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+	{
+		if (mymodel.pdf_class[iclass] > 0.)
+		{
+			(wsum_model.BPref[iclass]).reconstruct(mymodel.Iref[iclass], gridding_nr_iter, do_map,
+					mymodel.tau2_fudge_factor, mymodel.tau2_class[iclass], mymodel.sigma2_class[iclass],
+					mymodel.data_vs_prior_class[iclass], mymodel.fsc_halves_class[iclass], wsum_model.pdf_class[iclass],
+					false, false, nr_threads, minres_map);
+
+		}
+		else
+		{
+			mymodel.Iref[iclass].initZeros();
+		}
+
+		if (verb > 0)
+			progress_bar(iclass);
+	}
+
+	// Then perform the update of all other model parameters
+	maximizationOtherParameters();
+
+	// Keep track of changes in hidden variables
+	updateOverallChangesInHiddenVariables();
+
+	// This doesn't really work, and I need the original priors for the polishing...
+	//if (do_realign_movies)
+	//	updatePriorsForMovieFrames();
+
+	if (verb > 0)
+		progress_bar(mymodel.nr_classes);
+
+}
+
+void MlOptimiser::maximizationOtherParameters()
+{
+	// Note that reconstructions are done elsewhere!
+#ifdef DEBUG
+	std::cerr << "Entering maximizationOtherParameters" << std::endl;
+#endif
+
+	// Calculate total sum of weights, and average CTF for each class (for SSNR estimation)
+	double sum_weight = 0.;
+	for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+		sum_weight += wsum_model.pdf_class[iclass];
+
+	// Update average norm_correction
+	if (do_norm_correction)
+	{
+		mymodel.avg_norm_correction = wsum_model.avg_norm_correction / sum_weight;
+	}
+
+	if (do_scale_correction && !(iter==1 && do_firstiter_cc) )
+	{
+		double avg_scale_correction = 0., nr_part = 0.;
+		for (int igroup = 0; igroup < mymodel.nr_groups; igroup++)
+		{
+
+#ifdef DEVEL_BFAC
+			// TMP
+			if (verb>0)
+			{
+				for (int i=0; i<XSIZE(wsum_model.wsum_signal_product_spectra[igroup]); i++)
+				{
+					std::cout <<" igroup= "<<igroup<< " i= "<<i<<" "<<wsum_model.wsum_signal_product_spectra[igroup](i)<<" "<<wsum_model.wsum_reference_power_spectra[igroup](i)<<std::endl;
+				}
+			}
+#endif
+
+			double sumXA = wsum_model.wsum_signal_product_spectra[igroup].sum();
+			double sumAA = wsum_model.wsum_reference_power_spectra[igroup].sum();
+			if (sumAA > 0.)
+				mymodel.scale_correction[igroup] = sumXA / sumAA;
+			else
+				mymodel.scale_correction[igroup] = 1.;
+			avg_scale_correction += (double)(mymodel.nr_particles_group[igroup]) * mymodel.scale_correction[igroup];
+			nr_part += (double)(mymodel.nr_particles_group[igroup]);
+
+		}
+
+		// Constrain average scale_correction to one.
+		avg_scale_correction /= nr_part;
+		for (int igroup = 0; igroup < mymodel.nr_groups; igroup++)
+		{
+			mymodel.scale_correction[igroup] /= avg_scale_correction;
+//#define DEBUG_UPDATE_SCALE
+#ifdef DEBUG_UPDATE_SCALE
+			if (verb > 0)
+			{
+				std::cerr<< "Group "<<igroup+1<<": scale_correction= "<<mymodel.scale_correction[igroup]<<std::endl;
+				for (int i = 0; i < XSIZE(wsum_model.wsum_reference_power_spectra[igroup]); i++)
+					if (wsum_model.wsum_reference_power_spectra[igroup](i)> 0.)
+						std::cerr << " i= " << i << " XA= " << wsum_model.wsum_signal_product_spectra[igroup](i)
+											<< " A2= " << wsum_model.wsum_reference_power_spectra[igroup](i)
+											<< " XA/A2= " << wsum_model.wsum_signal_product_spectra[igroup](i)/wsum_model.wsum_reference_power_spectra[igroup](i) << std::endl;
+
+			}
+#endif
+		}
+
+	}
+
+	// Update model.pdf_class vector (for each k)
+	for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+	{
+		mymodel.pdf_class[iclass] = wsum_model.pdf_class[iclass] / sum_weight;
+
+		// for 2D also update priors of translations for each class!
+		if (mymodel.ref_dim == 2)
+		{
+			if (wsum_model.pdf_class[iclass] > 0.)
+				mymodel.prior_offset_class[iclass] = wsum_model.prior_offset_class[iclass] / wsum_model.pdf_class[iclass];
+			else
+				mymodel.prior_offset_class[iclass].initZeros();
+		}
+
+		// Use sampling.NrDirections(0, true) to include all directions (also those with zero prior probability for any given image)
+		for (int idir = 0; idir < sampling.NrDirections(0, true); idir++)
+		{
+			mymodel.pdf_direction[iclass](idir) = wsum_model.pdf_direction[iclass](idir) / sum_weight;
+		}
+	}
+
+	// Update sigma2_offset
+	// Factor 2 because of the 2-dimensionality of the xy-plane
+	if (!fix_sigma_offset)
+		mymodel.sigma2_offset = (wsum_model.sigma2_offset) / (2. * sum_weight);
+
+	// TODO: update estimates for sigma2_rot, sigma2_tilt and sigma2_psi!
+
+	// Also refrain from updating sigma_noise after the first iteration with first_iter_cc!
+	if (!fix_sigma_noise && !(iter == 1 && do_firstiter_cc))
+	{
+		for (int igroup = 0; igroup < mymodel.nr_groups; igroup++)
+		{
+			// Factor 2 because of the 2-dimensionality of the complex-plane
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(mymodel.sigma2_noise[igroup])
+			{
+				DIRECT_MULTIDIM_ELEM(mymodel.sigma2_noise[igroup], n) =
+						DIRECT_MULTIDIM_ELEM(wsum_model.sigma2_noise[igroup], n ) /
+							(2. * wsum_model.sumw_group[igroup] * DIRECT_MULTIDIM_ELEM(Npix_per_shell, n));
+			}
+		}
+	}
+
+	// After the first iteration the references are always CTF-corrected
+    if (do_ctf_correction)
+    	refs_are_ctf_corrected = true;
+
+	// Some statistics to output
+	mymodel.LL = 	wsum_model.LL;
+	if ((iter==1 && do_firstiter_cc) || do_always_cc)
+		mymodel.LL /= sum_weight; // this now stores the average ccf
+	mymodel.ave_Pmax = wsum_model.ave_Pmax / sum_weight;
+
+	// After the first, special iteration, apply low-pass filter of -ini_high again
+	if (iter == 1 && do_firstiter_cc)
+	{
+		initialLowPassFilterReferences();
+		if (ini_high > 0.)
+		{
+			// Adjust the tau2_class and data_vs_prior_class, because they were calculated on the unfiltered maps
+			// This is merely a matter of having correct output in the model.star file (these values are not used in the calculations)
+			double radius = mymodel.ori_size * mymodel.pixel_size / ini_high;
+			radius -= WIDTH_FMASK_EDGE / 2.;
+			double radius_p = radius + WIDTH_FMASK_EDGE;
+
+			for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+			{
+				for (int rr = 0; rr < XSIZE(mymodel.tau2_class[iclass]); rr++)
+				{
+					double r = (double)rr;
+					if (r < radius)
+						continue;
+					else if (r > radius_p)
+					{
+						DIRECT_A1D_ELEM(mymodel.tau2_class[iclass], rr) = 0.;
+						DIRECT_A1D_ELEM(mymodel.data_vs_prior_class[iclass], rr) = 0.;
+					}
+					else
+					{
+						double raisedcos = 0.5 - 0.5 * cos(PI * (radius_p - r) / WIDTH_FMASK_EDGE);
+						DIRECT_A1D_ELEM(mymodel.tau2_class[iclass], rr) *= raisedcos * raisedcos;
+						DIRECT_A1D_ELEM(mymodel.data_vs_prior_class[iclass], rr) *= raisedcos * raisedcos;
+					}
+				}
+			}
+		}
+
+		if (do_generate_seeds && mymodel.nr_classes > 1)
+		{
+			// In the first CC-iteration only a single reference was used
+			// Now copy this one reference to all K references, for seed generation in the second iteration
+			for (int iclass = 1; iclass < mymodel.nr_classes; iclass++)
+			{
+				mymodel.tau2_class[iclass] =  mymodel.tau2_class[0];
+				mymodel.data_vs_prior_class[iclass] = mymodel.data_vs_prior_class[0];
+				mymodel.pdf_class[iclass] = mymodel.pdf_class[0] / mymodel.nr_classes;
+				mymodel.pdf_direction[iclass] = mymodel.pdf_direction[0];
+				mymodel.Iref[iclass] = mymodel.Iref[0];
+			}
+			mymodel.pdf_class[0] /= mymodel.nr_classes;
+		}
+
+	}
+
+#ifdef DEBUG
+	std::cerr << "Leaving maximizationOtherParameters" << std::endl;
+#endif
+}
+
+
+void MlOptimiser::solventFlatten()
+{
+#ifdef DEBUG
+	std::cerr << "Entering MlOptimiser::solventFlatten" << std::endl;
+#endif
+	// First read solvent mask from disc, or pre-calculate it
+	Image<double> Isolvent, Isolvent2;
+    Isolvent().resize(mymodel.Iref[0]);
+	Isolvent().setXmippOrigin();
+	Isolvent().initZeros();
+	if (fn_mask.contains("None"))
+	{
+		double radius = particle_diameter / (2. * mymodel.pixel_size);
+		double radius_p = radius + width_mask_edge;
+		FOR_ALL_ELEMENTS_IN_ARRAY3D(Isolvent())
+		{
+			double r = sqrt((double)(k*k + i*i + j*j));
+			if (r < radius)
+				A3D_ELEM(Isolvent(), k, i, j) = 1.;
+			else if (r > radius_p)
+				A3D_ELEM(Isolvent(), k, i, j) = 0.;
+			else
+			{
+				A3D_ELEM(Isolvent(), k, i, j) = 0.5 - 0.5 * cos(PI * (radius_p - r) / width_mask_edge );
+			}
+		}
+	}
+	else
+	{
+		Isolvent.read(fn_mask);
+		Isolvent().setXmippOrigin();
+
+		if (Isolvent().computeMin() < 0. || Isolvent().computeMax() > 1.)
+			REPORT_ERROR("MlOptimiser::solventFlatten: ERROR solvent mask should contain values between 0 and 1 only...");
+	}
+
+	// Also read a second solvent mask if necessary
+	if (!fn_mask2.contains("None"))
+	{
+		Isolvent2.read(fn_mask2);
+		Isolvent2().setXmippOrigin();
+		if (!Isolvent2().sameShape(Isolvent()))
+			REPORT_ERROR("MlOptimiser::solventFlatten ERROR: second solvent mask is of incorrect size.");
+	}
+
+	for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+	{
+
+		// Then apply the expanded solvent mask to the map
+		mymodel.Iref[iclass] *= Isolvent();
+
+		// Apply a second solvent mask if necessary
+		// This may for example be useful to set the interior of icosahedral viruses to a constant density value that is higher than the solvent
+		// Invert the solvent mask, so that an input mask can be given where 1 is the masked area and 0 is protein....
+		if (!fn_mask2.contains("None"))
+			softMaskOutsideMap(mymodel.Iref[iclass], Isolvent2(), true);
+
+	} // end for iclass
+#ifdef DEBUG
+	std::cerr << "Leaving MlOptimiser::solventFlatten" << std::endl;
+#endif
+
+}
+
+void MlOptimiser::updateCurrentResolution()
+{
+//#define DEBUG
+#ifdef DEBUG
+	std::cerr << "Entering MlOptimiser::updateCurrentResolution" << std::endl;
+#endif
+
+
+    int maxres = 0;
+	if (do_map )
+	{
+		// Set current resolution
+		if (ini_high > 0. && (iter == 0 || (iter == 1 && do_firstiter_cc)))
+		{
+			maxres = ROUND(mymodel.ori_size * mymodel.pixel_size / ini_high);
+		}
+		else
+		{
+			// Calculate at which resolution shell the data_vs_prior drops below 1
+			int ires;
+			for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+			{
+				for (ires = 1; ires < mymodel.ori_size/2; ires++)
+				{
+					if (DIRECT_A1D_ELEM(mymodel.data_vs_prior_class[iclass], ires) < 1.)
+						break;
+				}
+				// Subtract one shell to be back on the safe side
+				ires--;
+				if (ires > maxres)
+					maxres = ires;
+			}
+
+			// Never allow smaller maxres than minres_map
+			maxres = XMIPP_MAX(maxres, minres_map);
+		}
+	}
+	else
+	{
+		// If we are not doing MAP-estimation, set maxres to Nyquist
+		maxres = mymodel.ori_size/2;
+	}
+    double newres = mymodel.getResolution(maxres);
+
+
+    // Check whether resolution improved, if not increase nr_iter_wo_resol_gain
+    //if (newres <= best_resol_thus_far)
+    if (newres <= mymodel.current_resolution+0.0001) // Add 0.0001 to avoid problems due to rounding error
+    	nr_iter_wo_resol_gain++;
+    else
+    	nr_iter_wo_resol_gain = 0;
+
+    // Store best resolution thus far (but no longer do anything with it anymore...)
+    if (newres > best_resol_thus_far)
+    	best_resol_thus_far = newres;
+
+    mymodel.current_resolution = newres;
+
+}
+
+void MlOptimiser::updateImageSizeAndResolutionPointers()
+{
+
+	// Increment the current_size
+    // If we are far from convergence (in the initial stages of refinement) take steps of 25% the image size
+    // Do this whenever the FSC at the current_size is larger than 0.2, but NOT when this is in combination with very low Pmax values,
+    // in the latter case, over-marginalisation may lead to spuriously high FSCs (2 smoothed maps may look very similar at high-res: all zero!)
+    //
+    int maxres = mymodel.getPixelFromResolution(mymodel.current_resolution);
+	if (mymodel.ave_Pmax > 0.1 && has_high_fsc_at_limit)
+    {
+		maxres += ROUND(0.25 * mymodel.ori_size / 2);
+    }
+	else
+	{
+		// If we are near our resolution limit, use incr_size (by default 10 shells)
+		maxres += incr_size;
+	}
+
+    // Go back from resolution shells (i.e. radius) to image size, which are BTW always even...
+	mymodel.current_size = maxres * 2;
+
+	// If realigning movies: go all the way because resolution increase may be substantial
+	if (do_use_all_data)
+		mymodel.current_size = mymodel.ori_size;
+
+	// current_size can never be larger than ori_size:
+	mymodel.current_size = XMIPP_MIN(mymodel.current_size, mymodel.ori_size);
+	// The current size is also used in wsum_model (in unpacking)
+	wsum_model.current_size = mymodel.current_size;
+
+	// Update coarse_size
+	if (strict_highres_exp > 0.)
+    {
+    	// Strictly limit the coarse size to the one corresponding to strict_highres_exp
+    	coarse_size = 2 * ROUND(mymodel.ori_size * mymodel.pixel_size / strict_highres_exp);
+    }
+    else if (adaptive_oversampling > 0.)
+	{
+    	// Dependency of coarse_size on the angular sampling used in the first pass
+    	double rotated_distance = (sampling.getAngularSampling() / 360.) * PI * particle_diameter;
+		double keepsafe_factor = (mymodel.ref_dim == 3) ? 1.2 : 1.5;
+		double coarse_resolution = rotated_distance / keepsafe_factor;
+		// Note coarse_size should be even-valued!
+		coarse_size = 2 * CEIL(mymodel.pixel_size * mymodel.ori_size / coarse_resolution);
+		// Coarse size can never be larger than max_coarse_size
+		coarse_size = XMIPP_MIN(max_coarse_size, coarse_size);
+	}
+	else
+		coarse_size = mymodel.current_size;
+    // Coarse_size can never become bigger than current_size
+    coarse_size = XMIPP_MIN(mymodel.current_size, coarse_size);
+
+	/// Also update the resolution pointers here
+
+	// Calculate number of pixels per resolution shell
+	Npix_per_shell.initZeros(mymodel.ori_size / 2 + 1);
+	MultidimArray<double> aux;
+	aux.resize(mymodel.ori_size, mymodel.ori_size / 2 + 1);
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(aux)
+	{
+		int ires = ROUND(sqrt((double)(kp*kp + ip*ip + jp*jp)));
+		// TODO: better check for volume_refine, but the same still seems to hold... Half of the yz plane (either ip<0 or kp<0 is redundant at jp==0)
+		// Exclude points beyond XSIZE(Npix_per_shell), and exclude half of the x=0 column that is stored twice in FFTW
+		if (ires < mymodel.ori_size / 2 + 1 && !(jp==0 && ip < 0))
+			Npix_per_shell(ires) += 1;
+	}
+
+	Mresol_fine.resize(mymodel.current_size, mymodel.current_size / 2 + 1);
+	Mresol_fine.initConstant(-1);
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Mresol_fine)
+	{
+		int ires = ROUND(sqrt((double)(kp*kp + ip*ip + jp*jp)));
+		// TODO: better check for volume_refine, but the same still seems to hold... Half of the yz plane (either ip<0 or kp<0 is redundant at jp==0)
+		// Exclude points beyond ires, and exclude and half (y<0) of the x=0 column that is stored twice in FFTW
+		if (ires < mymodel.current_size / 2 + 1  && !(jp==0 && ip < 0))
+		{
+			DIRECT_A3D_ELEM(Mresol_fine, k, i, j) = ires;
+		}
+	}
+
+	Mresol_coarse.resize(coarse_size, coarse_size/ 2 + 1);
+	Mresol_coarse.initConstant(-1);
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Mresol_coarse)
+	{
+		int ires = ROUND(sqrt((double)(kp*kp + ip*ip + jp*jp)));
+		// Exclude points beyond ires, and exclude and half (y<0) of the x=0 column that is stored twice in FFTW
+		// exclude lowest-resolution points
+		if (ires < coarse_size / 2 + 1 && !(jp==0 && ip < 0))
+		{
+			DIRECT_A3D_ELEM(Mresol_coarse, k, i, j) = ires;
+		}
+	}
+
+//#define DEBUG_MRESOL
+#ifdef DEBUG_MRESOL
+	Image<double> img;
+	img().resize(YSIZE(Mresol_fine),XSIZE(Mresol_fine));
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(img())
+	{
+		DIRECT_MULTIDIM_ELEM(img(), n) = (double)DIRECT_MULTIDIM_ELEM(Mresol_fine, n);
+	}
+	img.write("Mresol_fine.mrc");
+	img().resize(YSIZE(Mresol_coarse),XSIZE(Mresol_coarse));
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(img())
+	{
+		DIRECT_MULTIDIM_ELEM(img(), n) = (double)DIRECT_MULTIDIM_ELEM(Mresol_coarse, n);
+	}
+	img.write("Mresol_coarse.mrc");
+#endif
+
+
+#ifdef DEBUG
+	std::cerr << " current_size= " << mymodel.current_size << " coarse_size= " << coarse_size << " current_resolution= " << mymodel.current_resolution << std::endl;
+	std::cerr << "Leaving MlOptimiser::updateCurrentResolution" << std::endl;
+#endif
+
+}
+
+
+double MlOptimiser::calculatePdfOffset(Matrix1D<double> offset, Matrix1D<double> prior)
+{
+	if (mymodel.sigma2_offset < 0.0001)
+	{
+		return (offset.sum2() > 0.) ? 0. : 1.;
+	}
+	else
+	{
+		return exp ( (offset-prior).sum2() / (-2. * mymodel.sigma2_offset) ) / ( 2. * PI * mymodel.sigma2_offset );
+	}
+}
+
+void MlOptimiser::calculateRunningAveragesOfMovieFrames()
+{
+	std::vector<MultidimArray<Complex > > runavg_Fimgs;
+	std::vector<int> count_runavg;
+	MultidimArray<Complex > Fzero;
+	Fzero.resize(exp_Fimgs[0]);
+	Fzero.initZeros();
+
+	// initialise the sums at zero
+	for (int iimg = 0; iimg < exp_Fimgs.size(); iimg++)
+	{
+		runavg_Fimgs.push_back(Fzero);
+		count_runavg.push_back(0);
+	}
+
+	// running avgs NOT for series!
+	int iseries = 0;
+
+//#define DEBUG_RUNAVG
+#ifdef DEBUG_RUNAVG
+	FourierTransformer transformer;
+	MultidimArray< Complex > Fimg;
+	Image<double> It;
+	if (verb)
+	{
+		Fimg = exp_Fimgs[0];
+		It().resize(YSIZE(Fimg),YSIZE(Fimg));
+		transformer.inverseFourierTransform(Fimg, It());
+		CenterFFT(It(), false);
+		It.write("Fimg.spi");
+		std::cerr << "Written Fimg" << std::endl;
+	}
+#endif
+
+	// Calculate the running sums
+	for (int iimg = 0; iimg < exp_Fimgs.size(); iimg++)
+	{
+		// Who are we?
+		int my_ipart = exp_iimg_to_ipart[iimg];
+		long int my_ori_part_id = exp_ipart_to_ori_part_id[my_ipart];
+		long int my_part_id = exp_ipart_to_part_id[my_ipart];
+		int my_frame = exp_ipart_to_ori_part_nframe[my_ipart];
+
+#ifdef DEBUG_RUNAVG
+		if (verb)
+		{
+			long int my_img_id = mydata.getImageId(my_part_id, iseries);
+			FileName fntt;
+			mydata.MDimg.getValue(EMDL_IMAGE_NAME, fntt, my_img_id);
+			std::cerr << " my= " << fntt;
+		}
+#endif
+
+		long int my_first_runavg_frame = XMIPP_MAX(0, my_frame - movie_frame_running_avg_side);
+		long int my_last_runavg_frame = XMIPP_MIN(mydata.ori_particles[my_ori_part_id].particles_id.size() - 1, my_frame + movie_frame_running_avg_side);
+
+		// Run over all images again and see which ones to sum
+		for (int iimg2 = 0; iimg2 < exp_Fimgs.size(); iimg2++)
+		{
+			int other_ipart = exp_iimg_to_ipart[iimg2];
+			long int other_ori_part_id = exp_ipart_to_ori_part_id[other_ipart];
+			long int other_part_id = exp_ipart_to_part_id[other_ipart];
+			int other_frame = exp_ipart_to_ori_part_nframe[other_ipart];
+
+			if (my_ori_part_id == other_ori_part_id && other_frame >= my_first_runavg_frame && other_frame <= my_last_runavg_frame)
+			{
+#ifdef DEBUG_RUNAVG
+				if (verb)
+				{
+					long int other_img_id = mydata.getImageId(other_part_id, iseries);
+					FileName fnt, fnm, fnp;
+					mydata.MDimg.getValue(EMDL_IMAGE_NAME, fnt, other_img_id);
+					mydata.MDimg.getValue(EMDL_PARTICLE_ORI_NAME, fnp, other_img_id);
+					mydata.MDimg.getValue(EMDL_MICROGRAPH_NAME, fnm, other_img_id);
+					std::cerr << " = " << fnt<<" "<<fnm<<" "<<fnp;
+				}
+#endif
+
+				// Add to sum
+				runavg_Fimgs[iimg] += exp_Fimgs[iimg2];
+				count_runavg[iimg] += 1;
+			}
+		}
+
+#ifdef DEBUG_RUNAVG
+		if (verb)
+			std::cerr << std::endl;
+#endif
+	}
+
+	// Calculate averages from sums and set back in exp_ vectors
+	for (int iimg = 0; iimg < exp_Fimgs.size(); iimg++)
+	{
+		double sum = (double)count_runavg[iimg];
+		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(exp_Fimgs[iimg])
+		{
+			DIRECT_MULTIDIM_ELEM(exp_Fimgs[iimg], n) = DIRECT_MULTIDIM_ELEM(runavg_Fimgs[iimg], n) / sum;
+		}
+		// Also lower the power of the images for the sigma2_noise and diff2 calculations beyond current_size....
+		// sigma2_(a+b) = sigma2_(a) + sigma2_(b)
+		// The actual values are lost, just hope the images obey statistics...
+		exp_power_imgs[iimg] /= sum;
+		exp_highres_Xi2_imgs[iimg] /= sum;
+	}
+#ifdef DEBUG_RUNAVG
+	if (verb)
+	{
+		Fimg = exp_Fimgs[0];
+		It().resize(YSIZE(Fimg),YSIZE(Fimg));
+		transformer.inverseFourierTransform(Fimg, It());
+		CenterFFT(It(), false);
+		It.write("Frunavg.spi");
+		std::cerr << "Written Frunavg.spi, sleeping 2 seconds..." << std::endl;
+		sleep(2);
+
+	}
+#endif
+
+}
+
+void MlOptimiser::doThreadGetFourierTransformsAndCtfs(int thread_id)
+{
+	// Only first thread initialises
+	if (thread_id == 0)
+	{
+		exp_starting_image_no.clear();
+		exp_power_imgs.clear();
+		exp_highres_Xi2_imgs.clear();
+		exp_Fimgs.clear();
+		exp_Fimgs_nomask.clear();
+		exp_Fctfs.clear();
+		exp_old_offset.clear();
+		exp_prior.clear();
+		exp_local_oldcc.clear();
+		exp_ipart_to_part_id.clear();
+		exp_ipart_to_ori_part_id.clear();
+		exp_ipart_to_ori_part_nframe.clear();
+		exp_iimg_to_ipart.clear();
+
+		// Resize to the right size instead of using pushbacks
+		exp_starting_image_no.resize(exp_nr_particles);
+
+		// First check how many images there are in the series for each particle...
+		// And calculate exp_nr_images
+		exp_nr_images = 0;
+		for (long int ori_part_id = exp_my_first_ori_particle, my_image_no = 0, ipart = 0; ori_part_id <= exp_my_last_ori_particle; ori_part_id++)
+	    {
+
+#ifdef DEBUG_CHECKSIZES
+			if (ori_part_id >= mydata.ori_particles.size())
+			{
+				std::cerr<< "ori_part_id= "<<ori_part_id<<" mydata.ori_particles.size()= "<< mydata.ori_particles.size() <<std::endl;
+				REPORT_ERROR("ori_part_id >= mydata.ori_particles.size()");
+			}
+#endif
+			for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++, ipart++)
+			{
+				long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+				int iipart = exp_ipart_to_part_id.size();
+				exp_starting_image_no.at(iipart) = exp_nr_images;
+				exp_nr_images += mydata.getNrImagesInSeries(part_id);
+				exp_ipart_to_part_id.push_back(part_id);
+				exp_ipart_to_ori_part_id.push_back(ori_part_id);
+				exp_ipart_to_ori_part_nframe.push_back(i);
+				for (int i = 0; i < mydata.getNrImagesInSeries(part_id); i++)
+					exp_iimg_to_ipart.push_back(iipart);
+			}
+	    }
+		// Then also resize vectors for all images
+		exp_power_imgs.resize(exp_nr_images);
+		exp_highres_Xi2_imgs.resize(exp_nr_images);
+		exp_Fimgs.resize(exp_nr_images);
+		exp_Fimgs_nomask.resize(exp_nr_images);
+		exp_Fctfs.resize(exp_nr_images);
+		exp_old_offset.resize(exp_nr_images);
+		exp_prior.resize(exp_nr_images);
+		exp_local_oldcc.resize(exp_nr_images);
+
+	}
+	global_barrier->wait();
+
+	FourierTransformer transformer;
+	size_t first_ipart = 0, last_ipart = 0;
+	while (exp_ipart_ThreadTaskDistributor->getTasks(first_ipart, last_ipart))
+	{
+
+		for (long int ipart = first_ipart; ipart <= last_ipart; ipart++)
+		{
+			// the exp_ipart_ThreadTaskDistributor was set with nr_pool,
+			// but some, e.g. the last, batch of pooled particles may be smaller
+			if (ipart >= exp_nr_particles)
+				break;
+
+#ifdef DEBUG_CHECKSIZES
+			if (ipart >= exp_ipart_to_part_id.size())
+			{
+				std::cerr<< "ipart= "<<ipart<<" exp_ipart_to_part_id.size()= "<< exp_ipart_to_part_id.size() <<std::endl;
+				REPORT_ERROR("ipart >= exp_ipart_to_part_id.size()");
+			}
+#endif
+			long int part_id = exp_ipart_to_part_id[ipart];
+
+			// Prevent movies and series at the same time...
+			if (mydata.getNrImagesInSeries(part_id) > 1 && do_realign_movies)
+				REPORT_ERROR("Not ready yet for dealing with image series at the same time as realigning movie frames....");
+
+			for (int iseries = 0; iseries < mydata.getNrImagesInSeries(part_id); iseries++)
+			{
+
+				FileName fn_img;
+				Image<double> img, rec_img;
+				MultidimArray<Complex > Fimg, Faux;
+				MultidimArray<double> Fctf;
+				int my_image_no = exp_starting_image_no.at(ipart) + iseries;
+				// Which group do I belong?
+				int group_id = mydata.getGroupId(part_id, iseries);
+
+				// Get the norm_correction
+				double normcorr = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM);
+
+				// Get the optimal origin offsets from the previous iteration
+				Matrix1D<double> my_old_offset(2), my_prior(2);
+				XX(my_old_offset) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_XOFF);
+				YY(my_old_offset) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_YOFF);
+				XX(my_prior)      = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_XOFF_PRIOR);
+				YY(my_prior)      = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_YOFF_PRIOR);
+				// Uninitialised priors were set to 999.
+				if (XX(my_prior) > 998.99 && XX(my_prior) < 999.01)
+					XX(my_prior) = 0.;
+				if (YY(my_prior) > 998.99 && YY(my_prior) < 999.01)
+					YY(my_prior) = 0.;
+
+				// Get the old cross-correlations
+				exp_local_oldcc.at(my_image_no) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_DLL);
+
+				// If we do local angular searches, get the previously assigned angles to center the prior
+				// Only do this for the first image in the series, as this prior work per-particle, not per-image
+				// All images in the series use the same rotational sampling, brought back to "exp_R_mic=identity"
+				if (do_skip_align || do_skip_rotate)
+				{
+					// No need to block the threads global_mutex, as nr_pool will be set to 1 anyway for do_skip_align!
+					if (do_skip_align)
+					{
+						// Rounded translations will be applied to the image upon reading,
+						// set the unique translation in the sampling object to the fractional difference
+						Matrix1D<double> rounded_offset = my_old_offset;
+						rounded_offset.selfROUND();
+						rounded_offset = my_old_offset - rounded_offset;
+						sampling.setOneTranslation(rounded_offset);
+					}
+
+					// Also set the rotations
+					double old_rot, old_tilt, old_psi;
+					old_rot = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_ROT);
+					old_tilt = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_TILT);
+					old_psi = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PSI);
+					sampling.setOneOrientation(old_rot, old_tilt, old_psi);
+
+				}
+				else if (mymodel.orientational_prior_mode != NOPRIOR && iseries == 0)
+				{
+					// First try if there are some fixed prior angles
+					double prior_rot = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_ROT_PRIOR);
+					double prior_tilt = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_TILT_PRIOR);
+					double prior_psi = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PSI_PRIOR);
+
+					// If there were no defined priors (i.e. their values were 999.), then use the "normal" angles
+					if (prior_rot > 998.99 && prior_rot < 999.01)
+						prior_rot = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_ROT);
+					if (prior_tilt > 998.99 && prior_tilt < 999.01)
+						prior_tilt = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_TILT);
+					if (prior_psi > 998.99 && prior_psi < 999.01)
+						prior_psi = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PSI);
+
+					// For tilted series: convert the angles back onto the untilted ones...
+					// Calculate the angles back from the Euler matrix because for tilt series exp_R_mic may have changed them...
+					Matrix2D<double> A, R_mic(3,3);
+					R_mic(0,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_0);
+					R_mic(0,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_1);
+					R_mic(0,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_2);
+					R_mic(1,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_0);
+					R_mic(1,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_1);
+					R_mic(1,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_2);
+					R_mic(2,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_0);
+					R_mic(2,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_1);
+					R_mic(2,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_2);
+					if (!R_mic.isIdentity())
+					{
+						Euler_angles2matrix(prior_rot, prior_tilt, prior_psi, A);
+						A = R_mic.inv() * A;
+						Euler_matrix2angles(A, prior_rot, prior_tilt, prior_psi);
+					}
+
+					global_mutex.lock();
+
+					// Select only those orientations that have non-zero prior probability
+					sampling.selectOrientationsWithNonZeroPriorProbability(prior_rot, prior_tilt, prior_psi,
+							sqrt(mymodel.sigma2_rot), sqrt(mymodel.sigma2_tilt), sqrt(mymodel.sigma2_psi));
+
+					long int nr_orients = sampling.NrDirections() * sampling.NrPsiSamplings();
+					if (nr_orients == 0)
+					{
+						std::cerr << " sampling.NrDirections()= " << sampling.NrDirections() << " sampling.NrPsiSamplings()= " << sampling.NrPsiSamplings() << std::endl;
+						REPORT_ERROR("Zero orientations fall within the local angular search. Increase the sigma-value(s) on the orientations!");
+					}
+					int threadBlockSize = (nr_orients > 100) ? 10 : 1;
+
+					exp_iorient_ThreadTaskDistributor->resize(nr_orients, threadBlockSize);
+
+					global_mutex.unlock();
+
+				}
+
+				// Unpack the image from the imagedata
+				img().resize(mymodel.ori_size, mymodel.ori_size);
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(img())
+				{
+					DIRECT_A2D_ELEM(img(), i, j) = DIRECT_A3D_ELEM(exp_imagedata, my_image_no, i, j);
+				}
+				img().setXmippOrigin();
+				if (has_converged && do_use_reconstruct_images)
+				{
+					rec_img().resize(mymodel.ori_size, mymodel.ori_size);
+					FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(rec_img())
+					{
+						DIRECT_A2D_ELEM(rec_img(), i, j) = DIRECT_A3D_ELEM(exp_imagedata, exp_nr_images + my_image_no, i, j);
+					}
+					rec_img().setXmippOrigin();
+				}
+//#define DEBUG_SOFTMASK
+#ifdef DEBUG_SOFTMASK
+					Image<double> tt;
+					tt()=img();
+					tt.write("Fimg_unmasked.spi");
+					std::cerr << "written Fimg_unmasked.spi; press any key to continue..." << std::endl;
+					char c;
+					std::cin >> c;
+#endif
+				// Apply the norm_correction term
+				if (do_norm_correction)
+				{
+//#define DEBUG_NORM
+#ifdef DEBUG_NORM
+					if (normcorr < 0.001 || normcorr > 1000. || mymodel.avg_norm_correction < 0.001 || mymodel.avg_norm_correction > 1000.)
+					{
+						std::cerr << " ** normcorr= " << normcorr << std::endl;
+						std::cerr << " ** mymodel.avg_norm_correction= " << mymodel.avg_norm_correction << std::endl;
+						std::cerr << " ** fn_img= " << fn_img << " part_id= " << part_id << std::endl;
+						std::cerr << " ** iseries= " << iseries << " ipart= " << ipart << " part_id= " << part_id << std::endl;
+						int group_id = mydata.getGroupId(part_id, iseries);
+						std::cerr << " ml_model.sigma2_noise[group_id]= " << mymodel.sigma2_noise[group_id] << " group_id= " << group_id <<std::endl;
+						std::cerr << " part_id= " << part_id << " iseries= " << iseries << std::endl;
+						std::cerr << " img_id= " << img_id << std::endl;
+						REPORT_ERROR("Very small or very big (avg) normcorr!");
+					}
+#endif
+					img() *= mymodel.avg_norm_correction / normcorr;
+				}
+
+				// Apply (rounded) old offsets first
+				my_old_offset.selfROUND();
+				selfTranslate(img(), my_old_offset, DONT_WRAP);
+				if (has_converged && do_use_reconstruct_images)
+					selfTranslate(rec_img(), my_old_offset, DONT_WRAP);
+
+				exp_old_offset.at(my_image_no) = my_old_offset;
+				// Also store priors on translations
+				exp_prior.at(my_image_no) = my_prior;
+
+				// Always store FT of image without mask (to be used for the reconstruction)
+				MultidimArray<double> img_aux;
+				img_aux = (has_converged && do_use_reconstruct_images) ? rec_img() : img();
+				CenterFFT(img_aux, true);
+				transformer.FourierTransform(img_aux, Faux);
+				windowFourierTransform(Faux, Fimg, mymodel.current_size);
+
+				// Here apply the beamtilt correction if necessary
+				// This will only be used for reconstruction, not for alignment
+				// But beamtilt only affects very high-resolution components anyway...
+				//
+				double beamtilt_x = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_BEAMTILT_X);
+				double beamtilt_y = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_BEAMTILT_Y);
+				double Cs = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_CS);
+				double V = 1000. * DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_VOLTAGE);
+				double lambda = 12.2643247 / sqrt(V * (1. + V * 0.978466e-6));
+				if (ABS(beamtilt_x) > 0. || ABS(beamtilt_y) > 0.)
+					selfApplyBeamTilt(Fimg, beamtilt_x, beamtilt_y, lambda, Cs, mymodel.pixel_size, mymodel.ori_size);
+
+				exp_Fimgs_nomask.at(my_image_no) = Fimg;
+
+				long int ori_part_id = exp_ipart_to_ori_part_id[ipart];
+
+				MultidimArray<double> Mnoise;
+				if (!do_zero_mask)
+				{
+					// Make a noisy background image with the same spectrum as the sigma2_noise
+
+					// Different MPI-distributed subsets may otherwise have different instances of the random noise below,
+					// because work is on an on-demand basis and therefore variable with the timing of distinct nodes...
+					// Have the seed based on the ipart, so that each particle has a different instant of the noise
+					// Do this all inside a mutex for the threads, because they all use the same static variables inside ran1...
+					// (So the mutex only goal is to make things exactly reproducible with the same random_seed.)
+					global_mutex.lock();
+
+					//init_random_generator(random_seed + ori_part_id);
+					if (do_realign_movies)
+						init_random_generator(random_seed + part_id);
+					else
+						init_random_generator(random_seed + ori_part_id);
+
+					// If we're doing running averages, then the sigma2_noise was already adjusted for the running averages.
+					// Undo this adjustment here in order to get the right noise in the individual frames
+					MultidimArray<double> power_noise = sigma2_fudge * mymodel.sigma2_noise[group_id];
+					if (do_realign_movies)
+						power_noise *= (2. * movie_frame_running_avg_side + 1.);
+
+					// Create noisy image for outside the mask
+					MultidimArray<Complex > Fnoise;
+					Mnoise.resize(img());
+					transformer.setReal(Mnoise);
+					transformer.getFourierAlias(Fnoise);
+					// Fill Fnoise with random numbers, use power spectrum of the noise for its variance
+					FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Fnoise)
+					{
+						int ires = ROUND( sqrt( (double)(kp * kp + ip * ip + jp * jp) ) );
+						if (ires >= 0 && ires < XSIZE(Fnoise))
+						{
+							double sigma = sqrt(DIRECT_A1D_ELEM(power_noise, ires));
+							DIRECT_A3D_ELEM(Fnoise, k, i, j).real = rnd_gaus(0., sigma);
+							DIRECT_A3D_ELEM(Fnoise, k, i, j).imag = rnd_gaus(0., sigma);
+						}
+						else
+						{
+							DIRECT_A3D_ELEM(Fnoise, k, i, j) = 0.;
+						}
+					}
+					// Back to real space Mnoise
+					transformer.inverseFourierTransform();
+					Mnoise.setXmippOrigin();
+
+					// unlock the mutex now that all calss to random functions have finished
+					global_mutex.unlock();
+
+					softMaskOutsideMap(img(), particle_diameter / (2. * mymodel.pixel_size), (double)width_mask_edge, &Mnoise);
+
+				}
+				else
+				{
+					softMaskOutsideMap(img(), particle_diameter / (2. * mymodel.pixel_size), (double)width_mask_edge);
+				}
+#ifdef DEBUG_SOFTMASK
+					tt()=img();
+					tt.write("Fimg_masked.spi");
+					std::cerr << "written Fimg_masked.spi; press any key to continue..." << std::endl;
+					exit(1);
+					std::cin >> c;
+#endif
+
+				// Inside Projector and Backprojector the origin of the Fourier Transform is centered!
+				CenterFFT(img(), true);
+
+				// Store the Fourier Transform of the image Fimg
+				transformer.FourierTransform(img(), Faux);
+
+				// Store the power_class spectrum of the whole image (to fill sigma2_noise between current_size and ori_size
+				if (mymodel.current_size < mymodel.ori_size)
+				{
+					MultidimArray<double> spectrum;
+					spectrum.initZeros(mymodel.ori_size/2 + 1);
+					double highres_Xi2 = 0.;
+					FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Faux)
+					{
+						int ires = ROUND( sqrt( (double)(kp*kp + ip*ip + jp*jp) ) );
+						// Skip Hermitian pairs in the x==0 column
+
+						if (ires > 0 && ires < mymodel.ori_size/2 + 1 && !(jp==0 && ip < 0) )
+						{
+							double normFaux = norm(DIRECT_A3D_ELEM(Faux, k, i, j));
+							DIRECT_A1D_ELEM(spectrum, ires) += normFaux;
+							// Store sumXi2 from current_size until ori_size
+							if (ires >= mymodel.current_size/2 + 1)
+								highres_Xi2 += normFaux;
+						}
+					}
+
+					// Let's use .at() here instead of [] to check whether we go outside the vectors bounds
+					exp_power_imgs.at(my_image_no) = spectrum;
+					exp_highres_Xi2_imgs.at(my_image_no) = highres_Xi2;
+				}
+				else
+				{
+					exp_highres_Xi2_imgs.at(my_image_no) = 0.;
+				}
+
+				// We never need any resolutions higher than current_size
+				// So resize the Fourier transforms
+				windowFourierTransform(Faux, Fimg, mymodel.current_size);
+
+				// Also store its CTF
+				Fctf.resize(Fimg);
+
+				// Now calculate the actual CTF
+				if (do_ctf_correction)
+				{
+					CTF ctf;
+					ctf.setValues(DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_DEFOCUS_U),
+							DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_DEFOCUS_V),
+							DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_DEFOCUS_ANGLE),
+							DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_VOLTAGE),
+							DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_CS),
+							DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_Q0),
+							DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_BFAC));
+
+					ctf.getFftwImage(Fctf, mymodel.ori_size, mymodel.ori_size, mymodel.pixel_size,
+							ctf_phase_flipped, only_flip_phases, intact_ctf_first_peak, true);
+//#define DEBUG_CTF_FFTW_IMAGE
+#ifdef DEBUG_CTF_FFTW_IMAGE
+					Image<double> tt;
+					tt()=Fctf;
+					tt.write("relion_ctf.spi");
+					std::cerr << "Written relion_ctf.spi, now exiting..." << std::endl;
+					exit(1);
+#endif
+//#define DEBUG_GETCTF
+#ifdef DEBUG_GETCTF
+					std::cerr << " intact_ctf_first_peak= " << intact_ctf_first_peak << std::endl;
+					ctf.write(std::cerr);
+					Image<double> tmp;
+					tmp()=Fctf;
+					tmp.write("Fctf.spi");
+					tmp().resize(mymodel.ori_size, mymodel.ori_size);
+					ctf.getCenteredImage(tmp(), mymodel.pixel_size, ctf_phase_flipped, only_flip_phases, intact_ctf_first_peak, true);
+					tmp.write("Fctf_cen.spi");
+					std::cerr << "Written Fctf.spi, Fctf_cen.spi. Press any key to continue..." << std::endl;
+					char c;
+					std::cin >> c;
+#endif
+				}
+				else
+				{
+					Fctf.initConstant(1.);
+				}
+
+				// Store Fimg and Fctf
+				exp_Fimgs.at(my_image_no) = Fimg;
+				exp_Fctfs.at(my_image_no) = Fctf;
+
+			} // end loop iseries
+		}// end loop ipart
+	} // end while threadTaskDistributor
+
+	// All threads clear out their transformer object when they are finished
+	// This is to prevent a call from the first thread to fftw_cleanup, while there are still active plans in the transformer objects....
+	// The multi-threaded code with FFTW objects is really a bit of a pain...
+	if (thread_id != 0)
+	{
+		transformer.clear();
+	}
+
+	// Wait until all threads have finished
+	global_barrier->wait();
+
+	// Only the first thread cleans up the fftw-junk in the transformer object
+	if (thread_id == 0)
+	{
+		transformer.cleanup();
+	}
+
+}
+
+void MlOptimiser::doThreadPrecalculateShiftedImagesCtfsAndInvSigma2s(int thread_id)
+{
+#ifdef TIMING
+	timer.tic(TIMING_DIFF_SHIFT);
+#endif
+
+
+	size_t first_ipart = 0, last_ipart = 0;
+	while (exp_ipart_ThreadTaskDistributor->getTasks(first_ipart, last_ipart))
+	{
+		for (long int ipart = first_ipart; ipart <= last_ipart; ipart++)
+		{
+			// the exp_ipart_ThreadTaskDistributor was set with nr_pool,
+			// but some, e.g. the last, batch of pooled particles may be smaller
+			if (ipart >= exp_nr_particles)
+				break;
+
+			long int part_id = exp_ipart_to_part_id[ipart];
+#ifdef DEBUG_CHECKSIZES
+			if (ipart >= exp_starting_image_no.size())
+			{
+				std::cerr<< "ipart= "<<ipart<<" exp_starting_image_no.size()= "<< exp_starting_image_no.size() <<std::endl;
+				REPORT_ERROR("ipart >= exp_starting_image_no.size()");
+			}
+#endif
+			int my_image_no = exp_starting_image_no[ipart] + exp_iseries;
+
+#ifdef DEBUG_CHECKSIZES
+			if (my_image_no >= exp_Fimgs.size())
+			{
+				std::cerr<< "my_image_no= "<<my_image_no<<" exp_Fimgs.size()= "<< exp_Fimgs.size() <<std::endl;
+				std::cerr << " exp_nr_trans= " << exp_nr_trans << " exp_nr_oversampled_trans= " << exp_nr_oversampled_trans << " exp_current_oversampling= " << exp_current_oversampling << std::endl;
+				REPORT_ERROR("my_image_no >= exp_Fimgs.size()");
+			}
+#endif
+			// Downsize Fimg and Fctf (again) to exp_current_image_size, also initialise Fref and Fimg_shift to the right size
+			MultidimArray<Complex > Fimg, Fshifted, Fimg_nomask, Fshifted_nomask;
+			windowFourierTransform(exp_Fimgs[my_image_no], Fimg, exp_current_image_size);
+			windowFourierTransform(exp_Fimgs_nomask[my_image_no], Fimg_nomask, exp_current_image_size);
+
+
+			// Also precalculate the sqrt of the sum of all Xi2
+			// (Could exp_current_image_size ever be different from mymodel.current_size? Probhably therefore do it here rather than in getFourierTransforms
+			if ((iter == 1 && do_firstiter_cc) || do_always_cc)
+			{
+				double sumxi2 = 0.;
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fimg)
+				{
+					sumxi2 += norm(DIRECT_MULTIDIM_ELEM(Fimg, n));
+				}
+				// Normalised cross-correlation coefficient: divide by power of reference (power of image is a constant)
+				exp_local_sqrtXi2[my_image_no] = sqrt(sumxi2);
+			}
+
+			// Store all translated variants of Fimg
+			int my_trans_image = my_image_no * exp_nr_trans * exp_nr_oversampled_trans;
+			for (long int itrans = 0; itrans < exp_nr_trans; itrans++)
+			{
+				// First get the non-oversampled translations as defined by the sampling object
+				std::vector<Matrix1D <double> > oversampled_translations;
+				sampling.getTranslations(itrans, exp_current_oversampling, oversampled_translations);
+
+#ifdef DEBUG_CHECKSIZES
+				if (oversampled_translations.size() != exp_nr_oversampled_trans)
+				{
+					std::cerr<< "oversampled_translations.size()= "<<oversampled_translations.size()<<" exp_nr_oversampled_trans= "<< exp_nr_oversampled_trans <<std::endl;
+					REPORT_ERROR("oversampled_translations.size() != exp_nr_oversampled_trans");
+				}
+#endif
+
+				// Then loop over all its oversampled relatives
+				for (long int iover_trans = 0; iover_trans < exp_nr_oversampled_trans; iover_trans++)
+				{
+//#define DEBUG_SHIFTS
+#ifdef DEBUG_SHIFTS
+					Image<double> It;
+					std::cerr << " iover_trans= " << iover_trans << " XX(oversampled_translations[iover_trans] )= " << XX(oversampled_translations[iover_trans] ) << " YY(oversampled_translations[iover_trans] )= " << YY(oversampled_translations[iover_trans] ) << std::endl;
+#endif
+					// Shift through phase-shifts in the Fourier transform
+					// Note that the shift search range is centered around (exp_old_xoff, exp_old_yoff)
+					shiftImageInFourierTransform(Fimg, Fshifted, tab_sin, tab_cos, (double)mymodel.ori_size, oversampled_translations[iover_trans]);
+					shiftImageInFourierTransform(Fimg_nomask, Fshifted_nomask, tab_sin, tab_cos, (double)mymodel.ori_size, oversampled_translations[iover_trans]);
+
+#ifdef DEBUG_SHIFTS
+					FourierTransformer transformer;
+					It().resize(YSIZE(Fimg), YSIZE(Fimg));
+					transformer.inverseFourierTransform(Fimg, It());
+					CenterFFT(It(), false);
+					It.write("Fimg.spi");
+					transformer.inverseFourierTransform(Fshifted, It());
+					CenterFFT(It(), false);
+					It.write("Fshifted.spi");
+					std::cerr << "Written Fimg and Fshifted, press any key to continue..." << std::endl;
+					char c;
+					std::cin >> c;
+#endif
+					// Store the shifted image
+					exp_local_Fimgs_shifted[my_trans_image] = Fshifted;
+					exp_local_Fimgs_shifted_nomask[my_trans_image] = Fshifted_nomask;
+					my_trans_image++;
+				}
+			}
+
+
+			// Also store downsized Fctfs
+			// In the second pass of the adaptive approach this will have no effect,
+			// since then exp_current_image_size will be the same as the size of exp_Fctfs
+#ifdef DEBUG_CHECKSIZES
+			if (my_image_no >= exp_Fctfs.size())
+			{
+				std::cerr<< "my_image_no= "<<my_image_no<<" exp_Fctfs.size()= "<< exp_Fctfs.size() <<std::endl;
+				REPORT_ERROR("my_image_no >= exp_Fctfs.size()");
+			}
+#endif
+
+			MultidimArray<double> Fctf;
+			windowFourierTransform(exp_Fctfs[my_image_no], Fctf, exp_current_image_size);
+			exp_local_Fctfs[my_image_no] = Fctf;
+
+			// Get micrograph id (for choosing the right sigma2_noise)
+			int group_id = mydata.getGroupId(part_id, exp_iseries);
+
+			MultidimArray<double> Minvsigma2;
+			Minvsigma2.initZeros(YSIZE(Fimg), XSIZE(Fimg));
+			MultidimArray<int> * myMresol = (YSIZE(Fimg) == coarse_size) ? &Mresol_coarse : &Mresol_fine;
+
+#ifdef DEBUG_CHECKSIZES
+			if (!Minvsigma2.sameShape(*myMresol))
+			{
+				std::cerr<< "!Minvsigma2.sameShape(*myMresol)= "<<!Minvsigma2.sameShape(*myMresol) <<std::endl;
+				REPORT_ERROR("!Minvsigma2.sameShape(*myMresol)");
+			}
+#endif
+			// With group_id and relevant size of Fimg, calculate inverse of sigma^2 for relevant parts of Mresol
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(*myMresol)
+			{
+				int ires = DIRECT_MULTIDIM_ELEM(*myMresol, n);
+				// Exclude origin (ires==0) from the Probability-calculation
+				// This way we are invariant to additive factors
+				if (ires > 0)
+				{
+					DIRECT_MULTIDIM_ELEM(Minvsigma2, n) = 1. / (sigma2_fudge * DIRECT_A1D_ELEM(mymodel.sigma2_noise[group_id], ires));
+				}
+			}
+
+#ifdef DEBUG_CHECKSIZES
+			if (my_image_no >= exp_local_Minvsigma2s.size())
+			{
+				std::cerr<< "my_image_no= "<<my_image_no<<" exp_local_Minvsigma2s.size()= "<< exp_local_Minvsigma2s.size() <<std::endl;
+				REPORT_ERROR("my_image_no >= exp_local_Minvsigma2s.size()");
+			}
+#endif
+			exp_local_Minvsigma2s[my_image_no] = Minvsigma2;
+		}
+	}
+
+	// Wait until all threads are finsished
+	global_barrier->wait();
+
+#ifdef TIMING
+	timer.toc(TIMING_DIFF_SHIFT);
+#endif
+
+
+}
+
+bool MlOptimiser::isSignificantAnyParticleAnyTranslation(long int iorient)
+{
+
+	for (long int ipart = 0; ipart < YSIZE(exp_Mcoarse_significant); ipart++)
+	{
+		long int ihidden = iorient * exp_nr_trans;
+		for (long int itrans = 0; itrans < exp_nr_trans; itrans++, ihidden++)
+		{
+#ifdef DEBUG_CHECKSIZES
+			if (ihidden >= XSIZE(exp_Mcoarse_significant))
+			{
+				std::cerr << " ihidden= " << ihidden << " XSIZE(exp_Mcoarse_significant)= " << XSIZE(exp_Mcoarse_significant) << std::endl;
+				std::cerr << " iorient= " << iorient << " itrans= " << itrans << " exp_nr_trans= " << exp_nr_trans << std::endl;
+				REPORT_ERROR("ihidden > XSIZE: ");
+			}
+#endif
+			if (DIRECT_A2D_ELEM(exp_Mcoarse_significant, ipart, ihidden))
+				return true;
+		}
+	}
+	return false;
+
+}
+
+void MlOptimiser::doThreadGetSquaredDifferencesAllOrientations(int thread_id)
+{
+#ifdef DEBUG_THREAD
+    std::cerr << "entering doThreadGetAllSquaredDifferences" << std::endl;
+#endif
+
+    // Local variables
+	std::vector<double> thisthread_min_diff2;
+    std::vector< Matrix1D<double> > oversampled_orientations, oversampled_translations;
+	MultidimArray<Complex > Fimg, Fref, Frefctf, Fimg_shift;
+	MultidimArray<double> Fctf, Minvsigma2;
+    Matrix2D<double> A;
+
+    // Initialise local mindiff2 for thread-safety
+    thisthread_min_diff2.clear();
+    thisthread_min_diff2.resize(exp_nr_particles, 99.e99);
+    Fref.resize(exp_local_Fimgs_shifted[0]);
+	Frefctf.resize(exp_local_Fimgs_shifted[0]);
+
+    // THESE TWO FOR LOOPS WILL BE PARALLELISED USING THREADS...
+	// exp_iclass loop does not always go from 0 to nr_classes!
+	long int iorientclass_offset = exp_iclass * exp_nr_rot;
+
+    size_t first_iorient = 0, last_iorient = 0;
+	while (exp_iorient_ThreadTaskDistributor->getTasks(first_iorient, last_iorient))
+	{
+		for (long int iorient = first_iorient; iorient <= last_iorient; iorient++)
+		{
+
+			long int iorientclass = iorientclass_offset + iorient;
+			long int idir = iorient / exp_nr_psi;
+			long int ipsi = iorient % exp_nr_psi;
+			// Get prior for this direction and skip calculation if prior==0
+			double pdf_orientation;
+			if (mymodel.orientational_prior_mode == NOPRIOR)
+			{
+#ifdef DEBUG_CHECKSIZES
+				if (idir >= XSIZE(mymodel.pdf_direction[exp_iclass]))
+				{
+					std::cerr<< "idir= "<<idir<<" XSIZE(mymodel.pdf_direction[exp_iclass])= "<< XSIZE(mymodel.pdf_direction[exp_iclass]) <<std::endl;
+					REPORT_ERROR("idir >= mymodel.pdf_direction[exp_iclass].size()");
+				}
+#endif
+				pdf_orientation = DIRECT_MULTIDIM_ELEM(mymodel.pdf_direction[exp_iclass], idir);
+			}
+			else
+			{
+				pdf_orientation = sampling.getPriorProbability(idir, ipsi);
+			}
+
+			// In the first pass, always proceed
+			// In the second pass, check whether one of the translations for this orientation of any of the particles had a significant weight in the first pass
+			// if so, proceed with projecting the reference in that direction
+			bool do_proceed = (exp_ipass==0) ? true : isSignificantAnyParticleAnyTranslation(iorientclass);
+
+			if (do_proceed && pdf_orientation > 0.)
+			{
+				// Now get the oversampled (rot, tilt, psi) triplets
+				// This will be only the original (rot,tilt,psi) triplet in the first pass (exp_current_oversampling==0)
+				sampling.getOrientations(idir, ipsi, exp_current_oversampling, oversampled_orientations);
+
+#ifdef DEBUG_CHECKSIZES
+				if (exp_nr_oversampled_rot != oversampled_orientations.size())
+				{
+					std::cerr<< "exp_nr_oversampled_rot= "<<exp_nr_oversampled_rot<<" oversampled_orientations.size()= "<< oversampled_orientations.size() <<std::endl;
+					REPORT_ERROR("exp_nr_oversampled_rot != oversampled_orientations.size()");
+				}
+#endif
+				// Loop over all oversampled orientations (only a single one in the first pass)
+				for (long int iover_rot = 0; iover_rot < exp_nr_oversampled_rot; iover_rot++)
+				{
+
+					// Get the Euler matrix
+					Euler_angles2matrix(XX(oversampled_orientations[iover_rot]),
+										YY(oversampled_orientations[iover_rot]),
+										ZZ(oversampled_orientations[iover_rot]), A);
+
+					// Take tilt-series into account
+					A = (exp_R_mic * A).inv();
+
+					// Project the reference map (into Fref)
+#ifdef TIMING
+					// Only time one thread, as I also only time one MPI process
+					if (thread_id == 0)
+						timer.tic(TIMING_DIFF_PROJ);
+#endif
+					(mymodel.PPref[exp_iclass]).get2DFourierTransform(Fref, A, IS_INV);
+#ifdef TIMING
+					// Only time one thread, as I also only time one MPI process
+					if (thread_id == 0)
+						timer.toc(TIMING_DIFF_PROJ);
+#endif
+
+					/// Now that reference projection has been made loop over someParticles!
+					for (long int ori_part_id = exp_my_first_ori_particle, ipart = 0; ori_part_id <= exp_my_last_ori_particle; ori_part_id++)
+					{
+						// loop over all particles inside this ori_particle
+						for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++, ipart++)
+						{
+							long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+
+							bool is_last_image_in_series = mydata.getNrImagesInSeries(part_id) == (exp_iseries + 1);
+							// Which number was this image in the combined array of exp_iseries and part_id
+							long int my_image_no = exp_starting_image_no[ipart] + exp_iseries;
+
+#ifdef DEBUG_CHECKSIZES
+							if (my_image_no >= exp_local_Minvsigma2s.size())
+							{
+								std::cerr<< "my_image_no= "<<my_image_no<<" exp_local_Minvsigma2s.size()= "<< exp_local_Minvsigma2s.size() <<std::endl;
+								REPORT_ERROR("my_image_no >= exp_local_Minvsigma2.size()");
+							}
+#endif
+							Minvsigma2 = exp_local_Minvsigma2s[my_image_no];
+
+							// Apply CTF to reference projection
+							if (do_ctf_correction && refs_are_ctf_corrected)
+							{
+
+#ifdef DEBUG_CHECKSIZES
+								if (my_image_no >= exp_local_Fctfs.size())
+								{
+									std::cerr<< "my_image_no= "<<my_image_no<<" exp_local_Fctfs.size()= "<< exp_local_Fctfs.size() <<std::endl;
+									REPORT_ERROR("my_image_no >= exp_local_Fctfs.size()");
+								}
+								if (MULTIDIM_SIZE(Fref) != MULTIDIM_SIZE(exp_local_Fctfs[my_image_no]))
+								{
+									std::cerr<< "MULTIDIM_SIZE(Fref)= "<<MULTIDIM_SIZE(Fref)<<" MULTIDIM_SIZE()= "<< MULTIDIM_SIZE(exp_local_Fctfs[my_image_no]) <<std::endl;
+									REPORT_ERROR("MULTIDIM_SIZE(Fref) != MULTIDIM_SIZE(exp_local_Fctfs[my_image_no)");
+								}
+
+#endif
+								FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fref)
+								{
+									DIRECT_MULTIDIM_ELEM(Frefctf, n) = DIRECT_MULTIDIM_ELEM(Fref, n) * DIRECT_MULTIDIM_ELEM(exp_local_Fctfs[my_image_no], n);
+								}
+							}
+							else
+								Frefctf = Fref;
+
+							if (do_scale_correction)
+							{
+								int group_id = mydata.getGroupId(part_id, exp_iseries);
+#ifdef DEBUG_CHECKSIZES
+								if (group_id >= mymodel.scale_correction.size())
+								{
+									std::cerr<< "group_id= "<<group_id<<" mymodel.scale_correction.size()= "<< mymodel.scale_correction.size() <<std::endl;
+									REPORT_ERROR("group_id >= mymodel.scale_correction.size()");
+								}
+#endif
+								double myscale = mymodel.scale_correction[group_id];
+								FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Frefctf)
+								{
+									DIRECT_MULTIDIM_ELEM(Frefctf, n) *= myscale;
+								}
+							}
+
+							for (long int itrans = 0; itrans < exp_nr_trans; itrans++)
+							{
+								long int ihidden = iorientclass * exp_nr_trans + itrans;
+
+#ifdef DEBUG_CHECKSIZES
+								if (exp_ipass > 0 && ihidden >= XSIZE(exp_Mcoarse_significant))
+								{
+									std::cerr<< "ihidden= "<<ihidden<<" XSIZE(exp_Mcoarse_significant)= "<< XSIZE(exp_Mcoarse_significant) <<std::endl;
+									REPORT_ERROR("ihidden >= XSIZE(exp_Mcoarse_significant)");
+								}
+#endif
+								// In the first pass, always proceed
+								// In the second pass, check whether this translations (&orientation) had a significant weight in the first pass
+								bool do_proceed = (exp_ipass == 0) ? true : DIRECT_A2D_ELEM(exp_Mcoarse_significant, ipart, ihidden);
+								if (do_proceed)
+								{
+
+									sampling.getTranslations(itrans, exp_current_oversampling, oversampled_translations);
+									for (long int iover_trans = 0; iover_trans < exp_nr_oversampled_trans; iover_trans++)
+									{
+#ifdef TIMING
+										// Only time one thread, as I also only time one MPI process
+										if (thread_id == 0)
+											timer.tic(TIMING_DIFF_DIFF2);
+#endif
+										// Get the shifted image
+										long int ishift = my_image_no * exp_nr_oversampled_trans * exp_nr_trans +
+												itrans * exp_nr_oversampled_trans + iover_trans;
+
+#ifdef DEBUG_CHECKSIZES
+										if (ishift >= exp_local_Fimgs_shifted.size())
+										{
+											std::cerr<< "ishift= "<<ishift<<" exp_local_Fimgs_shifted.size()= "<< exp_local_Fimgs_shifted.size() <<std::endl;
+											std::cerr << " itrans= " << itrans << std::endl;
+											std::cerr << " ipart= " << ipart << std::endl;
+											std::cerr << " exp_nr_oversampled_trans= " << exp_nr_oversampled_trans << " exp_nr_trans= " << exp_nr_trans << " iover_trans= " << iover_trans << std::endl;
+											REPORT_ERROR("ishift >= exp_local_Fimgs_shifted.size()");
+										}
+#endif
+
+										Fimg_shift = exp_local_Fimgs_shifted[ishift];
+//#define DEBUG_GETALLDIFF2
+#ifdef DEBUG_GETALLDIFF2
+                                        if (verb> 0)
+                                        {
+										FourierTransformer transformer;
+										Image<double> tt;
+										tt().resize(exp_current_image_size, exp_current_image_size);
+										transformer.inverseFourierTransform(Fimg_shift, tt());
+										CenterFFT(tt(),false);
+										tt.write("Fimg_shift.spi");
+										transformer.inverseFourierTransform(Frefctf, tt());
+										CenterFFT(tt(),false);
+										tt.write("Fref.spi");
+										tt()=Minvsigma2;
+										tt.write("Minvsigma2.spi");
+										std::cerr << "written Minvsigma2.spi" << std::endl;
+
+										char c;
+										std::cerr << "Written Fimg_shift.spi and Fref.spi. Press any key to continue..." << std::endl;
+										std::cin >> c;
+										exit(1);
+                                        }
+#endif
+
+										double diff2;
+										if ((iter == 1 && do_firstiter_cc) || do_always_cc)
+										{
+											// Do not calculate squared-differences, but signal product
+											// Negative values because smaller is worse in this case
+											diff2 = 0.;
+											double suma2 = 0.;
+											FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fimg_shift)
+											{
+												diff2 -= (DIRECT_MULTIDIM_ELEM(Frefctf, n)).real * (DIRECT_MULTIDIM_ELEM(Fimg_shift, n)).real;
+												diff2 -= (DIRECT_MULTIDIM_ELEM(Frefctf, n)).imag * (DIRECT_MULTIDIM_ELEM(Fimg_shift, n)).imag;
+												suma2 += norm(DIRECT_MULTIDIM_ELEM(Frefctf, n));
+											}
+											// Normalised cross-correlation coefficient: divide by power of reference (power of image is a constant)
+											diff2 /= sqrt(suma2) * exp_local_sqrtXi2[my_image_no];
+										}
+										else
+										{
+
+#ifdef DEBUG_CHECKSIZES
+											if (my_image_no >= exp_highres_Xi2_imgs.size())
+											{
+												std::cerr<< "my_image_no= "<<my_image_no<<" exp_highres_Xi2_imgs.size()= "<< exp_highres_Xi2_imgs.size() <<std::endl;
+												REPORT_ERROR("my_image_no >= exp_highres_Xi2_imgs.size()");
+											}
+#endif
+
+											// Calculate the actual squared difference term of the Gaussian probability function
+											// If current_size < mymodel.ori_size diff2 is initialised to the sum of
+											// all |Xij|2 terms that lie between current_size and ori_size
+											// Factor two because of factor 2 in division below, NOT because of 2-dimensionality of the complex plane!
+											diff2 = exp_highres_Xi2_imgs[my_image_no] / 2.;
+											FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fimg_shift)
+											{
+												double diff_real = (DIRECT_MULTIDIM_ELEM(Frefctf, n)).real - (DIRECT_MULTIDIM_ELEM(Fimg_shift, n)).real;
+												double diff_imag = (DIRECT_MULTIDIM_ELEM(Frefctf, n)).imag - (DIRECT_MULTIDIM_ELEM(Fimg_shift, n)).imag;
+												diff2 += (diff_real * diff_real + diff_imag * diff_imag) * 0.5 * DIRECT_MULTIDIM_ELEM(Minvsigma2, n);
+											}
+
+										}
+
+#ifdef TIMING
+										// Only time one thread, as I also only time one MPI process
+										if (thread_id == 0)
+											timer.toc(TIMING_DIFF_DIFF2);
+#endif
+
+										// Store all diff2 in exp_Mweight
+										long int ihidden_over = sampling.getPositionOversampledSamplingPoint(ihidden, exp_current_oversampling,
+																										iover_rot, iover_trans);
+
+//#define DEBUG_DIFF2_ISNAN
+#ifdef DEBUG_DIFF2_ISNAN
+										if (std::isnan(diff2))
+										{
+											global_mutex.lock();
+											std::cerr << " ipart= " << ipart << std::endl;
+											std::cerr << " diff2= " << diff2 << " thisthread_min_diff2[ipart]= " << thisthread_min_diff2[ipart] << " ipart= " << ipart << std::endl;
+											std::cerr << " exp_highres_Xi2_imgs[my_image_no]= " << exp_highres_Xi2_imgs[my_image_no] << std::endl;
+											std::cerr<< " exp_nr_oversampled_trans="<<exp_nr_oversampled_trans<<std::endl;
+											std::cerr<< " exp_nr_oversampled_rot="<<exp_nr_oversampled_rot<<std::endl;
+											std::cerr << " iover_rot= " << iover_rot << " iover_trans= " << iover_trans << " ihidden= " << ihidden << std::endl;
+											std::cerr << " exp_current_oversampling= " << exp_current_oversampling << std::endl;
+											std::cerr << " ihidden_over= " << ihidden_over << " XSIZE(Mweight)= " << XSIZE(exp_Mweight) << std::endl;
+											int group_id = mydata.getGroupId(part_id, exp_iseries);
+											std::cerr << " mymodel.scale_correction[group_id]= " << mymodel.scale_correction[group_id] << std::endl;
+											if (std::isnan(mymodel.scale_correction[group_id]))
+											{
+												for (int i=0; i < mymodel.scale_correction.size(); i++)
+													std::cerr << " i= " << i << " mymodel.scale_correction[i]= " << mymodel.scale_correction[i] << std::endl;
+											}
+											std::cerr << " group_id= " << group_id << std::endl;
+											Image<double> It;
+											It()=Minvsigma2;
+											It.write("Minvsigma2.spi");
+											std::cerr << "written Minvsigma2.spi" << std::endl;
+											std::cerr << "Frefctf shape= "; Frefctf.printShape(std::cerr);
+											std::cerr << "Fimg_shift shape= "; Fimg_shift.printShape(std::cerr);
+											It()=exp_local_Fctfs[my_image_no];
+											It.write("exp_local_Fctf.spi");
+											std::cerr << "written exp_local_Fctf.spi" << std::endl;
+											FourierTransformer transformer;
+											Image<double> tt;
+											tt().resize(exp_current_image_size, exp_current_image_size);
+											transformer.inverseFourierTransform(Fimg_shift, tt());
+											CenterFFT(tt(),false);
+											tt.write("Fimg_shift.spi");
+											std::cerr << "written Fimg_shift.spi" << std::endl;
+											FourierTransformer transformer2;
+											tt().initZeros();
+											transformer2.inverseFourierTransform(Frefctf, tt());
+											CenterFFT(tt(),false);
+											tt.write("Frefctf.spi");
+											std::cerr << "written Frefctf.spi" << std::endl;
+											FourierTransformer transformer3;
+											tt().initZeros();
+											transformer3.inverseFourierTransform(Fref, tt());
+											CenterFFT(tt(),false);
+											tt.write("Fref.spi");
+											std::cerr << "written Fref.spi" << std::endl;
+											std::cerr << " A= " << A << std::endl;
+											std::cerr << " exp_R_mic= " << exp_R_mic << std::endl;
+											std::cerr << "written Frefctf.spi" << std::endl;
+											REPORT_ERROR("diff2 is not a number");
+											global_mutex.unlock();
+										}
+#endif
+//#define DEBUG_VERBOSE
+#ifdef DEBUG_VERBOSE
+										global_mutex.lock();
+										if (verb > 0)
+										{
+											std::cout << " rot= " << XX(oversampled_orientations[iover_rot]) << " tilt= "<< YY(oversampled_orientations[iover_rot]) << " psi= " << ZZ(oversampled_orientations[iover_rot]) << std::endl;
+											std::cout << " xoff= " <<XX(oversampled_translations[iover_trans]) <<" yoff= "<<YY(oversampled_translations[iover_trans])<<std::endl;
+											std::cout << " ihidden_over= " << ihidden_over << " diff2= " << diff2 << " thisthread_min_diff2[ipart]= " << thisthread_min_diff2[ipart] << std::endl;
+										}
+										global_mutex.unlock();
+#endif
+#ifdef DEBUG_CHECKSIZES
+										if (ihidden_over >= XSIZE(exp_Mweight) )
+										{
+											std::cerr<< " exp_nr_oversampled_trans="<<exp_nr_oversampled_trans<<std::endl;
+											std::cerr<< " exp_nr_oversampled_rot="<<exp_nr_oversampled_rot<<std::endl;
+											std::cerr << " iover_rot= " << iover_rot << " iover_trans= " << iover_trans << " ihidden= " << ihidden << std::endl;
+											std::cerr << " exp_current_oversampling= " << exp_current_oversampling << std::endl;
+											std::cerr << " ihidden_over= " << ihidden_over << " XSIZE(Mweight)= " << XSIZE(exp_Mweight) << std::endl;
+											REPORT_ERROR("ihidden_over >= XSIZE(Mweight)");
+										}
+#endif
+
+										if (exp_iseries == 0)
+											DIRECT_A2D_ELEM(exp_Mweight, ipart, ihidden_over) = diff2;
+										else
+											DIRECT_A2D_ELEM(exp_Mweight, ipart, ihidden_over) += diff2;
+
+#ifdef DEBUG_CHECKSIZES
+										if (ipart >= thisthread_min_diff2.size())
+										{
+											std::cerr<< "ipart= "<<ipart<<" thisthread_min_diff2.size()= "<< thisthread_min_diff2.size() <<std::endl;
+											REPORT_ERROR("ipart >= thisthread_min_diff2.size() ");
+										}
+#endif
+										// Keep track of minimum of all diff2, only for the last image in this series
+										diff2 = DIRECT_A2D_ELEM(exp_Mweight, ipart, ihidden_over);
+										//std::cerr << " exp_ipass= " << exp_ipass << " exp_iclass= " << exp_iclass << " diff2= " << diff2 << std::endl;
+										if (is_last_image_in_series && diff2 < thisthread_min_diff2[ipart])
+											thisthread_min_diff2[ipart] = diff2;
+
+									} // end loop iover_trans
+								} // end if do_proceed translations
+							} // end loop itrans
+						} // end loop part_id (i)
+					} // end loop ori_part_id
+				}// end loop iover_rot
+			} // end if do_proceed orientations
+		} // end loop iorient
+	} // end while task distribution
+
+
+	// Now inside a mutex set the minimum of the squared differences among all threads
+#ifdef DEBUG_CHECKSIZES
+	if (thisthread_min_diff2.size() != exp_min_diff2.size())
+	{
+		std::cerr<< "thisthread_min_diff2.size()= "<<thisthread_min_diff2.size()<<" exp_min_diff2.size()= "<< exp_min_diff2.size() <<std::endl;
+		REPORT_ERROR("thisthread_min_diff2.size() != exp_min_diff2.size()");
+	}
+#endif
+
+	global_mutex.lock();
+	for (int i = 0; i < exp_min_diff2.size(); i++)
+	{
+		if (thisthread_min_diff2[i] < exp_min_diff2[i])
+		{
+			exp_min_diff2[i] = thisthread_min_diff2[i];
+		}
+	}
+	global_mutex.unlock();
+
+	// Wait until all threads have finished
+	global_barrier->wait();
+
+#ifdef DEBUG_THREAD
+    std::cerr << "leaving doThreadGetAllSquaredDifferences" << std::endl;
+#endif
+
+}
+
+
+void MlOptimiser::getAllSquaredDifferences()
+{
+
+#ifdef TIMING
+	if (exp_ipass == 0) timer.tic(TIMING_ESP_DIFF1);
+	else timer.tic(TIMING_ESP_DIFF2);
+#endif
+
+//#define DEBUG_GETALLDIFF2
+#ifdef DEBUG_GETALLDIFF2
+	std::cerr << " ipass= " << exp_ipass << " exp_current_oversampling= " << exp_current_oversampling << std::endl;
+	std::cerr << " sampling.NrPsiSamplings(exp_current_oversampling)= " << sampling.NrPsiSamplings(exp_current_oversampling) << std::endl;
+	std::cerr << " sampling.NrTranslationalSamplings(exp_current_oversampling)= " << sampling.NrTranslationalSamplings(exp_current_oversampling) << std::endl;
+	std::cerr << " sampling.NrSamplingPoints(exp_current_oversampling)= " << sampling.NrSamplingPoints(exp_current_oversampling) << std::endl;
+	std::cerr << " sampling.oversamplingFactorOrientations(exp_current_oversampling)= "<<sampling.oversamplingFactorOrientations(exp_current_oversampling) << std::endl;
+	std::cerr << " sampling.oversamplingFactorTranslations(exp_current_oversampling)= "<<sampling.oversamplingFactorTranslations(exp_current_oversampling) << std::endl;
+#endif
+
+	// Initialise min_diff and exp_Mweight for this pass
+	exp_Mweight.resize(exp_nr_particles, mymodel.nr_classes * sampling.NrSamplingPoints(exp_current_oversampling, false));
+	exp_Mweight.initConstant(-999.);
+	if (exp_ipass==0)
+		exp_Mcoarse_significant.clear();
+
+	exp_min_diff2.clear();
+	exp_min_diff2.resize(exp_nr_particles);
+	for (int n = 0; n < exp_nr_particles; n++)
+		exp_min_diff2[n] = 99.e99;
+
+	// Use pre-sized vectors instead of push_backs!!
+	exp_local_Fimgs_shifted.clear();
+	exp_local_Fimgs_shifted.resize(exp_nr_images * sampling.NrTranslationalSamplings(exp_current_oversampling));
+	exp_local_Fimgs_shifted_nomask.clear();
+	exp_local_Fimgs_shifted_nomask.resize(exp_nr_images * sampling.NrTranslationalSamplings(exp_current_oversampling));
+	exp_local_Minvsigma2s.clear();
+	exp_local_Minvsigma2s.resize(exp_nr_images);
+	exp_local_Fctfs.clear();
+	exp_local_Fctfs.resize(exp_nr_images);
+	exp_local_sqrtXi2.clear();
+	exp_local_sqrtXi2.resize(exp_nr_images);
+
+	// TODO: MAKE SURE THAT ALL PARTICLES IN SomeParticles ARE FROM THE SAME AREA, SO THAT THE R_mic CAN BE RE_USED!!!
+
+	//for (exp_iseries = 0; exp_iseries < mydata.getNrImagesInSeries(part_id); exp_iseries++)
+	for (exp_iseries = 0; exp_iseries < mydata.getNrImagesInSeries((mydata.ori_particles[exp_my_first_ori_particle]).particles_id[0]); exp_iseries++)
+	{
+
+		// Get all shifted versions of the (downsized) images, their (downsized) CTFs and their inverted Sigma2 matrices
+		exp_ipart_ThreadTaskDistributor->reset(); // reset thread distribution tasks
+		global_ThreadManager->run(globalThreadPrecalculateShiftedImagesCtfsAndInvSigma2s);
+
+		// Get micrograph transformation matrix. Note that for all pooled particles (exp_my_first_particle-exp_my_last_particle)
+		// the same exp_R_mic will be used in order to re-use the reference projections
+		// This is the reason why all pooled particles should come from the same micrograph
+		// TODO: THAT STILL NEEDS TO BE CONFIRMED!!!! CURRENTLY NO CHECK ON SAME-PARTICLENAME IN EACH POOL!!!
+		// WORKAROUND FOR NOW: just set --pool 1
+		//exp_R_mic = mydata.getMicrographTransformationMatrix((mydata.ori_particles[exp_my_first_ori_particle]).particles_id[0], exp_iseries);
+		int my_image_no = exp_starting_image_no[0] + exp_iseries;
+		// Get micrograph transformation matrix
+		exp_R_mic.resize(3,3);
+		exp_R_mic(0,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_0);
+		exp_R_mic(0,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_1);
+		exp_R_mic(0,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_2);
+		exp_R_mic(1,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_0);
+		exp_R_mic(1,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_1);
+		exp_R_mic(1,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_2);
+		exp_R_mic(2,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_0);
+		exp_R_mic(2,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_1);
+		exp_R_mic(2,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_2);
+
+		// Loop from iclass_min to iclass_max to deal with seed generation in first iteration
+		for (exp_iclass = iclass_min; exp_iclass <= iclass_max; exp_iclass++)
+		{
+			if (mymodel.pdf_class[exp_iclass] > 0.)
+			{
+
+				exp_iorient_ThreadTaskDistributor->reset(); // reset thread distribution tasks
+				global_ThreadManager->run(globalThreadGetSquaredDifferencesAllOrientations);
+
+			} // end if mymodel.pdf_class[iclass] > 0.
+		} // end loop iclass
+	} // end loop iseries
+
+#ifdef DEBUG_GETALLDIFF2b
+	for (long int part_id = exp_my_first_particle, ipart = 0; part_id <= exp_my_last_particle; part_id++, ipart++)
+	{
+		if (exp_min_diff2[ipart] < 0.)
+		{
+			std::cerr << "Negative min_diff2...." << std::endl;
+			std::cerr << " ipart= " << ipart << " part_id= "<<part_id<<std::endl;
+			std::cerr << " do_firstiter_cc= " << do_firstiter_cc << std::endl;
+			int group_id = mydata.getGroupId(part_id, 0);
+			std::cerr << " group_id= " << group_id << std::endl;
+			std::cerr << " ml_model.sigma2_noise[group_id]= " << mymodel.sigma2_noise[group_id] << std::endl;
+		}
+	}
+#endif
+
+#ifdef TIMING
+	if (exp_ipass == 0) timer.toc(TIMING_ESP_DIFF1);
+	else timer.toc(TIMING_ESP_DIFF2);
+#endif
+
+}
+
+void MlOptimiser::doThreadConvertSquaredDifferencesToWeightsAllOrientations(int thread_id)
+{
+#ifdef DEBUG_THREAD
+    std::cerr << "entering doThreadConvertSquaredDifferencesToWeightsAllOrientations" << std::endl;
+#endif
+
+
+    // Store local sum of weights for this thread and then combined all threads at the end of this function inside a mutex.
+	double thisthread_sumweight = 0.;
+
+	// exp_iclass loop does not always go from 0 to nr_classes!
+	long int iorientclass_offset = exp_iclass * exp_nr_rot;
+
+	size_t first_iorient = 0, last_iorient = 0;
+	while (exp_iorient_ThreadTaskDistributor->getTasks(first_iorient, last_iorient))
+	{
+		for (long int iorient = first_iorient; iorient <= last_iorient; iorient++)
+		{
+
+			double pdf_orientation;
+			long int iorientclass = iorientclass_offset + iorient;
+			long int idir = iorient / exp_nr_psi;
+			long int ipsi = iorient % exp_nr_psi;
+
+			// Get prior for this direction
+			if (mymodel.orientational_prior_mode == NOPRIOR)
+			{
+#ifdef DEBUG_CHECKSIZES
+				if (idir >= XSIZE(mymodel.pdf_direction[exp_iclass]))
+				{
+					std::cerr<< "idir= "<<idir<<" XSIZE(mymodel.pdf_direction[exp_iclass])= "<< XSIZE(mymodel.pdf_direction[exp_iclass]) <<std::endl;
+					REPORT_ERROR("idir >= mymodel.pdf_direction[exp_iclass].size()");
+				}
+#endif
+				pdf_orientation = DIRECT_MULTIDIM_ELEM(mymodel.pdf_direction[exp_iclass], idir);
+			}
+			else
+			{
+				pdf_orientation = sampling.getPriorProbability(idir, ipsi);
+			}
+
+			// Loop over all translations
+			for (long int itrans = 0; itrans < exp_nr_trans; itrans++)
+			{
+
+				long int ihidden = iorientclass * exp_nr_trans + itrans;
+
+				// To speed things up, only calculate pdf_offset at the coarse sampling.
+				// That should not matter much, and that way one does not need to calculate all the OversampledTranslations
+				Matrix1D<double> my_offset, my_prior;
+				sampling.getTranslation(itrans, my_offset);
+				// Convert offsets back to Angstroms to calculate PDF!
+				// TODO: if series, then have different exp_old_xoff for each my_image_no....
+				// WHAT TO DO WITH THIS?!!!
+
+				double pdf_offset;
+				if (mymodel.ref_dim == 2)
+					pdf_offset = calculatePdfOffset(exp_old_offset[exp_iimage] + my_offset, mymodel.prior_offset_class[exp_iclass]);
+				else
+					pdf_offset = calculatePdfOffset(exp_old_offset[exp_iimage] + my_offset, exp_prior[exp_iimage]);
+
+				// TMP DEBUGGING
+				if (mymodel.orientational_prior_mode != NOPRIOR && (pdf_offset==0. || pdf_orientation==0.))
+				{
+					global_mutex.lock();
+					std::cerr << " pdf_offset= " << pdf_offset << " pdf_orientation= " << pdf_orientation << std::endl;
+					std::cerr << " exp_ipart= " << exp_ipart << " exp_part_id= " << exp_part_id << std::endl;
+					std::cerr << " iorient= " << iorient << " idir= " << idir << " ipsi= " << ipsi << std::endl;
+					std::cerr << " exp_nr_psi= " << exp_nr_psi << " exp_nr_dir= " << exp_nr_dir << " exp_nr_trans= " << exp_nr_trans << std::endl;
+					for (long int i = 0; i < sampling.directions_prior.size(); i++)
+						std::cerr << " sampling.directions_prior["<<i<<"]= " << sampling.directions_prior[i] << std::endl;
+					for (long int i = 0; i < sampling.psi_prior.size(); i++)
+						std::cerr << " sampling.psi_prior["<<i<<"]= " << sampling.psi_prior[i] << std::endl;
+					REPORT_ERROR("ERROR! pdf_offset==0.|| pdf_orientation==0.");
+					global_mutex.unlock();
+				}
+				if (exp_nr_oversampled_rot == 0)
+					REPORT_ERROR("exp_nr_oversampled_rot == 0");
+				if (exp_nr_oversampled_trans == 0)
+					REPORT_ERROR("exp_nr_oversampled_trans == 0");
+
+
+#ifdef TIMING
+				// Only time one thread, as I also only time one MPI process
+				if (thread_id == 0)
+					timer.tic(TIMING_WEIGHT_EXP);
+#endif
+
+				// Now first loop over iover_rot, because that is the order in exp_Mweight as well
+				long int ihidden_over = ihidden * exp_nr_oversampled_rot * exp_nr_oversampled_trans;
+				for (long int iover_rot = 0; iover_rot < exp_nr_oversampled_rot; iover_rot++)
+				{
+					// Then loop over iover_trans
+					for (long int iover_trans = 0; iover_trans < exp_nr_oversampled_trans; iover_trans++, ihidden_over++)
+					{
+
+#ifdef DEBUG_CHECKSIZES
+						if (ihidden_over >= XSIZE(exp_Mweight))
+						{
+							std::cerr<< "ihidden_over= "<<ihidden_over<<" XSIZE(Mweight)= "<< XSIZE(exp_Mweight) <<std::endl;
+							REPORT_ERROR("ihidden_over >= XSIZE(exp_Mweight)");
+						}
+#endif
+
+						// Only exponentiate for determined values of exp_Mweight
+						// (this is always true in the first pass, but not so in the second pass)
+						// Only deal with this sampling point if its weight was significant
+#ifdef DEBUG_CHECKSIZES
+						if (exp_iimage >= YSIZE(exp_Mweight))
+						{
+							std::cerr<< "exp_iimage= "<<exp_iimage<<" YSIZE(exp_Mweight)= "<< YSIZE(exp_Mweight) <<std::endl;
+							std::cerr << " exp_ipart= " << exp_ipart << std::endl;
+							std::cerr << " DIRECT_A2D_ELEM(exp_Mweight, exp_iimage, ihidden_over)= " << DIRECT_A2D_ELEM(exp_Mweight, exp_iimage, ihidden_over) << std::endl;
+							std::cerr << " DIRECT_A2D_ELEM(exp_Mweight, exp_ipart, ihidden_over)= " << DIRECT_A2D_ELEM(exp_Mweight, exp_ipart, ihidden_over) << std::endl;
+							REPORT_ERROR("exp_iimage >= YSIZE(exp_Mweight)");
+						}
+#endif
+
+						if (DIRECT_A2D_ELEM(exp_Mweight, exp_ipart, ihidden_over) < 0.)
+						{
+							DIRECT_A2D_ELEM(exp_Mweight, exp_ipart, ihidden_over) = 0.;
+						}
+						else
+						{
+							double weight = pdf_orientation * pdf_offset;
+
+							double diff2 = DIRECT_A2D_ELEM(exp_Mweight, exp_ipart, ihidden_over) - exp_min_diff2[exp_ipart];
+
+							// next line because of numerical precision of exp-function
+							if (diff2 > 700.) weight = 0.;
+							// TODO: use tabulated exp function?
+							else weight *= exp(-diff2);
+//#define DEBUG_PSIANGLE_PDISTRIBUTION
+#ifdef DEBUG_PSIANGLE_PDISTRIBUTION
+							std::cout << ipsi*360./sampling.NrPsiSamplings() << " "<< weight << std::endl;
+#endif
+							// Store the weight
+							DIRECT_A2D_ELEM(exp_Mweight, exp_ipart, ihidden_over) = weight;
+
+#ifdef DEBUG_CHECKSIZES
+							if (std::isnan(weight))
+							{
+								global_mutex.lock();
+								std::cerr<< "weight= "<<weight<<" is not a number! " <<std::endl;
+								std::cerr << " exp_min_diff2[exp_ipart]= " << exp_min_diff2[exp_ipart] << std::endl;
+								std::cerr << " exp_ipart= " << exp_ipart << std::endl;
+								std::cerr << " exp_part_id= " << exp_part_id << std::endl;
+								std::cerr << " mydata.getNrImagesInSeries(exp_part_id)= " << mydata.getNrImagesInSeries(exp_part_id) << std::endl;
+								long int my_image_no = exp_iimage + 0;
+								std::cerr << " my_image_no= " << my_image_no << std::endl;
+								std::cerr << " exp_iimage= " << exp_iimage << std::endl;
+								std::cerr << " DIRECT_A2D_ELEM(exp_Mweight, my_image_no, ihidden_over)= " << DIRECT_A2D_ELEM(exp_Mweight, my_image_no, ihidden_over) << std::endl;
+								REPORT_ERROR("weight is not a number");
+								global_mutex.unlock();
+							}
+#endif
+
+							// Keep track of sum and maximum of all weights for this particle
+							// Later add all to exp_thisparticle_sumweight, but inside this loop sum to local thisthread_sumweight first
+							thisthread_sumweight += weight;
+
+						} // end if/else exp_Mweight < 0.
+					} // end loop iover_trans
+				}// end loop iover_rot
+#ifdef TIMING
+				// Only time one thread, as I also only time one MPI process
+				if (thread_id == 0)
+					timer.toc(TIMING_WEIGHT_EXP);
+#endif
+			} // end loop itrans
+
+		} // end loop iorient
+	} // end while task distributor
+
+	// Now inside a mutex update the sum of all weights
+	global_mutex.lock();
+	exp_thisparticle_sumweight += thisthread_sumweight;
+	global_mutex.unlock();
+
+	// Wait until all threads have finished
+	global_barrier->wait();
+
+
+
+#ifdef DEBUG_THREAD
+    std::cerr << "leaving doThreadConvertSquaredDifferencesToWeightsAllOrientations" << std::endl;
+#endif
+}
+
+void MlOptimiser::convertAllSquaredDifferencesToWeights()
+{
+
+#ifdef TIMING
+	if (exp_ipass == 0) timer.tic(TIMING_ESP_WEIGHT1);
+	else timer.tic(TIMING_ESP_WEIGHT2);
+#endif
+
+	// Convert the squared differences into weights
+	// Note there is only one weight for each part_id, because a whole series of images is treated as one particle
+
+	// Initialising...
+	exp_sum_weight.resize(exp_nr_particles);
+	for (int i = 0; i < exp_nr_particles; i++)
+		exp_sum_weight[i] = 0.;
+
+//#define DEBUG_CONVERTDIFF2W
+#ifdef DEBUG_CONVERTDIFF2W
+	double max_weight = -1.;
+	double opt_psi, opt_xoff, opt_yoff;
+	int opt_iover_rot, opt_iover_trans, opt_ipsi, opt_itrans;
+	long int opt_ihidden, opt_ihidden_over;
+#endif
+
+	//TMP DEBUGGING
+	//DEBUGGING_COPY_exp_Mweight = exp_Mweight;
+
+	// Loop from iclass_min to iclass_max to deal with seed generation in first iteration
+	exp_iimage = 0;
+	exp_ipart = 0;
+	for (long int ori_part_id = exp_my_first_ori_particle; ori_part_id <= exp_my_last_ori_particle; ori_part_id++)
+	{
+		// loop over all particles inside this ori_particle
+		for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++, exp_ipart++)
+		{
+			exp_part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+			exp_thisparticle_sumweight = 0.;
+
+
+			if ((iter == 1 && do_firstiter_cc) || do_always_cc)
+			{
+
+				// Binarize the squared differences array to skip marginalisation
+				// Note this loop is not threaded. This is not so important because it will only be executed in the 1st iteration and is fast anyway
+				double mymindiff2 = 99.e10, mymaxprob = -99.e10;
+				long int myminidx = -1;
+				// Find the smallest element in this row of exp_Mweight
+				for (long int i = 0; i < XSIZE(exp_Mweight); i++)
+				{
+
+					double cc = DIRECT_A2D_ELEM(exp_Mweight, exp_ipart, i);
+					// ignore non-determined cc
+					if (cc == -999.)
+						continue;
+
+					if (do_sim_anneal && iter > 1)
+					{
+						// P_accept = exp ( - (CCold -CC)/temperature)
+						// cc is negative value, so use "+ cc"
+						double my_prob = rnd_unif() * exp(-(exp_local_oldcc[exp_ipart] + cc)/temperature);
+						if (my_prob > mymaxprob)
+						{
+							mymaxprob = my_prob;
+							mymindiff2 = cc;
+							myminidx = i;
+						}
+					}
+					else
+					{
+						// just search for the maximum
+						if (cc < mymindiff2)
+						{
+							mymindiff2 = cc;
+							myminidx = i;
+						}
+					}
+				}
+				// Set all except for the best hidden variable to zero and the smallest element to 1
+				for (long int i = 0; i < XSIZE(exp_Mweight); i++)
+					DIRECT_A2D_ELEM(exp_Mweight, exp_ipart, i)= 0.;
+
+				DIRECT_A2D_ELEM(exp_Mweight, exp_ipart, myminidx)= 1.;
+				exp_thisparticle_sumweight += 1.;
+
+			}
+			else
+			{
+				for (exp_iclass = iclass_min; exp_iclass <= iclass_max; exp_iclass++)
+				{
+
+					// The loops over all orientations are parallelised using threads
+					exp_iorient_ThreadTaskDistributor->reset(); // reset thread distribution tasks
+					global_ThreadManager->run(globalThreadConvertSquaredDifferencesToWeightsAllOrientations);
+
+				} // end loop iclass
+
+			} // end else iter==1 && do_firstiter_cc
+
+			// Keep track of number of processed images
+			exp_iimage += mydata.getNrImagesInSeries(exp_part_id);
+
+			//Store parameters for this particle
+			exp_sum_weight[exp_ipart] = exp_thisparticle_sumweight;
+
+			// Check the sum of weights is not zero
+// On a Mac, the isnan function does not compile. Just uncomment the define statement, as this is merely a debugging statement
+//#define MAC_OSX
+#ifndef MAC_OSX
+			if (exp_thisparticle_sumweight == 0. || std::isnan(exp_thisparticle_sumweight))
+			{
+				std::cerr << " exp_thisparticle_sumweight= " << exp_thisparticle_sumweight << std::endl;
+				Image<double> It;
+				It() = exp_Mweight;
+				It.write("Mweight.spi");
+				//It() = DEBUGGING_COPY_exp_Mweight;
+				//It.write("Mweight_copy.spi");
+				It().resize(exp_Mcoarse_significant);
+				if (MULTIDIM_SIZE(It()) > 0)
+				{
+					FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(It())
+					{
+						if (DIRECT_MULTIDIM_ELEM(exp_Mcoarse_significant, n))
+							DIRECT_MULTIDIM_ELEM(It(), n) = 1.;
+						else
+							DIRECT_MULTIDIM_ELEM(It(), n) = 0.;
+					}
+					It.write("Mcoarse_significant.spi");
+				}
+				std::cerr << " exp_part_id= " << exp_part_id << "exp_iimage="<<exp_iimage<<std::endl;
+				int group_id = mydata.getGroupId(exp_part_id, 0);
+				std::cerr << " group_id= " << group_id << " mymodel.scale_correction[group_id]= " << mymodel.scale_correction[group_id] << std::endl;
+				std::cerr << " exp_ipass= " << exp_ipass << std::endl;
+				std::cerr << " sampling.NrDirections(0, true)= " << sampling.NrDirections(0, true)
+						<< " sampling.NrDirections(0, false)= " << sampling.NrDirections(0, false) << std::endl;
+				std::cerr << " sampling.NrPsiSamplings(0, true)= " << sampling.NrPsiSamplings(0, true)
+						<< " sampling.NrPsiSamplings(0, false)= " << sampling.NrPsiSamplings(0, false) << std::endl;
+				std::cerr << " mymodel.sigma2_noise[exp_ipart]= " << mymodel.sigma2_noise[exp_ipart] << std::endl;
+				std::cerr << " wsum_model.sigma2_noise[exp_ipart]= " << wsum_model.sigma2_noise[exp_ipart] << std::endl;
+				if (mymodel.orientational_prior_mode == NOPRIOR)
+					std::cerr << " wsum_model.pdf_direction[exp_ipart]= " << wsum_model.pdf_direction[exp_ipart] << std::endl;
+				if (do_norm_correction)
+				{
+					std::cerr << " mymodel.avg_norm_correction= " << mymodel.avg_norm_correction << std::endl;
+					std::cerr << " wsum_model.avg_norm_correction= " << wsum_model.avg_norm_correction << std::endl;
+				}
+
+				std::cerr << "written out Mweight.spi" << std::endl;
+				std::cerr << " exp_thisparticle_sumweight= " << exp_thisparticle_sumweight << std::endl;
+				std::cerr << " exp_min_diff2[exp_ipart]= " << exp_min_diff2[exp_ipart] << std::endl;
+				REPORT_ERROR("ERROR!!! zero sum of weights....");
+			}
+#endif
+
+		} // end loop part_id (i)
+	} // end loop ori_part_id
+
+	// The remainder of this function is not threaded.
+
+	// Initialise exp_Mcoarse_significant
+	if (exp_ipass==0)
+		exp_Mcoarse_significant.resize(exp_nr_particles, XSIZE(exp_Mweight));
+
+	// Now, for each particle,  find the exp_significant_weight that encompasses adaptive_fraction of exp_sum_weight
+	exp_significant_weight.clear();
+	exp_significant_weight.resize(exp_nr_particles, 0.);
+	for (long int ori_part_id = exp_my_first_ori_particle, my_image_no = 0, ipart = 0; ori_part_id <= exp_my_last_ori_particle; ori_part_id++)
+	{
+		// loop over all particles inside this ori_particle
+		for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++, ipart++)
+		{
+			long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+
+	#ifdef TIMING
+	timer.tic(TIMING_WEIGHT_SORT);
+	#endif
+			MultidimArray<double> sorted_weight;
+			// Get the relevant row for this particle
+			exp_Mweight.getRow(ipart, sorted_weight);
+
+			// Only select non-zero probabilities to speed up sorting
+			long int np = 0;
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(sorted_weight)
+			{
+				if (DIRECT_MULTIDIM_ELEM(sorted_weight, n) > 0.)
+				{
+					DIRECT_MULTIDIM_ELEM(sorted_weight, np) = DIRECT_MULTIDIM_ELEM(sorted_weight, n);
+					np++;
+				}
+			}
+			sorted_weight.resize(np);
+
+			// Sort from low to high values
+			sorted_weight.sort();
+
+	#ifdef TIMING
+	timer.toc(TIMING_WEIGHT_SORT);
+	#endif
+			double frac_weight = 0.;
+			double my_significant_weight;
+			long int my_nr_significant_coarse_samples = 0;
+			for (long int i = XSIZE(sorted_weight) - 1; i >= 0; i--)
+			{
+				if (exp_ipass==0) my_nr_significant_coarse_samples++;
+				my_significant_weight = DIRECT_A1D_ELEM(sorted_weight, i);
+				frac_weight += my_significant_weight;
+				if (frac_weight > adaptive_fraction * exp_sum_weight[ipart])
+					break;
+			}
+
+	#ifdef DEBUG_SORT
+			// Check sorted array is really sorted
+			double prev = 0.;
+			FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(sorted_weight)
+			{
+				if (DIRECT_MULTIDIM_ELEM(sorted_weight, n) < prev)
+				{
+					Image<double> It;
+					It()=sorted_weight;
+					It() *= 10000;
+					It.write("sorted_weight.spi");
+					std::cerr << "written sorted_weight.spi" << std::endl;
+					REPORT_ERROR("Error in sorting!");
+				}
+				prev=DIRECT_MULTIDIM_ELEM(sorted_weight, n);
+			}
+	#endif
+
+			if (exp_ipass==0 && my_nr_significant_coarse_samples == 0)
+			{
+				std::cerr << " ipart= " << ipart << " adaptive_fraction= " << adaptive_fraction << std::endl;
+				std::cerr << " frac-weight= " << frac_weight << std::endl;
+				std::cerr << " exp_sum_weight[ipart]= " << exp_sum_weight[ipart] << std::endl;
+				Image<double> It;
+				std::cerr << " XSIZE(exp_Mweight)= " << XSIZE(exp_Mweight) << std::endl;
+				It()=exp_Mweight;
+				It() *= 10000;
+				It.write("Mweight2.spi");
+				std::cerr << "written Mweight2.spi" << std::endl;
+				std::cerr << " np= " << np << std::endl;
+				It()=sorted_weight;
+				It() *= 10000;
+				std::cerr << " XSIZE(sorted_weight)= " << XSIZE(sorted_weight) << std::endl;
+				if (XSIZE(sorted_weight) > 0)
+				{
+					It.write("sorted_weight.spi");
+					std::cerr << "written sorted_weight.spi" << std::endl;
+				}
+				REPORT_ERROR("my_nr_significant_coarse_samples == 0");
+			}
+
+			if (exp_ipass==0)
+			{
+				// Store nr_significant_coarse_samples for all images in this series
+				for (int iseries = 0; iseries < mydata.getNrImagesInSeries(part_id); iseries++, my_image_no++)
+				{
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NR_SIGN) = (double)my_nr_significant_coarse_samples;
+				}
+
+				// Keep track of which coarse samplings were significant were significant for this particle
+				for (int ihidden = 0; ihidden < XSIZE(exp_Mcoarse_significant); ihidden++)
+				{
+					if (DIRECT_A2D_ELEM(exp_Mweight, ipart, ihidden) >= my_significant_weight)
+						DIRECT_A2D_ELEM(exp_Mcoarse_significant, ipart, ihidden) = true;
+					else
+						DIRECT_A2D_ELEM(exp_Mcoarse_significant, ipart, ihidden) = false;
+				}
+
+			}
+			exp_significant_weight[ipart] = my_significant_weight;
+	#ifdef DEBUG_OVERSAMPLING
+			std::cerr << " sum_weight[ipart]= " << exp_sum_weight[ipart] << " my_significant_weight= " << my_significant_weight << std::endl;
+			std::cerr << " my_nr_significant_coarse_samples= " << my_nr_significant_coarse_samples << std::endl;
+			std::cerr << " ipass= " << exp_ipass << " Pmax="<<DIRECT_A1D_ELEM(sorted_weight,XSIZE(sorted_weight) - 1)/frac_weight
+					<<" nr_sign_sam= "<<nr_significant_samples<<" sign w= "<<exp_significant_weight<< "sum_weight= "<<exp_sum_weight<<std::endl;
+	#endif
+
+		} // end loop part_id (i)
+	} // end loop ori_part_id
+
+
+#ifdef DEBUG_CONVERTDIFF2W
+	//Image<double> tt;
+	//tt()=sorted_weight;
+	//tt.write("sorted_weight.spi");
+	//std::cerr << "written sorted_weight.spi" << std::endl;
+	std::cerr << " ipass= " << exp_ipass << " exp_part_id= " << exp_part_id << std::endl;
+	std::cerr << " diff2w: opt_xoff= " << opt_xoff << " opt_yoff= " << opt_yoff << " opt_psi= " << opt_psi << std::endl;
+	std::cerr << " diff2w: opt_iover_rot= " << opt_iover_rot << " opt_iover_trans= " << opt_iover_trans << " opt_ipsi= " << opt_ipsi << std::endl;
+	std::cerr << " diff2w: opt_itrans= " << opt_itrans << " opt_ihidden= " << opt_ihidden << " opt_ihidden_over= " << opt_ihidden_over << std::endl;
+	std::cerr << "significant_weight= " << exp_significant_weight << " max_weight= " << max_weight << std::endl;
+	std::cerr << "nr_significant_coarse_samples= " << nr_significant_coarse_samples <<std::endl;
+	debug2 = (double)opt_ihidden_over;
+#endif
+
+#ifdef TIMING
+	if (exp_ipass == 0) timer.toc(TIMING_ESP_WEIGHT1);
+	else timer.toc(TIMING_ESP_WEIGHT2);
+#endif
+
+}
+
+void MlOptimiser::doThreadStoreWeightedSumsAllOrientations(int thread_id)
+{
+#ifdef DEBUG_THREAD
+    std::cerr << "entering doThreadStoreWeightedSumsAllOrientations" << std::endl;
+#endif
+
+	std::vector< Matrix1D<double> > oversampled_orientations, oversampled_translations;
+	Matrix2D<double> A;
+	MultidimArray<Complex > Fimg, Fref, Frefctf, Fimg_shift, Fimg_shift_nomask;
+	MultidimArray<double> Minvsigma2, Mctf, Fweight;
+	double rot, tilt, psi;
+	bool have_warned_small_scale = false;
+
+	// Initialising...
+	Fref.resize(exp_Fimgs[0]);
+	Frefctf.resize(exp_Fimgs[0]);
+	Fweight.resize(exp_Fimgs[0]);
+
+	// Initialise Mctf to all-1 for if !do_ctf_corection
+	Mctf.resize(exp_Fimgs[0]);
+	Mctf.initConstant(1.);
+
+	// Initialise Minvsigma2 to all-1 for if !do_map
+	Minvsigma2.resize(exp_Fimgs[0]);
+	Minvsigma2.initConstant(1.);
+
+	// Make local copies of weighted sums (excepts BPrefs, which are too big)
+	// so that there are not too many mutex locks below
+	std::vector<MultidimArray<double> > thr_wsum_sigma2_noise, thr_wsum_scale_correction_XA, thr_wsum_scale_correction_AA, thr_wsum_pdf_direction;
+	std::vector<double> thr_wsum_norm_correction, thr_sumw_group, thr_wsum_pdf_class, thr_wsum_prior_offsetx_class, thr_wsum_prior_offsety_class, thr_max_weight;
+	double thr_wsum_sigma2_offset;
+	MultidimArray<double> thr_metadata, zeroArray;
+
+	// Wsum_sigma_noise2 is a 1D-spectrum for each group
+	zeroArray.initZeros(mymodel.ori_size/2 + 1);
+	thr_wsum_sigma2_noise.resize(mymodel.nr_groups);
+	for (int n = 0; n < mymodel.nr_groups; n++)
+	{
+		thr_wsum_sigma2_noise[n] = zeroArray;
+	}
+	// scale-correction terms are a spectrum for each particle
+	thr_wsum_scale_correction_XA.resize(exp_nr_particles);
+	thr_wsum_scale_correction_AA.resize(exp_nr_particles);
+	for (int n = 0; n < exp_nr_particles; n++)
+	{
+		thr_wsum_scale_correction_XA[n] = zeroArray;
+		thr_wsum_scale_correction_AA[n] = zeroArray;
+	}
+	// wsum_pdf_direction is a 1D-array (of length sampling.NrDirections(0, true)) for each class
+	zeroArray.initZeros(sampling.NrDirections(0, true));
+	thr_wsum_pdf_direction.resize(mymodel.nr_classes);
+	for (int n = 0; n < mymodel.nr_classes; n++)
+	{
+		thr_wsum_pdf_direction[n] = zeroArray;
+	}
+	// wsum_norm_correction is a double for each particle
+	thr_wsum_norm_correction.resize(exp_nr_particles, 0.);
+	// sumw_group is a double for each group
+	thr_sumw_group.resize(mymodel.nr_groups, 0.);
+	// wsum_pdf_class is a double for each class
+	thr_wsum_pdf_class.resize(mymodel.nr_classes, 0.);
+	if (mymodel.ref_dim == 2)
+	{
+		thr_wsum_prior_offsetx_class.resize(mymodel.nr_classes, 0.);
+		thr_wsum_prior_offsety_class.resize(mymodel.nr_classes, 0.);
+	}
+	// max_weight is a double for each particle
+	thr_max_weight.resize(exp_nr_particles, 0.);
+	// wsum_sigma2_offset is just a double
+	thr_wsum_sigma2_offset = 0.;
+	// metadata is a 2D array of nr_particles x METADATA_LINE_LENGTH
+	thr_metadata.initZeros(exp_metadata);
+
+	// exp_iclass loop does not always go from 0 to nr_classes!
+	long int iorientclass_offset = exp_iclass * exp_nr_rot;
+	size_t first_iorient = 0, last_iorient = 0;
+	while (exp_iorient_ThreadTaskDistributor->getTasks(first_iorient, last_iorient))
+	{
+		for (long int iorient = first_iorient; iorient <= last_iorient; iorient++)
+		{
+
+			long int iorientclass = iorientclass_offset + iorient;
+
+			// Only proceed if any of the particles had any significant coarsely sampled translation
+			if (isSignificantAnyParticleAnyTranslation(iorientclass))
+			{
+
+				long int idir = iorient / exp_nr_psi;
+				long int ipsi = iorient % exp_nr_psi;
+
+				// Now get the oversampled (rot, tilt, psi) triplets
+				// This will be only the original (rot,tilt,psi) triplet if (adaptive_oversampling==0)
+				sampling.getOrientations(idir, ipsi, adaptive_oversampling, oversampled_orientations);
+
+				// Loop over all oversampled orientations (only a single one in the first pass)
+				for (long int iover_rot = 0; iover_rot < exp_nr_oversampled_rot; iover_rot++)
+				{
+					rot = XX(oversampled_orientations[iover_rot]);
+					tilt = YY(oversampled_orientations[iover_rot]);
+					psi = ZZ(oversampled_orientations[iover_rot]);
+					// Get the Euler matrix
+					Euler_angles2matrix(rot, tilt, psi, A);
+
+					// Take tilt-series into account
+					A = (exp_R_mic * A).inv();
+
+#ifdef TIMING
+					// Only time one thread, as I also only time one MPI process
+					if (thread_id == 0)
+						timer.tic(TIMING_WSUM_PROJ);
+#endif
+					// Project the reference map (into Fref)
+					if (!do_skip_maximization)
+						(mymodel.PPref[exp_iclass]).get2DFourierTransform(Fref, A, IS_INV);
+
+#ifdef TIMING
+					// Only time one thread, as I also only time one MPI process
+					if (thread_id == 0)
+						timer.toc(TIMING_WSUM_PROJ);
+#endif
+					// Inside the loop over all translations and all part_id sum all shift Fimg's and their weights
+					// Then outside this loop do the actual backprojection
+					Fimg.initZeros(Fref);
+					Fweight.initZeros(Fref);
+
+					/// Now that reference projection has been made loop over someParticles!
+					for (long int ori_part_id = exp_my_first_ori_particle, ipart = 0; ori_part_id <= exp_my_last_ori_particle; ori_part_id++)
+					{
+						// loop over all particles inside this ori_particle
+						for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++, ipart++)
+						{
+							long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+#ifdef DEBUG_CHECKSIZES
+							if (ipart >= exp_starting_image_no.size())
+							{
+								std::cerr<< "ipart= "<<ipart<<" starting_image_no.size()= "<< exp_starting_image_no.size() <<std::endl;
+								REPORT_ERROR("ipart >= starting_image_no.size()");
+							}
+#endif
+							// Which number was this image in the combined array of iseries and part_idpart_id
+							long int my_image_no = exp_starting_image_no[ipart] + exp_iseries;
+							int group_id = mydata.getGroupId(part_id, exp_iseries);
+
+#ifdef DEBUG_CHECKSIZES
+							if (group_id >= mymodel.nr_groups)
+							{
+								std::cerr<< "group_id= "<<group_id<<" ml_model.nr_groups= "<< mymodel.nr_groups <<std::endl;
+								REPORT_ERROR("group_id >= ml_model.nr_groups");
+							}
+#endif
+
+							if (!do_skip_maximization)
+							{
+								if (do_map)
+									Minvsigma2 = exp_local_Minvsigma2s[my_image_no];
+								// else Minvsigma2 was initialised to ones
+
+								// Apply CTF to reference projection
+								if (do_ctf_correction)
+								{
+									Mctf = exp_local_Fctfs[my_image_no];
+									if (refs_are_ctf_corrected)
+									{
+										FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fref)
+										{
+											DIRECT_MULTIDIM_ELEM(Frefctf, n) = DIRECT_MULTIDIM_ELEM(Fref, n) * DIRECT_MULTIDIM_ELEM(Mctf, n);
+										}
+									}
+									else
+									{
+										Frefctf = Fref;
+									}
+								}
+								else
+								{
+									// initialise because there are multiple particles and Mctf gets selfMultiplied for scale_correction
+									Mctf.initConstant(1.);
+									Frefctf = Fref;
+								}
+
+								if (do_scale_correction)
+								{
+									// TODO: implemenent B-factor as well...
+									double myscale = mymodel.scale_correction[group_id];
+									if (myscale > 10000.)
+									{
+										std::cerr << " rlnMicrographScaleCorrection= " << myscale << " group= " << group_id + 1 << " my_image_no= " << my_image_no << std::endl;
+										REPORT_ERROR("ERROR: rlnMicrographScaleCorrection is very high. Did you normalize your data?");
+									}
+									else if (myscale < 0.001)
+									{
+
+										if (!have_warned_small_scale)
+										{
+											std::cout << " WARNING: ignoring group " << group_id + 1 << " with very small or negative scale (" << myscale <<
+													"); Use larger groups for more stable scale estimates." << std::endl;
+											have_warned_small_scale = true;
+										}
+										myscale = 0.001;
+									}
+									FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Frefctf)
+									{
+										DIRECT_MULTIDIM_ELEM(Frefctf, n) *= myscale;
+									}
+									// For CTF-terms in BP
+									Mctf *= myscale;
+								}
+							} // end if !do_skip_maximization
+
+							long int ihidden = iorientclass * exp_nr_trans;
+							for (long int itrans = 0; itrans < exp_nr_trans; itrans++, ihidden++)
+							{
+
+								sampling.getTranslations(itrans, adaptive_oversampling, oversampled_translations);
+
+								for (long int iover_trans = 0; iover_trans < exp_nr_oversampled_trans; iover_trans++)
+								{
+
+#ifdef DEBUG_CHECKSIZES
+									if (iover_trans >= oversampled_translations.size())
+									{
+										std::cerr<< "iover_trans= "<<iover_trans<<" oversampled_translations.size()= "<< oversampled_translations.size() <<std::endl;
+										REPORT_ERROR("iover_trans >= oversampled_translations.size()");
+									}
+#endif
+
+									// Only deal with this sampling point if its weight was significant
+									long int ihidden_over = ihidden * exp_nr_oversampled_trans * exp_nr_oversampled_rot +
+											iover_rot * exp_nr_oversampled_trans + iover_trans;
+
+#ifdef DEBUG_CHECKSIZES
+									if (ihidden_over >= XSIZE(exp_Mweight))
+									{
+										std::cerr<< "ihidden_over= "<<ihidden_over<<" XSIZE(exp_Mweight)= "<< XSIZE(exp_Mweight) <<std::endl;
+										REPORT_ERROR("ihidden_over >= XSIZE(exp_Mweight)");
+									}
+									if (ipart >= exp_significant_weight.size())
+									{
+										std::cerr<< "ipart= "<<ipart<<" exp_significant_weight.size()= "<< exp_significant_weight.size() <<std::endl;
+										REPORT_ERROR("ipart >= significant_weight.size()");
+									}
+									if (ipart >= exp_max_weight.size())
+									{
+										std::cerr<< "ipart= "<<ipart<<" exp_max_weight.size()= "<< exp_max_weight.size() <<std::endl;
+										REPORT_ERROR("ipart >= exp_max_weight.size()");
+									}
+									if (ipart >= exp_sum_weight.size())
+									{
+										std::cerr<< "ipart= "<<ipart<<" exp_max_weight.size()= "<< exp_sum_weight.size() <<std::endl;
+										REPORT_ERROR("ipart >= exp_sum_weight.size()");
+									}
+#endif
+									double weight = DIRECT_A2D_ELEM(exp_Mweight, ipart, ihidden_over);
+
+									// Only sum weights for non-zero weights
+									if (weight >= exp_significant_weight[ipart])
+									{
+#ifdef TIMING
+										// Only time one thread, as I also only time one MPI process
+										if (thread_id == 0)
+											timer.tic(TIMING_WSUM_DIFF2);
+#endif
+										// Normalise the weight (do this after the comparison with exp_significant_weight!)
+										weight /= exp_sum_weight[ipart];
+
+										if (!do_skip_maximization)
+										{
+											// Get the shifted image
+											long int ishift = my_image_no * exp_nr_oversampled_trans * exp_nr_trans +
+													itrans * exp_nr_oversampled_trans + iover_trans;
+											Fimg_shift = exp_local_Fimgs_shifted[ishift];
+											Fimg_shift_nomask = exp_local_Fimgs_shifted_nomask[ishift];
+
+											// Store weighted sum of squared differences for sigma2_noise estimation
+											FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Mresol_fine)
+											{
+												int ires = DIRECT_MULTIDIM_ELEM(Mresol_fine, n);
+												if (ires > -1)
+												{
+													// Use FT of masked image for noise estimation!
+													double diff_real = (DIRECT_MULTIDIM_ELEM(Frefctf, n)).real - (DIRECT_MULTIDIM_ELEM(Fimg_shift, n)).real;
+													double diff_imag = (DIRECT_MULTIDIM_ELEM(Frefctf, n)).imag - (DIRECT_MULTIDIM_ELEM(Fimg_shift, n)).imag;
+													double wdiff2 = weight * (diff_real*diff_real + diff_imag*diff_imag);
+
+													// group-wise sigma2_noise
+													DIRECT_MULTIDIM_ELEM(thr_wsum_sigma2_noise[group_id], ires) += wdiff2;
+													// For norm_correction
+													thr_wsum_norm_correction[ipart] += wdiff2;
+												}
+											}
+
+											// Store the weighted sums of the norm_correction terms
+											if (do_scale_correction)
+											{
+												double sumXA = 0.;
+												double sumA2 = 0.;
+												FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Mresol_fine)
+												{
+													int ires = DIRECT_MULTIDIM_ELEM(Mresol_fine, n);
+#ifdef DEBUG_CHECKSIZES
+													if (ires >= XSIZE(thr_wsum_scale_correction_XA[ipart]))
+													{
+														std::cerr<< "ires= "<<ires<<" XSIZE(thr_wsum_scale_correction_XA[ipart])= "<< XSIZE(thr_wsum_scale_correction_XA[ipart]) <<std::endl;
+														REPORT_ERROR("ires >= XSIZE(thr_wsum_scale_correction_XA[ipart])");
+													}
+													if (ires >= XSIZE(thr_wsum_scale_correction_AA[ipart]))
+													{
+														std::cerr<< "ires= "<<ires<<" XSIZE(thr_wsum_scale_correction_AA[ipart])= "<< XSIZE(thr_wsum_scale_correction_AA[ipart]) <<std::endl;
+														REPORT_ERROR("ires >= XSIZE(thr_wsum_scale_correction_AA[ipart])");
+													}
+#endif
+
+													// Once the reference becomes strongly regularised one does no longer want to store XA and AA!
+													if (ires > -1 && DIRECT_A1D_ELEM(mymodel.data_vs_prior_class[exp_iclass], ires) > 3.)
+													{
+														sumXA = (DIRECT_MULTIDIM_ELEM(Frefctf, n)).real * (DIRECT_MULTIDIM_ELEM(Fimg_shift, n)).real;
+														sumXA += (DIRECT_MULTIDIM_ELEM(Frefctf, n)).imag * (DIRECT_MULTIDIM_ELEM(Fimg_shift, n)).imag;
+														DIRECT_A1D_ELEM(thr_wsum_scale_correction_XA[ipart], ires) += weight * sumXA;
+
+														// This could be pre-calculated above...
+														sumA2 = (DIRECT_MULTIDIM_ELEM(Frefctf, n)).real * (DIRECT_MULTIDIM_ELEM(Frefctf, n)).real;
+														sumA2 += (DIRECT_MULTIDIM_ELEM(Frefctf, n)).imag * (DIRECT_MULTIDIM_ELEM(Frefctf, n)).imag;
+														DIRECT_A1D_ELEM(thr_wsum_scale_correction_AA[ipart], ires) += weight * sumA2;
+													}
+												}
+											}
+
+											// Store sum of weights for this group
+											thr_sumw_group[group_id] += weight;
+
+											// Store weights for this class and orientation
+											thr_wsum_pdf_class[exp_iclass] += weight;
+
+											if (mymodel.ref_dim ==2)
+											{
+												// Also store weighted offset differences for prior_offsets of each class
+												thr_wsum_prior_offsetx_class[exp_iclass] += weight * XX(exp_old_offset[my_image_no] + oversampled_translations[iover_trans]);
+												thr_wsum_prior_offsety_class[exp_iclass] += weight * YY(exp_old_offset[my_image_no] + oversampled_translations[iover_trans]);
+
+												// Store weighted sum2 of origin offsets (in Angstroms instead of pixels!!!)
+												thr_wsum_sigma2_offset += weight * ((mymodel.prior_offset_class[exp_iclass] - exp_old_offset[my_image_no] - oversampled_translations[iover_trans]).sum2());
+
+											}
+											else
+											{
+												// Store weighted sum2 of origin offsets (in Angstroms instead of pixels!!!)
+												thr_wsum_sigma2_offset += weight * ((exp_prior[my_image_no] - exp_old_offset[my_image_no] - oversampled_translations[iover_trans]).sum2());
+											}
+
+#ifdef DEBUG_CHECKSIZES
+											if (idir >= XSIZE(thr_wsum_pdf_direction[exp_iclass]))
+											{
+												std::cerr<< "idir= "<<idir<<" XSIZE(thr_wsum_pdf_direction[exp_iclass])= "<< XSIZE(thr_wsum_pdf_direction[exp_iclass]) <<std::endl;
+												REPORT_ERROR("idir >= XSIZE(thr_wsum_pdf_direction[iclass])");
+											}
+#endif
+
+											// Store weight for this direction of this class
+											if (mymodel.orientational_prior_mode == NOPRIOR)
+											{
+												DIRECT_MULTIDIM_ELEM(thr_wsum_pdf_direction[exp_iclass], idir) += weight;
+											}
+											else
+											{
+												// In the case of orientational priors, get the original number of the direction back
+												long int mydir = sampling.getDirectionNumberAlsoZeroPrior(idir);
+												DIRECT_MULTIDIM_ELEM(thr_wsum_pdf_direction[exp_iclass], mydir) += weight;
+											}
+
+#ifdef TIMING
+											// Only time one thread, as I also only time one MPI process
+											if (thread_id == 0)
+												timer.toc(TIMING_WSUM_DIFF2);
+											// Only time one thread, as I also only time one MPI process
+											if (thread_id == 0)
+												timer.tic(TIMING_WSUM_SUMSHIFT);
+#endif
+
+											// Store sum of weight*SSNR*Fimg in data and sum of weight*SSNR in weight
+											// Use the FT of the unmasked image to back-project in order to prevent reconstruction artefacts! SS 25oct11
+											FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fimg_shift)
+											{
+												double myctf = DIRECT_MULTIDIM_ELEM(Mctf, n);
+												// Note that weightxinvsigma2 already contains the CTF!
+												double weightxinvsigma2 = weight * myctf * DIRECT_MULTIDIM_ELEM(Minvsigma2, n);
+												// now Fimg stores sum of all shifted w*Fimg
+												(DIRECT_MULTIDIM_ELEM(Fimg, n)).real += (DIRECT_MULTIDIM_ELEM(Fimg_shift_nomask, n)).real * weightxinvsigma2;
+												(DIRECT_MULTIDIM_ELEM(Fimg, n)).imag += (DIRECT_MULTIDIM_ELEM(Fimg_shift_nomask, n)).imag * weightxinvsigma2;
+												// now Fweight stores sum of all w
+												// Note that CTF needs to be squared in Fweight, weightxinvsigma2 already contained one copy
+												DIRECT_MULTIDIM_ELEM(Fweight, n) += weightxinvsigma2 * myctf;
+											}
+
+#ifdef TIMING
+											// Only time one thread, as I also only time one MPI process
+											if (thread_id == 0)
+												timer.toc(TIMING_WSUM_SUMSHIFT);
+#endif
+
+										} // end if !do_skip_maximization
+
+										// Keep track of max_weight and the corresponding optimal hidden variables
+										if (weight > thr_max_weight[ipart])
+										{
+											// Store optimal image parameters
+											thr_max_weight[ipart] = weight;
+
+											// Calculate the angles back from the Euler matrix because for tilt series exp_R_mic may have changed them...
+											//std::cerr << " ORI rot= " << rot << " tilt= " << tilt << " psi= " << psi << std::endl;
+											Euler_matrix2angles(A.inv(), rot, tilt, psi);
+											//std::cerr << " BACK rot= " << rot << " tilt= " << tilt << " psi= " << psi << std::endl;
+
+											DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_ROT) = rot;
+											DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_TILT) = tilt;
+											DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_PSI) = psi;
+											DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_XOFF) = XX(exp_old_offset[my_image_no]) + XX(oversampled_translations[iover_trans]);
+											DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_YOFF) = YY(exp_old_offset[my_image_no]) + YY(oversampled_translations[iover_trans]);
+											DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_CLASS) = (double)exp_iclass + 1;
+											DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_PMAX) = thr_max_weight[ipart];
+										}
+
+									} // end if weight >= exp_significant_weight
+								} // end loop iover_trans
+							} // end loop itrans
+						}// end loop part_id (i)
+					} // end loop ori_part_id
+
+					if (!do_skip_maximization)
+					{
+#ifdef TIMING
+						// Only time one thread, as I also only time one MPI process
+						if (thread_id == 0)
+							timer.tic(TIMING_WSUM_BACKPROJ);
+#endif
+						// Perform the actual back-projection.
+						// This is done with the sum of all (in-plane) shifted Fimg's
+						// Perform this inside a mutex
+						global_mutex2.lock();
+						(wsum_model.BPref[exp_iclass]).set2DFourierTransform(Fimg, A, IS_INV, &Fweight);
+						global_mutex2.unlock();
+
+#ifdef TIMING
+						// Only time one thread, as I also only time one MPI process
+						if (thread_id == 0)
+							timer.toc(TIMING_WSUM_BACKPROJ);
+#endif
+					} // end if !do_skip_maximization
+
+				}// end if iover_rot
+			}// end loop do_proceed
+
+		} // end loop ipsi
+	} // end loop idir
+
+	// Now, inside a global_mutex, update the weighted sums among all threads
+	global_mutex.lock();
+
+	if (!do_skip_maximization)
+	{
+		if (do_scale_correction)
+		{
+			for (int n = 0; n < exp_nr_particles; n++)
+			{
+				exp_wsum_scale_correction_XA[n] += thr_wsum_scale_correction_XA[n];
+				exp_wsum_scale_correction_AA[n] += thr_wsum_scale_correction_AA[n];
+			}
+		}
+		for (int n = 0; n < exp_nr_particles; n++)
+		{
+			exp_wsum_norm_correction[n] += thr_wsum_norm_correction[n];
+		}
+		for (int n = 0; n < mymodel.nr_groups; n++)
+		{
+			wsum_model.sigma2_noise[n] += thr_wsum_sigma2_noise[n];
+			wsum_model.sumw_group[n] += thr_sumw_group[n];
+		}
+		for (int n = 0; n < mymodel.nr_classes; n++)
+		{
+			wsum_model.pdf_class[n] += thr_wsum_pdf_class[n];
+
+			if (mymodel.ref_dim == 2)
+			{
+				XX(wsum_model.prior_offset_class[n]) += thr_wsum_prior_offsetx_class[n];
+				YY(wsum_model.prior_offset_class[n]) += thr_wsum_prior_offsety_class[n];
+			}
+#ifdef CHECKSIZES
+			if (XSIZE(wsum_model.pdf_direction[n]) != XSIZE(thr_wsum_pdf_direction[n]))
+			{
+				std::cerr << " XSIZE(wsum_model.pdf_direction[n])= " << XSIZE(wsum_model.pdf_direction[n]) << " XSIZE(thr_wsum_pdf_direction[n])= " << XSIZE(thr_wsum_pdf_direction[n]) << std::endl;
+				REPORT_ERROR("XSIZE(wsum_model.pdf_direction[n]) != XSIZE(thr_wsum_pdf_direction[n])");
+			}
+#endif
+			wsum_model.pdf_direction[n] += thr_wsum_pdf_direction[n];
+		}
+		wsum_model.sigma2_offset += thr_wsum_sigma2_offset;
+	} // end if !do_skip_maximization
+
+	// Check max_weight for each particle and set exp_metadata
+	for (int n = 0; n < exp_nr_particles; n++)
+	{
+		// Equal-to because of the series: the nth images in a series will have the same maximum as the first one
+		if (thr_max_weight[n] >= exp_max_weight[n])
+		{
+			// Set max_weight
+			exp_max_weight[n] = thr_max_weight[n];
+
+			// Set metadata
+			long int my_image_no = exp_starting_image_no[n] + exp_iseries;
+			DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_ROT)  = DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_ROT);
+			DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_TILT) = DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_TILT);
+			DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PSI)  = DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_PSI);
+			DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_XOFF) = DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_XOFF);
+			DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_YOFF) = DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_YOFF);
+			DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CLASS)= DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_CLASS);
+			DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PMAX) = DIRECT_A2D_ELEM(thr_metadata, my_image_no, METADATA_PMAX);
+		}
+	}
+	global_mutex.unlock();
+
+	// Wait until all threads have finished
+	global_barrier->wait();
+#ifdef DEBUG_THREAD
+    std::cerr << "leaving doThreadStoreWeightedSumsAllOrientations" << std::endl;
+#endif
+
+}
+
+void MlOptimiser::storeWeightedSums()
+{
+
+#ifdef TIMING
+	timer.tic(TIMING_ESP_WSUM);
+#endif
+
+	// Initialise the maximum of all weights to a negative value
+	exp_max_weight.resize(exp_nr_particles);
+	for (int n = 0; n < exp_nr_particles; n++)
+		exp_max_weight[n] = -1.;
+
+	// In doThreadPrecalculateShiftedImagesCtfsAndInvSigma2s() the origin of the exp_local_Minvsigma2s was omitted.
+	// Set those back here
+	for (long int ori_part_id = exp_my_first_ori_particle, ipart = 0; ori_part_id <= exp_my_last_ori_particle; ori_part_id++)
+	{
+		// loop over all particles inside this ori_particle
+		for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++, ipart++)
+		{
+			long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+
+			for (exp_iseries = 0; exp_iseries < mydata.getNrImagesInSeries(part_id); exp_iseries++)
+			{
+				// Re-get all shifted versions of the (current_sized) images, their (current_sized) CTFs and their inverted Sigma2 matrices
+				// This may be necessary for when using --strict_highres_exp. Otherwise norm estimation may become unstable!!
+				exp_ipart_ThreadTaskDistributor->reset(); // reset thread distribution tasks
+				global_ThreadManager->run(globalThreadPrecalculateShiftedImagesCtfsAndInvSigma2s);
+
+				int group_id = mydata.getGroupId(part_id, exp_iseries);
+				int my_image_no = exp_starting_image_no[ipart] + exp_iseries;
+				DIRECT_MULTIDIM_ELEM(exp_local_Minvsigma2s[my_image_no], 0) = 1. / (sigma2_fudge * DIRECT_A1D_ELEM(mymodel.sigma2_noise[group_id], 0));
+			}
+		}
+	}
+
+	for (exp_iseries = 0; exp_iseries < mydata.getNrImagesInSeries((mydata.ori_particles[exp_my_first_ori_particle]).particles_id[0]); exp_iseries++)
+	{
+		// TODO: check this!!!
+		// I think this is just done for the first ipart
+		int my_image_no = exp_starting_image_no[0] + exp_iseries;
+		// Get micrograph transformation matrix
+		exp_R_mic.resize(3,3);
+		exp_R_mic(0,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_0);
+		exp_R_mic(0,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_1);
+		exp_R_mic(0,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_2);
+		exp_R_mic(1,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_0);
+		exp_R_mic(1,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_1);
+		exp_R_mic(1,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_2);
+		exp_R_mic(2,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_0);
+		exp_R_mic(2,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_1);
+		exp_R_mic(2,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_2);
+
+		// For norm_correction of this iseries image:
+		exp_wsum_norm_correction.resize(exp_nr_particles);
+		for (int n = 0; n < exp_nr_particles; n++)
+			exp_wsum_norm_correction[n] = 0.;
+
+		// For scale_correction of this iseries image:
+		if (do_scale_correction)
+		{
+			MultidimArray<double> aux;
+			aux.initZeros(mymodel.ori_size/2 + 1);
+			exp_wsum_scale_correction_XA.resize(exp_nr_particles);
+			exp_wsum_scale_correction_AA.resize(exp_nr_particles);
+			for (int n = 0; n < exp_nr_particles; n++)
+			{
+				exp_wsum_scale_correction_XA[n] = aux;
+				exp_wsum_scale_correction_AA[n] = aux;
+			}
+		}
+
+		// Loop from iclass_min to iclass_max to deal with seed generation in first iteration
+		for (exp_iclass = iclass_min; exp_iclass <= iclass_max; exp_iclass++)
+		{
+
+			// The loops over all orientations are parallelised using threads
+			exp_iorient_ThreadTaskDistributor->reset(); // reset thread distribution tasks
+			global_ThreadManager->run(globalThreadStoreWeightedSumsAllOrientations);
+
+		} // end loop iclass
+
+		// Extend norm_correction and sigma2_noise estimation to higher resolutions for all particles
+		for (long int ori_part_id = exp_my_first_ori_particle, ipart = 0; ori_part_id <= exp_my_last_ori_particle; ori_part_id++)
+		{
+			// loop over all particles inside this ori_particle
+			for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++, ipart++)
+			{
+				long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+
+				// Which number was this image in the combined array of exp_iseries and exp_part_id
+				long int my_image_no = exp_starting_image_no[ipart] + exp_iseries;
+
+				// If the current images were smaller than the original size, fill the rest of wsum_model.sigma2_noise with the power_class spectrum of the images
+				int group_id = mydata.getGroupId(part_id, exp_iseries);
+				for (int ires = mymodel.current_size/2 + 1; ires < mymodel.ori_size/2 + 1; ires++)
+				{
+					DIRECT_A1D_ELEM(wsum_model.sigma2_noise[group_id], ires) += DIRECT_A1D_ELEM(exp_power_imgs[my_image_no], ires);
+					// Also extend the weighted sum of the norm_correction
+					exp_wsum_norm_correction[ipart] += DIRECT_A1D_ELEM(exp_power_imgs[my_image_no], ires);
+				}
+
+				// Store norm_correction
+				// Multiply by old value because the old norm_correction term was already applied to the image
+				if (do_norm_correction)
+				{
+					double old_norm_correction = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM);
+					old_norm_correction /= mymodel.avg_norm_correction;
+					// Now set the new norm_correction in the relevant position of exp_metadata
+					// The factor two below is because exp_wsum_norm_correctiom is similar to sigma2_noise, which is the variance for the real/imag components
+					// The variance of the total image (on which one normalizes) is twice this value!
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM) = old_norm_correction * sqrt(exp_wsum_norm_correction[ipart] * 2.);
+					wsum_model.avg_norm_correction += old_norm_correction * sqrt(exp_wsum_norm_correction[ipart] * 2.);
+
+					if (!(iter == 1 && do_firstiter_cc) && DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM) > 10.)
+					{
+						std::cout << " WARNING: norm_correction= "<< DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM) << " for particle " << part_id << " in group " << group_id + 1 << "; Are your groups large enough?" << std::endl;
+						std::cout << " mymodel.current_size= " << mymodel.current_size << " mymodel.ori_size= " << mymodel.ori_size << " part_id= " << part_id << std::endl;
+						std::cout << " coarse_size= " << coarse_size << std::endl;
+						std::cout << " DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM)= " << DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM) << std::endl;
+						std::cout << " mymodel.avg_norm_correction= " << mymodel.avg_norm_correction << std::endl;
+						std::cout << " exp_wsum_norm_correction[ipart]= " << exp_wsum_norm_correction[ipart] << std::endl;
+						std::cout << " old_norm_correction= " << old_norm_correction << std::endl;
+						std::cout << " wsum_model.avg_norm_correction= " << wsum_model.avg_norm_correction << std::endl;
+						std::cout << " group_id= " << group_id << " mymodel.scale_correction[group_id]= " << mymodel.scale_correction[group_id] << std::endl;
+						std::cout << " mymodel.sigma2_noise[group_id]= " << mymodel.sigma2_noise[group_id] << std::endl;
+						std::cout << " wsum_model.sigma2_noise[group_id]= " << wsum_model.sigma2_noise[group_id] << std::endl;
+						std::cout << " exp_power_imgs[my_image_no]= " << exp_power_imgs[my_image_no] << std::endl;
+						std::cout << " exp_wsum_scale_correction_XA[ipart]= " << exp_wsum_scale_correction_XA[ipart] << " exp_wsum_scale_correction_AA[ipart]= " << exp_wsum_scale_correction_AA[ipart] << std::endl;
+						std::cout << " wsum_model.wsum_signal_product_spectra[group_id]= " << wsum_model.wsum_signal_product_spectra[group_id] << " wsum_model.wsum_reference_power_spectra[group_id]= " << wsum_model.wsum_reference_power_spectra[group_id] << std::endl;
+						std::cout << " exp_min_diff2[ipart]= " << exp_min_diff2[ipart] << std::endl;
+						std::cout << " ml_model.scale_correction[group_id]= " << mymodel.scale_correction[group_id] << std::endl;
+						std::cout << " exp_significant_weight[ipart]= " << exp_significant_weight[ipart] << std::endl;
+						std::cout << " exp_max_weight[ipart]= " << exp_max_weight[ipart] << std::endl;
+
+					}
+					//TMP DEBUGGING
+					/*
+					if (!(iter == 1 && do_firstiter_cc) && DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM) > 10.)
+					{
+						std::cerr << " mymodel.current_size= " << mymodel.current_size << " mymodel.ori_size= " << mymodel.ori_size << " part_id= " << part_id << std::endl;
+						std::cerr << " DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM)= " << DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM) << std::endl;
+						std::cerr << " mymodel.avg_norm_correction= " << mymodel.avg_norm_correction << std::endl;
+						std::cerr << " exp_wsum_norm_correction[ipart]= " << exp_wsum_norm_correction[ipart] << std::endl;
+						std::cerr << " old_norm_correction= " << old_norm_correction << std::endl;
+						std::cerr << " wsum_model.avg_norm_correction= " << wsum_model.avg_norm_correction << std::endl;
+						std::cerr << " group_id= " << group_id << " mymodel.scale_correction[group_id]= " << mymodel.scale_correction[group_id] << std::endl;
+						std::cerr << " mymodel.sigma2_noise[group_id]= " << mymodel.sigma2_noise[group_id] << std::endl;
+						std::cerr << " wsum_model.sigma2_noise[group_id]= " << wsum_model.sigma2_noise[group_id] << std::endl;
+						std::cerr << " exp_power_imgs[my_image_no]= " << exp_power_imgs[my_image_no] << std::endl;
+						std::cerr << " exp_wsum_scale_correction_XA[ipart]= " << exp_wsum_scale_correction_XA[ipart] << " exp_wsum_scale_correction_AA[ipart]= " << exp_wsum_scale_correction_AA[ipart] << std::endl;
+						std::cerr << " wsum_model.wsum_signal_product_spectra[group_id]= " << wsum_model.wsum_signal_product_spectra[group_id] << " wsum_model.wsum_reference_power_spectra[group_id]= " << wsum_model.wsum_reference_power_spectra[group_id] << std::endl;
+						std::cerr << " exp_min_diff2[ipart]= " << exp_min_diff2[ipart] << std::endl;
+						std::cerr << " ml_model.scale_correction[group_id]= " << mymodel.scale_correction[group_id] << std::endl;
+						std::cerr << " exp_significant_weight[ipart]= " << exp_significant_weight[ipart] << std::endl;
+						std::cerr << " exp_max_weight[ipart]= " << exp_max_weight[ipart] << std::endl;
+						mymodel.write("debug");
+						std::cerr << "written debug_model.star" << std::endl;
+						REPORT_ERROR("MlOptimiser::storeWeightedSums ERROR: normalization is larger than 10");
+					}
+					*/
+
+				}
+
+				// Store weighted sums for scale_correction
+				if (do_scale_correction)
+				{
+					// Divide XA by the old scale_correction and AA by the square of that, because was incorporated into Fctf
+					exp_wsum_scale_correction_XA[ipart] /= mymodel.scale_correction[group_id];
+					exp_wsum_scale_correction_AA[ipart] /= mymodel.scale_correction[group_id] * mymodel.scale_correction[group_id];
+
+					wsum_model.wsum_signal_product_spectra[group_id] += exp_wsum_scale_correction_XA[ipart];
+					wsum_model.wsum_reference_power_spectra[group_id] += exp_wsum_scale_correction_AA[ipart];
+				}
+
+			} // end loop part_id (i)
+		} // end loop ori_part_id
+	} // end loop exp_iseries
+
+
+#ifdef DEBUG_OVERSAMPLING
+	std::cerr << " max_weight= " << max_weight << " nr_sign_sam= "<<nr_significant_samples<<" sign w= "<<exp_significant_weight<<std::endl;
+#endif
+
+	// Some analytics...
+	// Calculate normalization constant for dLL
+	for (long int ori_part_id = exp_my_first_ori_particle, ipart = 0; ori_part_id <= exp_my_last_ori_particle; ori_part_id++)
+	{
+		// loop over all particles inside this ori_particle
+		for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++, ipart++)
+		{
+			long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+			double logsigma2 = 0.;
+			for (long int iseries = 0; iseries < mydata.getNrImagesInSeries(part_id); iseries++)
+			{
+				int group_id = mydata.getGroupId(part_id, iseries);
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Mresol_fine)
+				{
+					int ires = DIRECT_MULTIDIM_ELEM(Mresol_fine, n);
+					// Note there is no sqrt in the normalisation term because of the 2-dimensionality of the complex-plane
+					// Also exclude origin from logsigma2, as this will not be considered in the P-calculations
+					if (ires > 0)
+						logsigma2 += log( 2. * PI * DIRECT_A1D_ELEM(mymodel.sigma2_noise[group_id], ires));
+				}
+
+			}
+
+			if (exp_sum_weight[ipart]==0)
+			{
+				std::cerr << " part_id= " << part_id << std::endl;
+				std::cerr << " ipart= " << ipart << std::endl;
+				std::cerr << " exp_min_diff2[ipart]= " << exp_min_diff2[ipart] << std::endl;
+				std::cerr << " logsigma2= " << logsigma2 << std::endl;
+				int group_id = mydata.getGroupId(part_id, 0);
+				std::cerr << " group_id= " << group_id << std::endl;
+				std::cerr << " ml_model.scale_correction[group_id]= " << mymodel.scale_correction[group_id] << std::endl;
+				std::cerr << " exp_significant_weight[ipart]= " << exp_significant_weight[ipart] << std::endl;
+				std::cerr << " exp_max_weight[ipart]= " << exp_max_weight[ipart] << std::endl;
+				std::cerr << " ml_model.sigma2_noise[group_id]= " << mymodel.sigma2_noise[group_id] << std::endl;
+				REPORT_ERROR("ERROR: exp_sum_weight[ipart]==0");
+			}
+
+			double dLL;
+
+			if ((iter==1 && do_firstiter_cc) || do_always_cc)
+				dLL = -exp_min_diff2[ipart];
+			else
+				dLL = log(exp_sum_weight[ipart]) - exp_min_diff2[ipart] - logsigma2;
+
+			wsum_model.LL += dLL;
+			wsum_model.ave_Pmax += DIRECT_A2D_ELEM(exp_metadata, exp_starting_image_no[ipart], METADATA_PMAX);
+
+			// Also store dLL of each image in the output array
+			for (long int iseries = 0; iseries < mydata.getNrImagesInSeries(part_id); iseries++)
+			{
+				long int my_image_no = exp_starting_image_no[ipart] + iseries;
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_DLL) = dLL;
+			}
+		} // end loop part_id
+	} // end loop ori_part_id
+#ifdef TIMING
+	timer.toc(TIMING_ESP_WSUM);
+#endif
+
+}
+
+/** Monitor the changes in the optimal translations, orientations and class assignments for some particles */
+void MlOptimiser::monitorHiddenVariableChanges(long int my_first_ori_particle, long int my_last_ori_particle)
+{
+
+	for (long int ori_part_id = my_first_ori_particle, my_image_no = 0; ori_part_id <= my_last_ori_particle; ori_part_id++)
+	{
+
+#ifdef DEBUG_CHECKSIZES
+		if (ori_part_id >= mydata.ori_particles.size())
+		{
+			std::cerr<< "ori_part_id= "<<ori_part_id<<" mydata.ori_particles.size()= "<< mydata.ori_particles.size() <<std::endl;
+			REPORT_ERROR("ori_part_id >= mydata.ori_particles.size()");
+		}
+#endif
+
+		// loop over all particles inside this ori_particle
+		for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++)
+		{
+			long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+			for (int iseries = 0; iseries < mydata.getNrImagesInSeries(part_id); iseries++, my_image_no++)
+			{
+				long int img_id = mydata.getImageId(part_id, iseries);
+
+#ifdef DEBUG_CHECKSIZES
+				if (img_id >= mydata.MDimg.numberOfObjects())
+				{
+					std::cerr<< "img_id= "<<img_id<<" mydata.MDimg.numberOfObjects()= "<< mydata.MDimg.numberOfObjects() <<std::endl;
+					REPORT_ERROR("img_id >= mydata.MDimg.numberOfObjects()");
+				}
+				if (my_image_no >= YSIZE(exp_metadata))
+				{
+					std::cerr<< "my_image_no= "<<my_image_no<<" YSIZE(exp_metadata)= "<< YSIZE(exp_metadata) <<std::endl;
+					REPORT_ERROR("my_image_no >= YSIZE(exp_metadata)");
+				}
+#endif
+
+				// Old optimal parameters
+				double old_rot, old_tilt, old_psi, old_xoff, old_yoff, old_zoff = 0.;
+				int old_iclass;
+				mydata.MDimg.getValue(EMDL_ORIENT_ROT,  old_rot, img_id);
+				mydata.MDimg.getValue(EMDL_ORIENT_TILT, old_tilt, img_id);
+				mydata.MDimg.getValue(EMDL_ORIENT_PSI,  old_psi, img_id);
+				mydata.MDimg.getValue(EMDL_ORIENT_ORIGIN_X, old_xoff, img_id);
+				mydata.MDimg.getValue(EMDL_ORIENT_ORIGIN_Y, old_yoff, img_id);
+				mydata.MDimg.getValue(EMDL_PARTICLE_CLASS, old_iclass, img_id);
+
+				// New optimal parameters
+				double rot = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_ROT);
+				double tilt = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_TILT);
+				double psi = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PSI);
+				double xoff = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_XOFF);
+				double yoff = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_YOFF);
+				double zoff = 0.;
+				int iclass = (int)DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CLASS);
+
+				// Some orientational distance....
+				sum_changes_optimal_orientations += sampling.calculateAngularDistance(rot, tilt, psi, old_rot, old_tilt, old_psi);
+				sum_changes_optimal_offsets += (xoff-old_xoff)*(xoff-old_xoff) + (yoff-old_yoff)*(yoff-old_yoff) + (zoff-old_zoff)*(zoff-old_zoff);
+				if (iclass != old_iclass)
+					sum_changes_optimal_classes += 1.;
+				sum_changes_count += 1.;
+			} // end loop iseries
+		} // end loop part_id (i)
+	} //end loop ori_part_id
+
+
+}
+
+void MlOptimiser::updateOverallChangesInHiddenVariables()
+{
+
+	// Calculate hidden variable changes
+	current_changes_optimal_classes = sum_changes_optimal_classes / sum_changes_count;
+	current_changes_optimal_orientations = sum_changes_optimal_orientations / sum_changes_count;
+	current_changes_optimal_offsets = sqrt(sum_changes_optimal_offsets / (2. * sum_changes_count));
+
+	// Reset the sums
+	sum_changes_optimal_classes = 0.;
+	sum_changes_optimal_orientations = 0.;
+	sum_changes_optimal_offsets = 0.;
+	sum_changes_count = 0.;
+
+	// Update nr_iter_wo_large_hidden_variable_changes if all three assignment types are within 3% of the smallest thus far
+	if (1.03 * current_changes_optimal_classes >= smallest_changes_optimal_classes &&
+		1.03 * current_changes_optimal_offsets >= smallest_changes_optimal_offsets &&
+		1.03 * current_changes_optimal_orientations >= smallest_changes_optimal_orientations)
+		nr_iter_wo_large_hidden_variable_changes++;
+	else
+		nr_iter_wo_large_hidden_variable_changes = 0;
+
+	// Update smallest changes in hidden variables thus far
+	if (current_changes_optimal_classes < smallest_changes_optimal_classes)
+		smallest_changes_optimal_classes = ROUND(current_changes_optimal_classes);
+	if (current_changes_optimal_offsets < smallest_changes_optimal_offsets)
+		smallest_changes_optimal_offsets = current_changes_optimal_offsets;
+	if (current_changes_optimal_orientations < smallest_changes_optimal_orientations)
+		smallest_changes_optimal_orientations = current_changes_optimal_orientations;
+
+
+}
+
+
+void MlOptimiser::calculateExpectedAngularErrors(long int my_first_ori_particle, long int my_last_ori_particle)
+{
+
+	long int n_trials = 0;
+	exp_starting_image_no.clear();
+	exp_nr_images = 0;
+	for (long int ori_part_id = my_first_ori_particle, my_image_no = 0, ipart = 0; ori_part_id <= my_last_ori_particle; ori_part_id++)
+    {
+		for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++, ipart++)
+		{
+			long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+			exp_starting_image_no.push_back(exp_nr_images);
+			exp_nr_images += mydata.getNrImagesInSeries(part_id);
+			n_trials++;
+		}
+    }
+
+	// Set exp_current_image_size to the coarse_size to calculate exepcted angular errors
+	if (strict_highres_exp > 0. && !do_acc_currentsize_despite_highres_exp)
+	{
+		// Use smaller images in both passes and keep a maximum on coarse_size, just like in FREALIGN
+		exp_current_image_size = coarse_size;
+	}
+	else
+	{
+		// Use smaller images in the first pass, but larger ones in the second pass
+		exp_current_image_size = mymodel.current_size;
+	}
+
+	// Separate angular error estimate for each of the classes
+	acc_rot = acc_trans = 999.; // later XMIPP_MIN will be taken to find the best class...
+
+	// P(X | X_1) / P(X | X_2) = exp ( |F_1 - F_2|^2 / (-2 sigma2) )
+	// exp(-4.60517) = 0.01
+	double pvalue = 4.60517;
+
+	std::cout << " Estimating accuracies in the orientational assignment ... " << std::endl;
+	init_progress_bar(n_trials * mymodel.nr_classes);
+	for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+	{
+
+		// Don't do this for (almost) empty classes
+		if (mymodel.pdf_class[iclass] < 0.01)
+		{
+			mymodel.acc_rot[iclass]   = 999.;
+			mymodel.acc_trans[iclass] = 999.;
+			continue;
+		}
+
+		// Initialise the orientability arrays that will be written out in the model.star file
+		// These are for the user's information only: nothing will be actually done with them
+#ifdef DEBUG_CHECKSIZES
+		if (iclass >= (mymodel.orientability_contrib).size())
+		{
+			std::cerr<< "iclass= "<<iclass<<" (mymodel.orientability_contrib).size()= "<< (mymodel.orientability_contrib).size() <<std::endl;
+			REPORT_ERROR("iclass >= (mymodel.orientability_contrib).size()");
+		}
+#endif
+		(mymodel.orientability_contrib)[iclass].initZeros(mymodel.ori_size/2 + 1);
+
+		double acc_rot_class = 0.;
+		double acc_trans_class = 0.;
+		// Particles are already in random order, so just move from 0 to n_trials
+		for (long int ori_part_id = my_first_ori_particle, my_image_no = 0, ipart = 0; ori_part_id <= my_last_ori_particle; ori_part_id++)
+	    {
+			for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++, ipart++)
+			{
+				long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+
+				// Search 2 times: ang and off
+				// Don't estimate rotational accuracies if we're doing do_skip_rotate (for faster movie-frame alignment)
+				int imode_start = (do_skip_rotate) ? 1 : 0;
+				for (int imode = imode_start; imode < 2; imode++)
+				{
+					double ang_error = 0.;
+					double sh_error = 0.;
+					double ang_step;
+					double sh_step;
+					double my_snr = 0.;
+
+					// Search for ang_error and sh_error where there are at least 3-sigma differences!
+					// 13feb12: change for explicit probability at P=0.01
+					while (my_snr <= pvalue)
+					{
+						// Graduallly increase the step size
+						if (ang_error < 0.2)
+							ang_step = 0.05;
+						else if (ang_error < 1.)
+							ang_step = 0.1;
+						else if (ang_error < 2.)
+							ang_step = 0.2;
+						else if (ang_error < 5.)
+							ang_step = 0.5;
+						else if (ang_error < 10.)
+							ang_step = 1.0;
+						else if (ang_error < 20.)
+							ang_step = 2;
+						else
+							ang_step = 5.0;
+
+						if (sh_error < 0.2)
+							sh_step = 0.05;
+						else if (sh_error < 1.)
+							sh_step = 0.1;
+						else if (sh_error < 2.)
+							sh_step = 0.2;
+						else if (sh_error < 5.)
+							sh_step = 0.5;
+						else if (sh_error < 10.)
+							sh_step = 1.0;
+						else
+							sh_step = 2.0;
+
+						ang_error += ang_step;
+						sh_error += sh_step;
+
+						// Prevent an endless while by putting boundaries on ang_error and sh_error
+						if ( (imode == 0 && ang_error > 30.) || (imode == 1 && sh_error > 10.) )
+							break;
+
+						init_random_generator(random_seed + part_id);
+
+						// Loop over all images in the series
+						// TODO: check this for series!!
+						// Initialise the my_snr value (accumulate its sum for all images in the series!!)
+						my_snr = 0.;
+						for (int iseries = 0; iseries < mydata.getNrImagesInSeries(part_id); iseries++)
+						{
+
+							int my_image_no = exp_starting_image_no.at(ipart) + iseries;
+
+							Matrix2D<double> R_mic(3,3);
+							R_mic(0,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_0);
+							R_mic(0,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_1);
+							R_mic(0,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_2);
+							R_mic(1,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_0);
+							R_mic(1,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_1);
+							R_mic(1,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_2);
+							R_mic(2,0) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_0);
+							R_mic(2,1) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_1);
+							R_mic(2,2) = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_2);
+
+							int group_id = mydata.getGroupId(part_id, iseries);
+#ifdef DEBUG_CHECKSIZES
+							if (group_id  >= mymodel.sigma2_noise.size())
+							{
+								std::cerr<< "group_id = "<<group_id <<" mymodel.sigma2_noise.size()= "<< mymodel.sigma2_noise.size() <<std::endl;
+								REPORT_ERROR("group_id  >= mymodel.sigma2_noise.size()");
+							}
+#endif
+							MultidimArray<Complex > F1, F2;
+							MultidimArray<double> Fctf;
+							Matrix2D<double> A1, A2;
+
+
+							// TODO: get values through exp_metadata?!
+							double rot1 = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_ROT);
+							double tilt1 = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_TILT);
+							double psi1 = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PSI);
+							double xoff1 = 0.;
+							double yoff1 = 0.;
+
+							// Get the FT of the first image
+							F1.initZeros(exp_current_image_size, exp_current_image_size/ 2 + 1);
+
+							Euler_angles2matrix(rot1, tilt1, psi1, A1);
+							A1 = R_mic * A1.inv();
+							(mymodel.PPref[iclass]).get2DFourierTransform(F1, A1, IS_INV);
+
+							// Apply the angular or shift error
+							double rot2 = rot1;
+							double tilt2 = tilt1;
+							double psi2 = psi1;
+							Matrix1D<double> shift(2);
+							XX(shift) = xoff1;
+							YY(shift) = yoff1;
+							// Perturb psi or xoff , depending on the mode
+							if (imode == 0)
+							{
+								if (mymodel.ref_dim == 3)
+								{
+									// Randomly change rot, tilt or psi
+									double ran = rnd_unif();
+									if (ran < 0.3333)
+										rot2 = rot1 + ang_error;
+									else if (ran < 0.6667)
+										tilt2 = tilt1 + ang_error;
+									else
+										psi2  = psi1 + ang_error;
+								}
+								else
+								{
+									psi2  = psi1 + ang_error;
+								}
+							}
+							else
+							{
+								// Randomly change xoff or yoff
+								double ran = rnd_unif();
+								if (ran < 0.5)
+									XX(shift) = xoff1 + sh_error;
+								else
+									YY(shift) = yoff1 + sh_error;
+							}
+							// Get the FT of the second image
+							F2.initZeros(exp_current_image_size, exp_current_image_size / 2 + 1);
+							Euler_angles2matrix(rot2, tilt2, psi2, A2);
+							A2 = R_mic * A2.inv();
+							(mymodel.PPref[iclass]).get2DFourierTransform(F2, A2, IS_INV);
+							if (ABS(XX(shift)) > 0. || ABS(YY(shift)) > 0.)
+								// shiftImageInFourierTransform takes shifts in pixels!
+								shiftImageInFourierTransform(F2, F2, (double) mymodel.ori_size, -shift);
+
+							// Apply CTF to F1 and F2 if necessary
+							if (do_ctf_correction)
+							{
+								CTF ctf;
+
+								ctf.setValues(DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_DEFOCUS_U),
+											  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_DEFOCUS_V),
+											  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_DEFOCUS_ANGLE),
+											  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_VOLTAGE),
+											  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_CS),
+											  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_Q0),
+											  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_BFAC));
+
+								Fctf.resize(F1);
+								ctf.getFftwImage(Fctf, mymodel.ori_size, mymodel.ori_size, mymodel.pixel_size, ctf_phase_flipped, only_flip_phases, intact_ctf_first_peak, true);
+#ifdef DEBUG_CHECKSIZES
+								if (!Fctf.sameShape(F1) || !Fctf.sameShape(F2))
+								{
+									std::cerr<<" Fctf: "; Fctf.printShape(std::cerr);
+									std::cerr<<" F1:   "; F1.printShape(std::cerr);
+									std::cerr<<" F2:   "; F2.printShape(std::cerr);
+									REPORT_ERROR("ERROR: Fctf has a different shape from F1 and F2");
+								}
+#endif
+								FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(F1)
+								{
+									DIRECT_MULTIDIM_ELEM(F1, n) *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+									DIRECT_MULTIDIM_ELEM(F2, n) *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+								}
+							}
+
+							MultidimArray<int> * myMresol = (YSIZE(F1) == coarse_size) ? &Mresol_coarse : &Mresol_fine;
+							FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(F1)
+							{
+								int ires = DIRECT_MULTIDIM_ELEM(*myMresol, n);
+								if (ires > 0)
+								{
+									my_snr += norm(DIRECT_MULTIDIM_ELEM(F1, n) - DIRECT_MULTIDIM_ELEM(F2, n)) / (2 * sigma2_fudge * mymodel.sigma2_noise[group_id](ires));
+								}
+							}
+
+							// Only for the psi-angle and the translations, and only when my_prob < 0.01 calculate a histogram of the contributions at each resolution shell
+							if (my_snr > pvalue && imode == 0)
+							{
+								FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(F1)
+								{
+									int ires = DIRECT_MULTIDIM_ELEM(*myMresol, n);
+									if (ires > 0)
+										mymodel.orientability_contrib[iclass](ires) +=
+												norm(DIRECT_MULTIDIM_ELEM(F1, n) - DIRECT_MULTIDIM_ELEM(F2, n)) / ( (2 * sigma2_fudge * mymodel.sigma2_noise[group_id](ires)) );
+								}
+
+							}
+
+						} // end for iseries
+
+					} // end while my_snr >= pvalue
+					if (imode == 0)
+						acc_rot_class += ang_error;
+					else if (imode == 1)
+						acc_trans_class += sh_error;
+				} // end for imode
+
+			}// end for part_id
+
+			progress_bar(n_trials*iclass + ipart);
+		} // end for ori_part_id
+
+		mymodel.acc_rot[iclass]   = acc_rot_class / (double)n_trials;
+		mymodel.acc_trans[iclass] = acc_trans_class / (double)n_trials;
+
+		// Store normalised spectral contributions to orientability
+		if (mymodel.orientability_contrib[iclass].sum() > 0.)
+			mymodel.orientability_contrib[iclass]   /= mymodel.orientability_contrib[iclass].sum();
+
+		// Keep the orientational accuracy of the best class for the auto-sampling approach
+		acc_rot     = XMIPP_MIN(mymodel.acc_rot[iclass], acc_rot);
+		acc_trans   = XMIPP_MIN(mymodel.acc_trans[iclass], acc_trans);
+
+
+		// Richard's formula with Greg's constant
+		//double b_orient = (acc_rot_class*acc_rot_class* particle_diameter*particle_diameter) / 3000.;
+		//std::cout << " + expected B-factor from the orientational errors = "
+		//		<< b_orient<<std::endl;
+		// B=8 PI^2 U^2
+		//std::cout << " + expected B-factor from the translational errors = "
+		//		<< 8 * PI * PI * mymodel.pixel_size * mymodel.pixel_size * acc_trans_class * acc_trans_class << std::endl;
+
+	} // end loop iclass
+	progress_bar(n_trials * mymodel.nr_classes);
+
+
+	std::cout << " Auto-refine: Estimated accuracy angles= " << acc_rot<< " degrees; offsets= " << acc_trans << " pixels" << std::endl;
+	// Warn for inflated resolution estimates
+	if (acc_rot > 10.)
+	{
+		std::cout << " Auto-refine: WARNING: The angular accuracy is worse than 10 degrees, so basically you cannot align your particles (yet)!" << std::endl;
+		std::cout << " Auto-refine: WARNING: You probably need not worry if the accuracy improves during the next few iterations." << std::endl;
+		std::cout << " Auto-refine: WARNING: However, if the problem persists it may lead to spurious FSC curves, so be wary of inflated resolution estimates..." << std::endl;
+		std::cout << " Auto-refine: WARNING: Sometimes it is better to tune resolution yourself by adjusting T in a 3D-classification with a single class." << std::endl;
+	}
+
+}
+
+void MlOptimiser::updateAngularSampling(bool verb)
+{
+
+	if (!do_split_random_halves)
+		REPORT_ERROR("MlOptimiser::updateAngularSampling: BUG! updating of angular sampling should only happen for gold-standard (auto-) refinements.");
+
+	if (do_realign_movies)
+	{
+
+		// A. Adjust translational sampling to 75% of estimated accuracy
+		double new_step = XMIPP_MIN(1.5, 0.75 * acc_trans) * std::pow(2., adaptive_oversampling);
+
+		// Search ranges are three times the estimates std.dev. in the offsets
+		double new_range = 3. * sqrt(mymodel.sigma2_offset);
+
+		// Prevent too narrow searches: always at least 3x3 pixels in the coarse search
+		if (new_range < 1.5 * new_step)
+			new_range = 1.5 * new_step;
+
+		// Also prevent too wide searches: that will lead to memory problems:
+		// Just use coarser step size and hope things will settle down later...
+		if (new_range > 4. * new_step)
+			new_step = new_range / 4.;
+
+		sampling.setTranslations(new_step, new_range);
+
+		if (!do_skip_rotate)
+		{
+			// B. Find the healpix order that corresponds to at least 50% of the estimated rotational accuracy
+			double angle_range = sqrt(mymodel.sigma2_rot) * 3.;
+			double new_ang_step, new_ang_step_wo_over;
+			int new_hp_order;
+			for (new_hp_order = 0; new_hp_order < 8; new_hp_order++)
+			{
+
+				new_ang_step = 360. / (6 * ROUND(std::pow(2., new_hp_order + adaptive_oversampling)));
+				new_ang_step_wo_over = 2. * new_ang_step;
+				// Only consider healpix orders that gives at least more than one (non-oversampled) samplings within the local angular searches
+				if (new_ang_step_wo_over > angle_range)
+					continue;
+				// If sampling is at least twice as fine as the estimated rotational accuracy, then use this sampling
+				if (new_ang_step < 0.50 * acc_rot)
+					break;
+			}
+
+			if (new_hp_order != sampling.healpix_order)
+			{
+				// Set the new sampling in the sampling-object
+				sampling.setOrientations(new_hp_order, new_ang_step * std::pow(2., adaptive_oversampling));
+				// Resize the pdf_direction arrays to the correct size and fill with an even distribution
+				mymodel.initialisePdfDirection(sampling.NrDirections(0, true));
+				// Also reset the nr_directions in wsum_model
+				wsum_model.nr_directions = mymodel.nr_directions;
+				// Also resize and initialise wsum_model.pdf_direction for each class!
+				for (int iclass=0; iclass < mymodel.nr_classes; iclass++)
+					wsum_model.pdf_direction[iclass].initZeros(mymodel.nr_directions);
+			}
+		}
+	}
+	else
+	{
+
+		if (do_skip_rotate)
+			REPORT_ERROR("ERROR: --skip_rotate can only be used in classification or in movie-frame refinement ...");
+
+		// Only change the sampling if the resolution has not improved during the last 2 iterations
+		// AND the hidden variables have not changed during the last 2 iterations
+		double old_rottilt_step = sampling.getAngularSampling(adaptive_oversampling);
+
+		// Only use a finer angular sampling is the angular accuracy is still above 75% of the estimated accuracy
+		// If it is already below, nothing will change and eventually nr_iter_wo_resol_gain or nr_iter_wo_large_hidden_variable_changes will go above MAX_NR_ITER_WO_RESOL_GAIN
+		if (nr_iter_wo_resol_gain >= MAX_NR_ITER_WO_RESOL_GAIN && nr_iter_wo_large_hidden_variable_changes >= MAX_NR_ITER_WO_LARGE_HIDDEN_VARIABLE_CHANGES)
+		{
+			// Old rottilt step is already below 75% of estimated accuracy: have to stop refinement
+			if (old_rottilt_step < 0.75 * acc_rot)
+			{
+				// don't change angular sampling, as it is already fine enough
+				has_fine_enough_angular_sampling = true;
+
+			}
+			else
+			{
+				has_fine_enough_angular_sampling = false;
+
+				// A. Use translational sampling as suggested by acc_trans
+
+				// Prevent very coarse translational samplings: max 1.5
+				// Also stay a bit on the safe side with the translational sampling: 75% of estimated accuracy
+				double new_step = XMIPP_MIN(1.5, 0.75 * acc_trans) * std::pow(2., adaptive_oversampling);
+				// Search ranges are five times the last observed changes in offsets
+				double new_range = 5. * current_changes_optimal_offsets;
+				// New range can only become 30% bigger than the previous range (to prevent very slow iterations in the beginning)
+				new_range = XMIPP_MIN(1.3*sampling.offset_range, new_range);
+				// Prevent too narrow searches: always at least 3x3 pixels in the coarse search
+				if (new_range < 1.5 * new_step)
+					new_range = 1.5 * new_step;
+				// Also prevent too wide searches: that will lead to memory problems:
+				// If steps size < 1/4th of search range, then decrease search range by 50%
+				if (new_range > 4. * new_step)
+					new_range /= 2.;
+				//If even that was not enough: use coarser step size and hope things will settle down later...
+				if (new_range > 4. * new_step)
+					new_step = new_range / 4.;
+				sampling.setTranslations(new_step, new_range);
+
+				// B. Use twice as fine angular sampling
+				int new_hp_order;
+				double new_rottilt_step, new_psi_step;
+				if (mymodel.ref_dim == 3)
+				{
+					new_hp_order = sampling.healpix_order + 1;
+					new_rottilt_step = new_psi_step = 360. / (6 * ROUND(std::pow(2., new_hp_order + adaptive_oversampling)));
+				}
+				else if (mymodel.ref_dim == 2)
+				{
+					new_hp_order = sampling.healpix_order;
+					new_psi_step = sampling.getAngularSampling() / 2.;
+				}
+				else
+					REPORT_ERROR("MlOptimiser::autoAdjustAngularSampling BUG: ref_dim should be two or three");
+
+				// Set the new sampling in the sampling-object
+				sampling.setOrientations(new_hp_order, new_psi_step * std::pow(2., adaptive_oversampling));
+
+				// Resize the pdf_direction arrays to the correct size and fill with an even distribution
+				mymodel.initialisePdfDirection(sampling.NrDirections(0, true));
+
+				// Also reset the nr_directions in wsum_model
+				wsum_model.nr_directions = mymodel.nr_directions;
+
+				// Also resize and initialise wsum_model.pdf_direction for each class!
+				for (int iclass=0; iclass < mymodel.nr_classes; iclass++)
+					wsum_model.pdf_direction[iclass].initZeros(mymodel.nr_directions);
+
+				// Reset iteration counters
+				nr_iter_wo_resol_gain = 0;
+				nr_iter_wo_large_hidden_variable_changes = 0;
+
+				// Reset smallest changes hidden variables
+				smallest_changes_optimal_classes = 9999999;
+				smallest_changes_optimal_offsets = 999.;
+				smallest_changes_optimal_orientations = 999.;
+
+				// If the angular sampling is smaller than autosampling_hporder_local_searches, then use local searches of +/- 6 times the angular sampling
+				if (new_hp_order >= autosampling_hporder_local_searches)
+				{
+					// Switch ON local angular searches
+					mymodel.orientational_prior_mode = PRIOR_ROTTILT_PSI;
+					sampling.orientational_prior_mode = PRIOR_ROTTILT_PSI;
+					mymodel.sigma2_rot = mymodel.sigma2_tilt = mymodel.sigma2_psi = 2. * 2. * new_rottilt_step * new_rottilt_step;
+					nr_pool = max_nr_pool = 1;
+				}
+
+			}
+
+		}
+	}
+
+	// Print to screen
+	if (verb)
+	{
+		std::cout << " Auto-refine: Angular step= " << sampling.getAngularSampling(adaptive_oversampling) << " degrees; local searches= ";
+		if (sampling.orientational_prior_mode == NOPRIOR)
+			std:: cout << "false" << std::endl;
+		else
+			std:: cout << "true" << std::endl;
+		std::cout << " Auto-refine: Offset search range= " << sampling.offset_range << " pixels; offset step= " << sampling.getTranslationalSampling(adaptive_oversampling) << " pixels"<<std::endl;
+	}
+
+}
+
+void MlOptimiser::checkConvergence()
+{
+
+	if (do_realign_movies)
+	{
+		// only resolution needs to be stuck
+		// Since there does not seem to be any improvement (and sometimes even the opposite)
+		// of performing more than one iteration with the movie frames, just perform a single iteration
+		//if (nr_iter_wo_resol_gain >= MAX_NR_ITER_WO_RESOL_GAIN)
+		//{
+		//	has_converged = true;
+		//	do_join_random_halves = true;
+		//	// movies were already use all data until Nyquist
+		//}
+	}
+	else
+	{
+		has_converged = false;
+		if ( has_fine_enough_angular_sampling && nr_iter_wo_resol_gain >= MAX_NR_ITER_WO_RESOL_GAIN && nr_iter_wo_large_hidden_variable_changes >= MAX_NR_ITER_WO_LARGE_HIDDEN_VARIABLE_CHANGES )
+		{
+			has_converged = true;
+			do_join_random_halves = true;
+			// In the last iteration, include all data until Nyquist
+			do_use_all_data = true;
+		}
+	}
+
+}
+
+void MlOptimiser::printConvergenceStats()
+{
+
+	std::cout << " Auto-refine: Iteration= "<< iter<< std::endl;
+	std::cout << " Auto-refine: Resolution= "<< 1./mymodel.current_resolution<< " (no gain for " << nr_iter_wo_resol_gain << " iter) "<< std::endl;
+	std::cout << " Auto-refine: Changes in angles= " << current_changes_optimal_orientations << " degrees; and in offsets= " << current_changes_optimal_offsets
+			<< " pixels (no gain for " << nr_iter_wo_large_hidden_variable_changes << " iter) "<< std::endl;
+
+	if (has_converged)
+	{
+		std::cout << " Auto-refine: Refinement has converged, entering last iteration where two halves will be combined..."<<std::endl;
+		if (!do_realign_movies)
+			std::cout << " Auto-refine: The last iteration will use data to Nyquist frequency, which may take more CPU and RAM."<<std::endl;
+	}
+
+}
+
+void MlOptimiser::setMetaDataSubset(int first_ori_particle_id, int last_ori_particle_id)
+{
+
+	for (long int ori_part_id = first_ori_particle_id, my_image_no = 0; ori_part_id <= last_ori_particle_id; ori_part_id++)
+    {
+
+#ifdef DEBUG_CHECKSIZES
+		if (ori_part_id >= mydata.ori_particles.size())
+		{
+			std::cerr<< "ori_part_id= "<<ori_part_id<<" mydata.ori_particles.size()= "<< mydata.ori_particles.size() <<std::endl;
+			REPORT_ERROR("ori_part_id >= mydata.ori_particles.size()");
+		}
+#endif
+
+		for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++)
+		{
+			long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+
+			for (int iseries = 0; iseries < mydata.getNrImagesInSeries(part_id); iseries++, my_image_no++)
+			{
+
+				long int img_id = mydata.getImageId(part_id, iseries);
+
+#ifdef DEBUG_CHECKSIZES
+				if (img_id >= mydata.MDimg.numberOfObjects())
+				{
+					std::cerr<< "img_id= "<<img_id<<" mydata.MDimg.numberOfObjects()= "<< mydata.MDimg.numberOfObjects() <<std::endl;
+					REPORT_ERROR("img_id >= mydata.MDimg.numberOfObjects()");
+				}
+				if (my_image_no >= YSIZE(exp_metadata))
+				{
+					std::cerr<< "my_image_no= "<<my_image_no<<" YSIZE(exp_metadata)= "<< YSIZE(exp_metadata) <<std::endl;
+					REPORT_ERROR("my_image_no >= YSIZE(exp_metadata)");
+				}
+#endif
+				mydata.MDimg.setValue(EMDL_ORIENT_ROT,  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_ROT), img_id);
+				mydata.MDimg.setValue(EMDL_ORIENT_TILT, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_TILT), img_id);
+				mydata.MDimg.setValue(EMDL_ORIENT_PSI,  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PSI), img_id);
+				mydata.MDimg.setValue(EMDL_ORIENT_ORIGIN_X, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_XOFF), img_id);
+				mydata.MDimg.setValue(EMDL_ORIENT_ORIGIN_Y, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_YOFF), img_id);
+				mydata.MDimg.setValue(EMDL_PARTICLE_CLASS, (int)DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CLASS) , img_id);
+				mydata.MDimg.setValue(EMDL_PARTICLE_DLL,  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_DLL), img_id);
+				mydata.MDimg.setValue(EMDL_PARTICLE_PMAX, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PMAX), img_id);
+				mydata.MDimg.setValue(EMDL_PARTICLE_NR_SIGNIFICANT_SAMPLES,(int)DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NR_SIGN), img_id);
+				mydata.MDimg.setValue(EMDL_IMAGE_NORM_CORRECTION, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM), img_id);
+
+				// For the moment, CTF, prior and transformation matrix info is NOT updated...
+				double prior_x = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_XOFF_PRIOR);
+				double prior_y = DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_YOFF_PRIOR);
+				if (prior_x < 999.)
+					mydata.MDimg.setValue(EMDL_ORIENT_ORIGIN_X_PRIOR, prior_x, img_id);
+				if (prior_y < 999.)
+					mydata.MDimg.setValue(EMDL_ORIENT_ORIGIN_Y_PRIOR, prior_y, img_id);
+			}
+		}
+	}
+
+}
+
+void MlOptimiser::getMetaAndImageDataSubset(int first_ori_particle_id, int last_ori_particle_id, bool do_also_imagedata)
+{
+
+	int nr_images = 0;
+	for (long int ori_part_id = first_ori_particle_id; ori_part_id <= last_ori_particle_id; ori_part_id++)
+	{
+
+#ifdef DEBUG_CHECKSIZES
+		if (ori_part_id >= mydata.ori_particles.size())
+		{
+			std::cerr<< "ori_part_id= "<<ori_part_id<<" mydata.ori_particles.size()= "<< mydata.ori_particles.size() <<std::endl;
+			REPORT_ERROR("ori_part_id >= mydata.ori_particles.size()");
+		}
+#endif
+
+		for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++)
+		{
+			long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+			nr_images += mydata.getNrImagesInSeries(part_id);
+		}
+	}
+
+	exp_metadata.initZeros(nr_images, METADATA_LINE_LENGTH);
+	if (has_converged && do_use_reconstruct_images)
+		exp_imagedata.resize(2*nr_images, mymodel.ori_size, mymodel.ori_size);
+	else
+		exp_imagedata.resize(nr_images, mymodel.ori_size, mymodel.ori_size);
+
+	for (long int ori_part_id = first_ori_particle_id, my_image_no = 0; ori_part_id <= last_ori_particle_id; ori_part_id++)
+    {
+		for (long int i = 0; i < mydata.ori_particles[ori_part_id].particles_id.size(); i++)
+		{
+			long int part_id = mydata.ori_particles[ori_part_id].particles_id[i];
+			for (int iseries = 0; iseries < mydata.getNrImagesInSeries(part_id); iseries++, my_image_no++)
+			{
+				long int img_id = mydata.getImageId(part_id, iseries);
+
+#ifdef DEBUG_CHECKSIZES
+				if (img_id >= mydata.MDimg.numberOfObjects())
+				{
+					std::cerr<< "img_id= "<<img_id<<" mydata.MDimg.numberOfObjects()= "<< mydata.MDimg.numberOfObjects() <<std::endl;
+					REPORT_ERROR("img_id >= mydata.MDimg.numberOfObjects()");
+				}
+				if (my_image_no >= YSIZE(exp_metadata))
+				{
+					std::cerr<< "my_image_no= "<<my_image_no<<" YSIZE(exp_metadata)= "<< YSIZE(exp_metadata) <<std::endl;
+					REPORT_ERROR("my_image_no >= YSIZE(exp_metadata)");
+				}
+				if (my_image_no >= nr_images)
+				{
+					std::cerr<< "my_image_no= "<<my_image_no<<" nr_images= "<< nr_images <<std::endl;
+					REPORT_ERROR("my_image_no >= nr_images");
+				}
+#endif
+				// First read the image from disc
+				FileName fn_img, fn_rec_img;
+				mydata.MDimg.getValue(EMDL_IMAGE_NAME, fn_img, img_id);
+				Image<double> img, rec_img;
+				img.read(fn_img);
+				if (XSIZE(img()) != XSIZE(exp_imagedata) || YSIZE(img()) != YSIZE(exp_imagedata) )
+				{
+					std::cerr << " fn_img= " << fn_img << " XSIZE(img())= " << XSIZE(img()) << " YSIZE(img())= " << YSIZE(img()) << std::endl;
+					REPORT_ERROR("MlOptimiser::getMetaAndImageDataSubset ERROR: incorrect image size");
+				}
+				if (has_converged && do_use_reconstruct_images)
+				{
+					mydata.MDimg.getValue(EMDL_IMAGE_RECONSTRUCT_NAME, fn_rec_img, img_id);
+					rec_img.read(fn_rec_img);
+					if (XSIZE(rec_img()) != XSIZE(exp_imagedata) || YSIZE(rec_img()) != YSIZE(exp_imagedata) )
+					{
+						std::cerr << " fn_rec_img= " << fn_rec_img << " XSIZE(rec_img())= " << XSIZE(rec_img()) << " YSIZE(rec_img())= " << YSIZE(rec_img()) << std::endl;
+						REPORT_ERROR("MlOptimiser::getMetaAndImageDataSubset ERROR: incorrect reconstruct_image size");
+					}
+				}
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(img())
+				{
+					DIRECT_A3D_ELEM(exp_imagedata, my_image_no, i, j) = DIRECT_A2D_ELEM(img(), i, j);
+				}
+
+				if (has_converged && do_use_reconstruct_images)
+				{
+					FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(rec_img())
+					{
+						DIRECT_A3D_ELEM(exp_imagedata, nr_images + my_image_no, i, j) = DIRECT_A2D_ELEM(rec_img(), i, j);
+					}
+				}
+
+				// Now get the metadata
+				int iaux;
+				mydata.MDimg.getValue(EMDL_ORIENT_ROT,  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_ROT), img_id);
+				mydata.MDimg.getValue(EMDL_ORIENT_TILT, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_TILT), img_id);
+				mydata.MDimg.getValue(EMDL_ORIENT_PSI,  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PSI), img_id);
+				mydata.MDimg.getValue(EMDL_ORIENT_ORIGIN_X, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_XOFF), img_id);
+				mydata.MDimg.getValue(EMDL_ORIENT_ORIGIN_Y, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_YOFF), img_id);
+				mydata.MDimg.getValue(EMDL_PARTICLE_CLASS, iaux, img_id);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CLASS) = (double)iaux;
+				mydata.MDimg.getValue(EMDL_PARTICLE_DLL,  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_DLL), img_id);
+				mydata.MDimg.getValue(EMDL_PARTICLE_PMAX, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PMAX), img_id);
+				mydata.MDimg.getValue(EMDL_PARTICLE_NR_SIGNIFICANT_SAMPLES, iaux, img_id);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NR_SIGN) = (double)iaux;
+				if (!mydata.MDimg.getValue(EMDL_IMAGE_NORM_CORRECTION, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM), img_id))
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_NORM) = 1.;
+				if (do_ctf_correction)
+				{
+					long int mic_id = mydata.getMicrographId(part_id, iseries);
+					double kV, DeltafU, DeltafV, azimuthal_angle, Cs, Bfac, Q0;
+					if (!mydata.MDimg.getValue(EMDL_CTF_VOLTAGE, kV, img_id))
+						if (!mydata.MDmic.getValue(EMDL_CTF_VOLTAGE, kV, mic_id))
+							kV=200;
+
+					if (!mydata.MDimg.getValue(EMDL_CTF_DEFOCUSU, DeltafU, img_id))
+						if (!mydata.MDmic.getValue(EMDL_CTF_DEFOCUSU, DeltafU, mic_id))
+							DeltafU=0;
+
+					if (!mydata.MDimg.getValue(EMDL_CTF_DEFOCUSV, DeltafV, img_id))
+						if (!mydata.MDmic.getValue(EMDL_CTF_DEFOCUSV, DeltafV, mic_id))
+							DeltafV=DeltafU;
+
+					if (!mydata.MDimg.getValue(EMDL_CTF_DEFOCUS_ANGLE, azimuthal_angle, img_id))
+						if (!mydata.MDmic.getValue(EMDL_CTF_DEFOCUS_ANGLE, azimuthal_angle, mic_id))
+							azimuthal_angle=0;
+
+					if (!mydata.MDimg.getValue(EMDL_CTF_CS, Cs, img_id))
+						if (!mydata.MDmic.getValue(EMDL_CTF_CS, Cs, mic_id))
+							Cs=0;
+
+					if (!mydata.MDimg.getValue(EMDL_CTF_BFACTOR, Bfac, img_id))
+						if (!mydata.MDmic.getValue(EMDL_CTF_BFACTOR, Bfac, mic_id))
+							Bfac=0;
+
+					if (!mydata.MDimg.getValue(EMDL_CTF_Q0, Q0, img_id))
+						if (!mydata.MDmic.getValue(EMDL_CTF_Q0, Q0, mic_id))
+							Q0=0;
+
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_VOLTAGE) = kV;
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_DEFOCUS_U) = DeltafU;
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_DEFOCUS_V) = DeltafV;
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_DEFOCUS_ANGLE) = azimuthal_angle;
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_CS) = Cs;
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_BFAC) = Bfac;
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_CTF_Q0) = Q0;
+
+				}
+
+				// beamtilt
+				double beamtilt_x = 0., beamtilt_y = 0.;
+				if (mydata.MDimg.containsLabel(EMDL_IMAGE_BEAMTILT_X))
+					mydata.MDimg.getValue(EMDL_IMAGE_BEAMTILT_X, beamtilt_x, img_id);
+				if (mydata.MDimg.containsLabel(EMDL_IMAGE_BEAMTILT_Y))
+					mydata.MDimg.getValue(EMDL_IMAGE_BEAMTILT_Y, beamtilt_y, img_id);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_BEAMTILT_X) = beamtilt_x;
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_BEAMTILT_Y) = beamtilt_y;
+
+				// If the priors are NOT set, then set their values to 999.
+				if (!mydata.MDimg.getValue(EMDL_ORIENT_ROT_PRIOR,  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_ROT_PRIOR), img_id))
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_ROT_PRIOR) = 999.;
+				if (!mydata.MDimg.getValue(EMDL_ORIENT_TILT_PRIOR, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_TILT_PRIOR), img_id))
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_TILT_PRIOR) = 999.;
+				if (!mydata.MDimg.getValue(EMDL_ORIENT_PSI_PRIOR,  DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PSI_PRIOR), img_id))
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_PSI_PRIOR) = 999.;
+				if (!mydata.MDimg.getValue(EMDL_ORIENT_ORIGIN_X_PRIOR, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_XOFF_PRIOR), img_id))
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_XOFF_PRIOR) = 999.;
+				if (!mydata.MDimg.getValue(EMDL_ORIENT_ORIGIN_Y_PRIOR, DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_YOFF_PRIOR), img_id))
+					DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_YOFF_PRIOR) = 999.;
+
+				// Pass the transformation matrix (even if it is the Identity matrix...
+				Matrix2D<double> R_mic;
+				R_mic = mydata.getMicrographTransformationMatrix(part_id, iseries);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_0) = R_mic(0,0);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_1) = R_mic(0,1);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_0_2) = R_mic(0,2);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_0) = R_mic(1,0);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_1) = R_mic(1,1);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_1_2) = R_mic(1,2);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_0) = R_mic(2,0);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_1) = R_mic(2,1);
+				DIRECT_A2D_ELEM(exp_metadata, my_image_no, METADATA_MAT_2_2) = R_mic(2,2);
+
+			}
+		}
+    }
+
+}
+
diff --git a/src/ml_optimiser.h b/src/ml_optimiser.h
new file mode 100644
index 0000000..af6e62a
--- /dev/null
+++ b/src/ml_optimiser.h
@@ -0,0 +1,631 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef ML_OPTIMISER_H_
+#define ML_OPTIMISER_H_
+
+#include "src/ml_model.h"
+#include "src/parallel.h"
+#include "src/exp_model.h"
+#include "src/ctf.h"
+#include "src/time.h"
+#include "src/mask.h"
+#include "src/healpix_sampling.h"
+
+#define ML_SIGNIFICANT_WEIGHT 1.e-8
+#define METADATA_LINE_LENGTH METADATA_LINE_LENGTH_ALL
+
+#define METADATA_LINE_LENGTH_NOCTF 11
+#define METADATA_LINE_LENGTH_NOPRIOR 18
+#define METADATA_LINE_LENGTH_NOTILT 26
+#define METADATA_LINE_LENGTH_ALL 35
+
+#define METADATA_ROT 0
+#define METADATA_TILT 1
+#define METADATA_PSI 2
+#define METADATA_XOFF 3
+#define METADATA_YOFF 4
+#define METADATA_ZOFF 5
+#define METADATA_CLASS 6
+#define METADATA_DLL 7
+#define METADATA_PMAX 8
+#define METADATA_NR_SIGN 9
+#define METADATA_NORM 10
+
+#define METADATA_CTF_DEFOCUS_U 11
+#define METADATA_CTF_DEFOCUS_V 12
+#define METADATA_CTF_DEFOCUS_ANGLE 13
+#define METADATA_CTF_VOLTAGE 14
+#define METADATA_CTF_Q0 15
+#define METADATA_CTF_CS 16
+#define METADATA_CTF_BFAC 17
+
+#define METADATA_ROT_PRIOR 18
+#define METADATA_TILT_PRIOR 19
+#define METADATA_PSI_PRIOR 20
+#define METADATA_XOFF_PRIOR 21
+#define METADATA_YOFF_PRIOR 22
+#define METADATA_ZOFF_PRIOR 23
+
+#define METADATA_BEAMTILT_X 24
+#define METADATA_BEAMTILT_Y 25
+
+#define METADATA_MAT_0_0 26
+#define METADATA_MAT_0_1 27
+#define METADATA_MAT_0_2 28
+#define METADATA_MAT_1_0 29
+#define METADATA_MAT_1_1 30
+#define METADATA_MAT_1_2 31
+#define METADATA_MAT_2_0 32
+#define METADATA_MAT_2_1 33
+#define METADATA_MAT_2_2 34
+
+#define DO_WRITE_DATA true
+#define DONT_WRITE_DATA false
+#define DO_WRITE_SAMPLING true
+#define DONT_WRITE_SAMPLING false
+#define DO_WRITE_MODEL true
+#define DONT_WRITE_MODEL false
+#define DO_WRITE_OPTIMISER true
+#define DONT_WRITE_OPTIMISER false
+
+#define WIDTH_FMASK_EDGE 2.
+#define MAX_NR_ITER_WO_RESOL_GAIN 1
+#define MAX_NR_ITER_WO_LARGE_HIDDEN_VARIABLE_CHANGES 1
+
+// for profiling
+//#define TIMING
+
+class MlOptimiser;
+
+class MlOptimiser
+{
+public:
+
+	// I/O Parser
+	IOParser parser;
+
+	// Experimental metadata model
+	Experiment mydata;
+
+	// Current ML model
+	MlModel mymodel;
+
+	// Current weighted sums
+	MlWsumModel wsum_model;
+
+	// HEALPix sampling object for coarse sampling
+	HealpixSampling sampling;
+
+	// Filename for the experimental images
+	FileName fn_data;
+
+	// Output root filename
+	FileName fn_out;
+
+	// Filename for input reference images (stack, star or image)
+	FileName fn_ref;
+
+	// Filename for input tau2-spectrum
+	FileName fn_tau;
+
+	// Flag to keep tau-spectrum constant
+	bool fix_tau;
+
+    // some parameters for debugging
+	double debug1, debug2;
+
+	// Starting and finishing particles (for parallelisation)
+    long int my_first_ori_particle_id, my_last_ori_particle_id;
+
+	// Total number iterations and current iteration
+	int iter, nr_iter;
+
+	// Flag whether to split data from the beginning into two random halves
+	bool do_split_random_halves;
+
+	// resolution (in Angstrom) to join the two random halves
+	double low_resol_join_halves;
+
+	// Flag to join random halves again
+	bool do_join_random_halves;
+
+	// Flag to always join random halves, this is a developmental option for testing of sub-optimal FSC-usage only!
+	bool do_always_join_random_halves;
+
+	// Flag whether to use different images for recnostruction and alignment
+	bool do_use_reconstruct_images;
+
+	// Flag whether to do CTF correction
+	bool do_ctf_correction;
+
+	// Do not correct CTFs until after the first peak
+	bool intact_ctf_first_peak;
+
+	// Pnly perform phase-flipping CTF correction
+	bool only_flip_phases;
+
+	// Images have been CTF phase flipped al;ready
+	bool ctf_phase_flipped;
+
+	// Flag whether current references are ctf corrected
+	bool refs_are_ctf_corrected;
+
+	// Flag whether directions have changed upon continuing an old run
+	bool directions_have_changed;
+
+	// Flag whether to do image-wise intensity-scale correction
+	bool do_norm_correction;
+
+	// Flag whether to do group-wise intensity bfactor correction
+	bool do_scale_correction;
+
+	// Flag whether to use the auto-refine procedure
+	bool do_auto_refine;
+
+	// Number of iterations without a resolution increase
+	int nr_iter_wo_resol_gain;
+
+	// Best resolution obtained thus far
+	double best_resol_thus_far;
+
+	// Is the FSC still high at the resolution limit?
+	bool has_high_fsc_at_limit;
+
+	// How many iterations ago was there a big step in the increase of current_size
+	int has_large_incr_size_iter_ago;
+
+	// In auto-sampling mode, use local searches from this sampling rate on
+	int autosampling_hporder_local_searches;
+
+	// Smallest changes thus far in the optimal translational offsets, orientations and classes
+	double smallest_changes_optimal_offsets;
+	double smallest_changes_optimal_orientations;
+	int smallest_changes_optimal_classes;
+
+	// Number of iterations without a decrease in OffsetChanges
+	int nr_iter_wo_large_hidden_variable_changes;
+
+	// Strict high-res limit in the expectation step
+	double strict_highres_exp;
+
+	// Flag to indicate to estimate angular accuracy until current_size (and not coarse_size) when restricting high-res limit in the expectation step
+	// This is used for testing purposes only
+	bool do_acc_currentsize_despite_highres_exp;
+
+	// Global parameters to store accuracy on rot and trans
+	double acc_rot, acc_trans;
+
+	// Flag to indicate to use all data out to Nyquist
+	bool do_use_all_data;
+
+	// Flag to indicate the refinement has converged
+	bool has_converged;
+
+	// Flag to indicate that angular sampling in auto-sampling has reached its limit
+	bool has_fine_enough_angular_sampling;
+
+	// Flag to keep sigma2_offset fixed
+	bool fix_sigma_offset;
+
+	// Flag to keep sigma2_noise fixed
+	bool fix_sigma_noise;
+
+	//  Use images only up to a certain resolution in the expectation step
+	int coarse_size;
+
+	// Use images only up to a certain resolution in the expectation step
+	int max_coarse_size;
+
+	// Particle diameter (in Ang)
+	double particle_diameter;
+
+	// How many fourier shells should be included beyond the highest shell where evidenceVsPriorRatio < 1?
+	int incr_size;
+
+	// Minimum resolution to perform Bayesian estimates of the model
+	int minres_map;
+
+	// Flag to flatten solvent
+	bool do_solvent;
+
+	// Filename for a user-provided mask
+	FileName fn_mask;
+
+	// Filename for a user-provided second solvent mask
+	// This solvent mask will have its own average density and may be useful for example to fill the interior of an icosahedral virus
+	FileName fn_mask2;
+
+	// Width of the soft-edges of the circular masks
+	int width_mask_edge;
+
+	// Number of particles to be processed simultaneously
+	int nr_pool, max_nr_pool;
+
+	// Available memory (in Gigabyte)
+	double available_memory;
+
+	// Perform combination of weight through files written on disc
+	bool combine_weights_thru_disc;
+
+	// Only print metadata label definitions and exit
+	bool do_print_metadata_labels;
+
+	// Print the symmetry transformation matrices
+	bool do_print_symmetry_ops;
+
+	/* Flag whether to use the Adaptive approach as by Tagare et al (2010) J. Struc. Biol.
+	 * where two passes through the integrations are made: a first one with a coarse angular sampling and
+	 * smaller images and a second one with finer angular sampling and larger images
+	 * Only the orientations that accumulate XXX% (adaptive_fraction) of the top weights from the first pass are oversampled in the second pass
+	 * Only these oversampled orientations will then contribute to the weighted sums
+	 * Note that this is a bit different from Tagare et al, in that we do not perform any B-spline interpolation....
+	 *
+	 * For (adaptive_oversampling==0): no adaptive approach is being made, there is only one pass
+	 * For (adaptive_oversampling==1): the coarse sampling grid is 2x coarse than the fine one
+	 * For (adaptive_oversampling==2): the coarse sampling grid is 4x coarse than the fine one
+	 * etc..
+	 *
+	 * */
+	int adaptive_oversampling;
+
+	/* Fraction of the weights for which to consider the finer sampling
+	 * The closer to one, the more orientations will be oversampled
+	 * The default is 0.999.
+	 */
+	double adaptive_fraction;
+
+	// Seed for random number generator
+	int random_seed;
+
+	/* Flag to indicate orientational (i.e. rotational AND translational) searches will be skipped */
+	bool do_skip_align;
+
+	/* Flag to indicate rotational searches will be skipped */
+	bool do_skip_rotate;
+
+	/* Flag to indicate maximization step will be skipped: only data.star file will be written out */
+	bool do_skip_maximization;
+
+	//////// Special stuff for the first iterations /////////////////
+
+	// Skip marginalisation in first iteration and use signal cross-product instead of Gaussian
+	bool do_firstiter_cc;
+
+	/// Always perform cross-correlation instead of marginalization
+	bool do_always_cc;
+
+	// Initial low-pass filter for all references (in digital frequency)
+	double ini_high;
+
+	// Flag whether to generate seeds
+	// TODO: implement!
+	bool do_generate_seeds;
+
+	// Flag whether to calculate the average of the unaligned images (for 2D refinements)
+	bool do_average_unaligned;
+
+	// Flag whether to calculate initial sigma_noise spectra
+	bool do_calculate_initial_sigma_noise;
+
+	// Flag to switch off error message about normalisation
+	bool dont_raise_norm_error;
+
+	///////// Re-align individual frames of movies /////////////
+
+	// Flag whether to realign frames of movies
+	bool do_realign_movies;
+
+	// Starfile with the movie-frames
+	FileName fn_data_movie;
+
+	// How many individual frames contribute to the priors?
+	int nr_frames_per_prior;
+
+	// How wide are the running averages of the frames to use for alignment?
+	// If set to 1, then running averages will be n-1, n, n+1, i.e. 3 frames wide
+	int movie_frame_running_avg_side;
+
+	///////// Hidden stuff, does not work with read/write: only via command-line ////////////////
+
+	// Number of iterations for gridding preweighting reconstruction
+	int gridding_nr_iter;
+
+	// Flag whether to do group-wise B-factor correction or not
+	bool do_bfactor;
+
+	// Flag whether to use maximum a posteriori (MAP) estimation
+	bool do_map;
+
+	// For debugging/analysis: Name for initial sigma_noise sepctrum;
+	FileName fn_sigma;
+
+	// Multiplicative fdge factor for the sigma estimates
+	double sigma2_fudge;
+
+	// Perform two reconstructions of random halves sequentially (to save memory for very big cases)
+	bool do_sequential_halves_recons;
+
+	// Do zero-filled soft-masks instead of noisy masks on experimental particles
+	// This will increase SNR but introduce correlations that are not modelled...
+	// Until now the best refinements have used the noisy mask, not the soft mask....
+	bool do_zero_mask;
+
+
+	// Developmental: simulated annealing to get out of local minima...
+	bool do_sim_anneal;
+	double temperature, temp_ini, temp_fin;
+
+	/////////// Keep track of hidden variable changes ////////////////////////
+
+	// Changes from one iteration to the next in the angles
+	double current_changes_optimal_orientations, sum_changes_optimal_orientations;
+
+	// Changes from one iteration to the next in the translations
+	double current_changes_optimal_offsets, sum_changes_optimal_offsets;
+
+	// Changes from one iteration to the next in the class assignments
+	double current_changes_optimal_classes, sum_changes_optimal_classes;
+
+	// Just count how often the optimal changes are summed
+	double sum_changes_count;
+
+	/////////// Some internal stuff ////////////////////////
+
+    // Array with pointers to the resolution of each point in a Fourier-space FFTW-like array
+	MultidimArray<int> Mresol_fine, Mresol_coarse, Npix_per_shell;
+
+	// Tabulated sin and cosine functions for shifts in Fourier space
+	TabSine tab_sin;
+	TabCosine tab_cos;
+
+	// Loop from iclass_min to iclass_max to deal with seed generation in the first iteration
+	int iclass_min, iclass_max;
+
+	// Verbosity flag
+	int verb;
+
+	// Thread Managers for the expectation step: one for allorientations, the other for all (pooled) particles
+	ThreadTaskDistributor *exp_iorient_ThreadTaskDistributor, *exp_ipart_ThreadTaskDistributor;
+
+	// Number of threads to run in parallel
+	int nr_threads, nr_threads_original;
+
+	/** Some global variables that are only for thread visibility */
+	/// Taken from getAllSquaredDifferences
+	std::vector<MultidimArray<Complex > > exp_Fimgs, exp_Fimgs_nomask, exp_local_Fimgs_shifted, exp_local_Fimgs_shifted_nomask;
+	std::vector<MultidimArray<double> > exp_Fctfs, exp_local_Fctfs, exp_local_Minvsigma2s;
+	Matrix2D<double> exp_R_mic;
+	int exp_iseries, exp_iclass, exp_ipass, exp_iimage, exp_ipart, exp_current_image_size, exp_current_oversampling, exp_nr_ori_particles, exp_nr_particles, exp_nr_images;
+	long int exp_nr_oversampled_rot, exp_nr_oversampled_trans, exp_nr_rot, exp_nr_dir, exp_nr_psi, exp_nr_trans;
+	long int exp_part_id, exp_my_first_ori_particle, exp_my_last_ori_particle;
+	std::vector<int> exp_starting_image_no;
+	std::vector<long int> exp_ipart_to_part_id, exp_ipart_to_ori_part_id, exp_ipart_to_ori_part_nframe, exp_iimg_to_ipart;
+	std::vector<double> exp_highres_Xi2_imgs, exp_min_diff2, exp_local_sqrtXi2, exp_local_oldcc;
+	MultidimArray<double> exp_Mweight;
+	MultidimArray<bool> exp_Mcoarse_significant;
+	// And from storeWeightedSums
+	std::vector<double> exp_sum_weight, exp_significant_weight, exp_max_weight;
+	std::vector<Matrix1D<double> > exp_old_offset, exp_prior;
+	std::vector<double> exp_wsum_norm_correction;
+	std::vector<MultidimArray<double> > exp_wsum_scale_correction_XA, exp_wsum_scale_correction_AA, exp_power_imgs;
+	MultidimArray<double> exp_metadata, exp_imagedata;
+	double exp_thisparticle_sumweight;
+
+	//TMP DEBUGGING
+	MultidimArray<double> DEBUGGING_COPY_exp_Mweight;
+
+#ifdef TIMING
+    Timer timer;
+	int TIMING_DIFF_PROJ, TIMING_DIFF_SHIFT, TIMING_DIFF_DIFF2;
+	int TIMING_WSUM_PROJ, TIMING_WSUM_BACKPROJ, TIMING_WSUM_DIFF2, TIMING_WSUM_SUMSHIFT;
+	int TIMING_EXP, TIMING_MAX, TIMING_RECONS;
+	int TIMING_ESP, TIMING_ESP_READ, TIMING_ESP_DIFF1, TIMING_ESP_DIFF2;
+	int TIMING_ESP_WEIGHT1, TIMING_ESP_WEIGHT2, TIMING_WEIGHT_EXP, TIMING_WEIGHT_SORT, TIMING_ESP_WSUM;
+#endif
+
+public:
+
+    /** ========================== I/O operations  =========================== */
+	/// Print help message
+    void usage();
+
+    /// Interpret command line
+	void read(int argc, char **argv, int rank = 0);
+
+	/// Interpret command line for the initial start of a run
+	void parseInitial(int argc, char **argv);
+
+	/// Interpret command line for the re-start of a run
+	void parseContinue(int argc, char **argv);
+
+	/// Read from STAR file
+	void read(FileName fn_in, int rank = 0);
+
+	// Write files to disc
+	void write(bool do_write_sampling, bool do_write_data, bool do_write_optimiser, bool do_write_model, int random_subset = 0);
+
+    /** ========================== Initialisation  =========================== */
+
+	// Initialise the whole optimiser
+	void initialise();
+
+	// Some general stuff that is shared between MPI and sequential code
+	void initialiseGeneral(int rank = 0);
+
+	// Randomise particle processing order and resize metadata array
+	void initialiseWorkLoad();
+
+	/* Calculates the sum of all individual power spectra and the average of all images for initial sigma_noise estimation
+	 * The rank is passed so that if one splits the data into random halves one can know which random half to treat
+	 */
+	void calculateSumOfPowerSpectraAndAverageImage(MultidimArray<double> &Mavg, bool myverb = true);
+
+	/** Use the sum of the individual power spectra to calculate their average and set this in sigma2_noise
+	 * Also subtract the power spectrum of the average images,
+	 * and if (do_average_unaligned) then also set Mavg to all Iref
+	 */
+	void setSigmaNoiseEstimatesAndSetAverageImage(MultidimArray<double> &Mavg);
+
+	/* Perform an initial low-pass filtering of the references
+	 * Note that because of the MAP estimation, this is not necessary inside the refinement
+	 */
+	void initialLowPassFilterReferences();
+
+	/** ========================== EM-Iteration  ================================= */
+
+	/* Launch threads and set up task distributors*/
+	void iterateSetup();
+
+	/* Delete threads and task distributors */
+	void iterateWrapUp();
+
+	/* Perform expectation-maximization iterations */
+	void iterate();
+
+	/* Expectation step: loop over all particles
+	 */
+	void expectation();
+
+	/* Setup expectation step */
+	void expectationSetup();
+
+	/* Check whether everything fits into memory, possibly adjust nr_pool and setup thread task managers */
+	void expectationSetupCheckMemory(bool myverb = true);
+
+	/* Perform the expectation integration over all k, phi and series elements for a number (some) of pooled particles
+	 * The number of pooled particles is determined by max_nr_pool and some memory checks in expectationSetup()
+	 */
+	void expectationSomeParticles(long int my_first_particle, long int my_last_particle);
+
+	/* Maximization step
+	 * Updates the current model: reconstructs and updates all other model parameter
+	 */
+	void maximization();
+
+	/* Perform the actual reconstructions
+	 * This is officially part of the maximization, but it is separated because of parallelisation issues.
+	 */
+	void maximizationReconstructClass(int iclass);
+
+	/* Updates all other model parameters (besides the reconstructions)
+	 */
+	void maximizationOtherParameters();
+
+
+    /** ========================== Deeper functions ================================= */
+
+	/* Apply a solvent flattening to a map
+	 */
+	void solventFlatten();
+
+	/* Updates the current resolution (from data_vs_prior array) and keeps track of best resolution thus far
+	 *  and precalculates a 2D Fourier-space array with pointers to the resolution of each point in a FFTW-centered array
+	 */
+	void updateCurrentResolution();
+
+	/* Update the current and coarse image size
+	 *  and precalculates a 2D Fourier-space array with pointers to the resolution of each point in a FFTW-centered array
+	 */
+	void updateImageSizeAndResolutionPointers();
+
+	/* Calculates the PDF of the in-plane translation
+	 * assuming a 2D (or 3D) Gaussian centered at (0,0) and with stddev of mymodel.sigma2_offset
+	 */
+	double calculatePdfOffset(Matrix1D<double> offset, Matrix1D<double> prior);
+
+	/* From the vectors of Fourier transforms of the images, calculate running averages over the movie frames
+	 */
+	void calculateRunningAveragesOfMovieFrames();
+
+	/* Read image and its metadata from disc (threaded over all pooled particles)
+	 */
+	void doThreadGetFourierTransformsAndCtfs(int thread_id);
+
+	/* Store all shifted FourierTransforms in a vector
+	 * also store precalculated 2D matrices with 1/sigma2_noise
+	 */
+	void doThreadPrecalculateShiftedImagesCtfsAndInvSigma2s(int thread_id);
+
+	// Given exp_Mcoarse_significant, check for iorient whether any of the particles has any significant (coarsely sampled) translation
+	bool isSignificantAnyParticleAnyTranslation(long int iorient);
+
+	// Threaded core of getAllSquaredDifferences, where loops over all orientations are parallelised using threads
+	void doThreadGetSquaredDifferencesAllOrientations(int thread_id);
+
+	// Get squared differences for all iclass, idir, ipsi and itrans...
+	void getAllSquaredDifferences();
+
+	// Threaded core of convertAllSquaredDifferencesToWeights, where loops over all orientations are parallelised using threads
+	void doThreadConvertSquaredDifferencesToWeightsAllOrientations(int thread_id);
+
+	// Convert all squared difference terms to weights.
+	// Also calculates exp_sum_weight and, for adaptive approach, also exp_significant_weight
+	void convertAllSquaredDifferencesToWeights();
+
+	// Threaded core of storeWeightedSums, where loops over all orientations are parallelised using threads
+	void doThreadStoreWeightedSumsAllOrientations(int thread_id);
+
+	// Store all relevant weighted sums, also return optimal hidden variables, max_weight and dLL
+	void storeWeightedSums();
+
+	/** Monitor the changes in the optimal translations, orientations and class assignments for some particles */
+	void monitorHiddenVariableChanges(long int my_first_ori_particle, long int my_last_ori_particle);
+
+	// Updates the overall changes in the hidden variables and keeps track of nr_iter_wo_large_changes_in_hidden_variables
+	void updateOverallChangesInHiddenVariables();
+
+	// Calculate expected error in orientational assignments
+	// Based on comparing projections of the model and see how many degrees apart gives rise to difference of power > 3*sigma^ of the noise
+	void calculateExpectedAngularErrors(long int my_first_ori_particle, long int my_last_ori_particle);
+
+	// Adjust angular sampling based on the expected angular accuracies for auto-refine procedure
+	void updateAngularSampling(bool verb = true);
+
+	// Check convergence for auto-refine procedure
+	void checkConvergence();
+
+	// Print convergence information to screen for auto-refine procedure
+	void printConvergenceStats();
+
+	// Set metadata of a subset of particles to the experimental model
+	void setMetaDataSubset(int first_ori_particle_id, int last_ori_particle_id);
+
+	// Get metadata array of a subset of particles from the experimental model
+	void getMetaAndImageDataSubset(int first_ori_particle_id, int last_ori_particle_id, bool do_also_imagedata = true);
+
+};
+
+// Global call to threaded core of doThreadGetFourierTransformsAndCtfs
+void globalThreadGetFourierTransformsAndCtfs(ThreadArgument &thArg);
+
+// Global call to threaded core of doPrecalculateShiftedImagesCtfsAndInvSigma2s
+void globalThreadPrecalculateShiftedImagesCtfsAndInvSigma2s(ThreadArgument &thArg);
+
+// Global call to threaded core of getAllSquaredDifferences, where loops over all orientations are parallelised using threads
+void globalThreadGetSquaredDifferencesAllOrientations(ThreadArgument &thArg);
+
+// Global call to threaded core of convertAllSquaredDifferencesToWeights, where loops over all orientations are parallelised using threads
+void globalThreadConvertSquaredDifferencesToWeightsAllOrientations(ThreadArgument &thArg);
+
+// Global call to threaded core of convertAllSquaredDifferencesToWeights, where loops over all orientations are parallelised using threads
+void globalThreadConvertSquaredDifferencesToWeightsAllOrientations(ThreadArgument &thArg);
+
+#endif /* MAXLIK_H_ */
diff --git a/src/ml_optimiser_mpi.cpp b/src/ml_optimiser_mpi.cpp
new file mode 100644
index 0000000..04a35cc
--- /dev/null
+++ b/src/ml_optimiser_mpi.cpp
@@ -0,0 +1,1680 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include <mpi.h>
+#include "src/ml_optimiser_mpi.h"
+#include "src/ml_optimiser.h"
+
+//#define DEBUG
+//#define DEBUG_MPIEXP2
+void MlOptimiserMpi::read(int argc, char **argv)
+{
+#ifdef DEBUG
+    std::cerr<<"MlOptimiserMpi::read Entering "<<std::endl;
+#endif
+
+    // Define a new MpiNode
+    node = new MpiNode(argc, argv);
+
+    // First read in non-parallelisation-dependent variables
+    MlOptimiser::read(argc, argv, node->rank);
+    fn_scratch = parser.getOption("--scratchdir", "Directory (with absolute path, and visible to all nodes) for temporary files", "");
+
+    // Don't put any output to screen for mpi slaves
+    verb = (node->isMaster()) ? 1 : 0;
+
+    // TMP for debugging only
+    //if (node->rank==1)
+    //	verb = 1;
+    // Possibly also read parallelisation-dependent variables here
+
+#ifdef DEBUG
+    std::cerr<<"MlOptimiserMpi::read done"<<std::endl;
+#endif
+
+}
+void MlOptimiserMpi::finalise()
+{
+	delete node;
+}
+
+void MlOptimiserMpi::initialise()
+{
+
+#ifdef DEBUG
+    std::cerr<<"MlOptimiserMpi::initialise Entering"<<std::endl;
+#endif
+
+    // Print information about MPI nodes:
+    printMpiNodesMachineNames(*node, nr_threads);
+
+    MlOptimiser::initialiseGeneral(node->rank);
+
+    initialiseWorkLoad();
+
+	if (fn_sigma != "")
+	{
+		// Read in sigma_noise spetrum from file DEVELOPMENTAL!!! FOR DEBUGGING ONLY....
+		MetaDataTable MDsigma;
+		double val;
+		int idx;
+		MDsigma.read(fn_sigma);
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDsigma)
+		{
+			MDsigma.getValue(EMDL_SPECTRAL_IDX, idx);
+			MDsigma.getValue(EMDL_MLMODEL_SIGMA2_NOISE, val);
+			if (idx < XSIZE(mymodel.sigma2_noise[0]))
+				mymodel.sigma2_noise[0](idx) = val;
+		}
+		if (idx < XSIZE(mymodel.sigma2_noise[0]) - 1)
+		{
+			if (verb > 0) std::cout<< " WARNING: provided sigma2_noise-spectrum has fewer entries ("<<idx+1<<") than needed ("<<XSIZE(mymodel.sigma2_noise[0])<<"). Set rest to zero..."<<std::endl;
+		}
+		// Use the same spectrum for all classes
+		for (int igroup = 0; igroup< mymodel.nr_groups; igroup++)
+			mymodel.sigma2_noise[igroup] =  mymodel.sigma2_noise[0];
+
+	}
+	else if (do_calculate_initial_sigma_noise || do_average_unaligned)
+	{
+		MultidimArray<double> Mavg;
+		// Calculate initial sigma noise model from power_class spectra of the individual images
+		// This is done in parallel
+		//std::cout << " Hello world1! I am node " << node->rank << " out of " << node->size <<" and my hostname= "<< getenv("HOSTNAME")<< std::endl;
+		calculateSumOfPowerSpectraAndAverageImage(Mavg);
+
+		// Set sigma2_noise and Iref from averaged poser spectra and Mavg
+		if (!node->isMaster())
+			MlOptimiser::setSigmaNoiseEstimatesAndSetAverageImage(Mavg);
+		//std::cout << " Hello world3! I am node " << node->rank << " out of " << node->size <<" and my hostname= "<< getenv("HOSTNAME")<< std::endl;
+	}
+
+    MlOptimiser::initialLowPassFilterReferences();
+
+	// Initialise the data_versus_prior ratio to get the initial current_size right
+	if (iter == 0)
+		mymodel.initialiseDataVersusPrior(fix_tau); // fix_tau was set in initialiseGeneral
+
+	//std::cout << " Hello world! I am node " << node->rank << " out of " << node->size <<" and my hostname= "<< getenv("HOSTNAME")<< std::endl;
+
+	// Only master writes out initial mymodel (do not gather metadata yet)
+	int nr_subsets = (do_split_random_halves) ? 2 : 1;
+	if (node->isMaster())
+		MlOptimiser::write(DONT_WRITE_SAMPLING, DO_WRITE_DATA, DONT_WRITE_OPTIMISER, DONT_WRITE_MODEL, node->rank);
+	else if (node->rank <= nr_subsets)
+	{
+		//Only the first_slave of each subset writes model to disc
+		MlOptimiser::write(DO_WRITE_SAMPLING, DONT_WRITE_DATA, DO_WRITE_OPTIMISER, DO_WRITE_MODEL, node->rank);
+
+		bool do_warn = false;
+		for (int igroup = 0; igroup< mymodel.nr_groups; igroup++)
+		{
+			if (mymodel.nr_particles_group[igroup] < 5 && node->rank == 1) // only warn for half1 to avoid messy output
+			{
+				if (nr_subsets == 1)
+					std:: cout << "WARNING: There are only " << mymodel.nr_particles_group[igroup] << " particles in group " << igroup + 1 << std::endl;
+				else
+					std:: cout << "WARNING: There are only " << mymodel.nr_particles_group[igroup] << " particles in group " << igroup + 1 << " of half-set " << node->rank << std::endl;
+				do_warn = true;
+			}
+		}
+		if (do_warn)
+		{
+			std:: cout << "WARNING: You may want to consider joining some micrographs into larger groups to obtain more robust noise estimates. " << std::endl;
+			std:: cout << "         You can do so by using the same rlnMicrographName for particles from multiple different micrographs in the input STAR file. " << std::endl;
+            std:: cout << "         It is then best to join micrographs with similar defocus values and similar apparent signal-to-noise ratios. " << std::endl;
+		}
+	}
+
+	// Do this after writing out the model, so that still the random halves are written in separate files.
+	if (do_realign_movies)
+	{
+		// Resolution seems to decrease again after 1 iteration. Therefore, just perform a single iteration until we figure out what exactly happens here...
+		has_converged = true;
+		// Then use join random halves
+		do_join_random_halves = true;
+
+		// If we skip the maximization step, then there is no use in using all data
+		if (!do_skip_maximization)
+		{
+			// Use all data out to Nyquist because resolution gains may be substantial
+			do_use_all_data = true;
+		}
+	}
+
+
+#ifdef DEBUG
+    std::cerr<<"MlOptimiserMpi::initialise Done"<<std::endl;
+#endif
+}
+
+void MlOptimiserMpi::initialiseWorkLoad()
+{
+
+    if (do_split_random_halves && node->size <= 2)
+    	REPORT_ERROR("MlOptimiserMpi::initialiseWorkLoad: at least 3 MPI processes are required when splitting data into random halves");
+    else if(node->size <= 1)
+    	REPORT_ERROR("MlOptimiserMpi::initialiseWorkLoad: at least 2 MPI processes are required, otherwise use the sequential program");
+
+	// Get the same random number generator seed for all mpi nodes
+	if (random_seed == -1)
+	{
+		if (node->isMaster())
+		{
+			random_seed = time(NULL);
+	        for (int slave = 1; slave < node->size; slave++)
+	        	node->relion_MPI_Send(&random_seed, 1, MPI_INT, slave, MPITAG_RANDOMSEED, MPI_COMM_WORLD);
+		}
+		else
+		{
+			MPI_Status status;
+			node->relion_MPI_Recv(&random_seed, 1, MPI_INT, 0, MPITAG_RANDOMSEED, MPI_COMM_WORLD, status);
+		}
+	}
+
+    // First split the data into two random halves and then randomise the particle order
+	if (do_split_random_halves)
+		mydata.divideOriginalParticlesInRandomHalves(random_seed);
+
+	// Randomise the order of the particles
+    mydata.randomiseOriginalParticlesOrder(random_seed, do_split_random_halves);
+
+    // Also randomize random-number-generator for perturbations on the angles
+    init_random_generator(random_seed);
+
+
+	if (node->isMaster())
+	{
+		// The master never participates in any actual work
+		my_first_ori_particle_id = 0;
+		my_last_ori_particle_id = -1;
+	}
+	else
+	{
+		if (do_split_random_halves)
+		{
+	    	int nr_slaves_subset1 = (node->size - 1) / 2;
+	    	int nr_slaves_subset2 = nr_slaves_subset1;
+	    	if ( (node->size - 1) % 2 != 0)
+	    		nr_slaves_subset1 += 1;
+	    	if (node->myRandomSubset() == 1)
+	    	{
+	    		// Divide first half of the images
+	    		divide_equally(mydata.numberOfOriginalParticles(1), nr_slaves_subset1, node->rank / 2, my_first_ori_particle_id, my_last_ori_particle_id);
+	    	}
+	    	else
+	    	{
+	    		// Divide second half of the images
+	    		divide_equally(mydata.numberOfOriginalParticles(2), nr_slaves_subset2, node->rank / 2 - 1, my_first_ori_particle_id, my_last_ori_particle_id);
+	    		my_first_ori_particle_id += mydata.numberOfOriginalParticles(1);
+	    		my_last_ori_particle_id += mydata.numberOfOriginalParticles(1);
+	    	}
+		}
+		else
+		{
+			int nr_slaves = (node->size - 1);
+			divide_equally(mydata.numberOfOriginalParticles(), nr_slaves, node->rank - 1, my_first_ori_particle_id, my_last_ori_particle_id);
+		}
+
+	}
+//#define DEBUG_WORKLOAD
+#ifdef DEBUG_WORKLOAD
+	std::cerr << " node->rank= " << node->rank << " my_first_ori_particle_id= " << my_first_ori_particle_id << " my_last_ori_particle_id= " << my_last_ori_particle_id << std::endl;
+#endif
+}
+
+void MlOptimiserMpi::calculateSumOfPowerSpectraAndAverageImage(MultidimArray<double> &Mavg)
+{
+
+	// First calculate the sum of all individual power spectra on each subset
+	MlOptimiser::calculateSumOfPowerSpectraAndAverageImage(Mavg, node->rank == 1);
+	//std::cout << " Hello world22! I am node " << node->rank << " out of " << node->size <<" and my hostname= "<< getenv("HOSTNAME")<< std::endl;
+
+	// When splitting the data into two random halves, perform two passes: one for each subset
+	int nr_subsets = (do_split_random_halves) ? 2 : 1;
+
+	MultidimArray<double> Msum, MsumI;
+	MultidimArray<int> Mnr, Msumnr;
+	double dsum;
+	int isum;
+	MPI_Status status;
+
+
+	for (int isubset = 1; isubset <= nr_subsets; isubset++)
+	{
+		int my_first_slave = isubset; // first pass subset1: my_first_rank = 1, second pass subset2: my_first_rank = 2
+		int my_first_other_slave = XMIPP_MIN(my_first_slave + nr_subsets, node->size);
+		//std::cerr << " my_first_slave= " << my_first_slave << " my_first_other_slave= " << my_first_other_slave << std::endl;
+		// Initialise on the first slave
+		if (node->rank == my_first_slave)
+		{
+			Msum = wsum_model.sigma2_noise[0];
+			MsumI = Mavg;
+			dsum = wsum_model.sumw_group[0];
+			Mnr.resize(mymodel.nr_groups);
+			FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(Mnr)
+			{
+				DIRECT_A1D_ELEM(Mnr, i) = mymodel.nr_particles_group[i];
+			}
+			Msumnr = Mnr;
+
+    	}
+		for (int other_slave = my_first_other_slave; other_slave < node->size; other_slave += nr_subsets)
+		{
+			if (node->rank == other_slave)
+			{
+				//std::cerr << "Sending from "<<other_slave<< " to "<<my_first_slave << std::endl;
+				node->relion_MPI_Send(MULTIDIM_ARRAY(wsum_model.sigma2_noise[0]), MULTIDIM_SIZE(wsum_model.sigma2_noise[0]), MPI_DOUBLE, my_first_slave, MPITAG_PACK, MPI_COMM_WORLD);
+				node->relion_MPI_Send(MULTIDIM_ARRAY(Mavg), MULTIDIM_SIZE(Mavg), MPI_DOUBLE, my_first_slave, MPITAG_IMAGE, MPI_COMM_WORLD);
+				Mnr.resize(mymodel.nr_groups);
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(Mnr)
+				{
+					DIRECT_A1D_ELEM(Mnr, i) = mymodel.nr_particles_group[i];
+        		}
+				node->relion_MPI_Send(MULTIDIM_ARRAY(Mnr), MULTIDIM_SIZE(Mnr), MPI_INT, my_first_slave, MPITAG_METADATA, MPI_COMM_WORLD);
+				node->relion_MPI_Send(&wsum_model.sumw_group[0], 1, MPI_DOUBLE, my_first_slave, MPITAG_DOUBLE, MPI_COMM_WORLD);
+
+    		}
+			else if (node->rank == my_first_slave)
+			{
+				//std::cerr << "Receiving at "<<my_first_slave<< " from "<<other_slave<<std::endl;
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(wsum_model.sigma2_noise[0]), MULTIDIM_SIZE(wsum_model.sigma2_noise[0]), MPI_DOUBLE, other_slave, MPITAG_PACK, MPI_COMM_WORLD, status);
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(Mavg), MULTIDIM_SIZE(Mavg), MPI_DOUBLE, other_slave, MPITAG_IMAGE, MPI_COMM_WORLD, status);
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(Mnr), MULTIDIM_SIZE(Mnr), MPI_INT, other_slave, MPITAG_METADATA, MPI_COMM_WORLD, status);
+				node->relion_MPI_Recv(&wsum_model.sumw_group[0], 1, MPI_DOUBLE, other_slave, MPITAG_DOUBLE, MPI_COMM_WORLD, status);
+				// Add the contribution of this other slave
+				Msum  += wsum_model.sigma2_noise[0];
+				MsumI += Mavg;
+				Msumnr += Mnr;
+				dsum += wsum_model.sumw_group[0];
+    		}
+		}
+
+		// Now the first slave has the sum of all other slaves in its Msum
+		// Send this sum to all relevant other slaves
+		for (int other_slave = my_first_other_slave; other_slave < node->size; other_slave += nr_subsets)
+		{
+			if (node->rank == my_first_slave)
+			{
+				//std::cerr << "Sending from my_first_slave"<<my_first_slave<< " to other_slave "<<other_slave<< std::endl;
+				node->relion_MPI_Send(MULTIDIM_ARRAY(Msum), MULTIDIM_SIZE(Msum), MPI_DOUBLE, other_slave, MPITAG_PACK, MPI_COMM_WORLD);
+				node->relion_MPI_Send(MULTIDIM_ARRAY(Msumnr), MULTIDIM_SIZE(Msumnr), MPI_INT, other_slave, MPITAG_METADATA, MPI_COMM_WORLD);
+				node->relion_MPI_Send(MULTIDIM_ARRAY(MsumI), MULTIDIM_SIZE(MsumI), MPI_DOUBLE, other_slave, MPITAG_IMAGE, MPI_COMM_WORLD);
+				node->relion_MPI_Send(&dsum, 1, MPI_DOUBLE, other_slave, MPITAG_DOUBLE, MPI_COMM_WORLD);
+			}
+			else if (node->rank == other_slave)
+			{
+				//std::cerr << "Receiving at other_slave "<<other_slave<<" from my_first_slave "<<my_first_slave<< std::endl;
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(wsum_model.sigma2_noise[0]), MULTIDIM_SIZE(wsum_model.sigma2_noise[0]), MPI_DOUBLE, my_first_slave, MPITAG_PACK, MPI_COMM_WORLD, status);
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(Mnr), MULTIDIM_SIZE(Mnr), MPI_INT, my_first_slave, MPITAG_METADATA, MPI_COMM_WORLD, status);
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(Mavg), MULTIDIM_SIZE(Mavg), MPI_DOUBLE, my_first_slave, MPITAG_IMAGE, MPI_COMM_WORLD, status);
+				node->relion_MPI_Recv(&wsum_model.sumw_group[0], 1, MPI_DOUBLE, my_first_slave, MPITAG_DOUBLE, MPI_COMM_WORLD, status);
+				// Unpack Mnr on the other slave
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(Mnr)
+				{
+					mymodel.nr_particles_group[i] = DIRECT_A1D_ELEM(Mnr, i);
+				}
+			}
+		}
+
+		// Also set sums on the first slave
+		if (node->rank == my_first_slave)
+		{
+			wsum_model.sigma2_noise[0] = Msum;
+			Mavg = MsumI;
+			FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(Msumnr)
+			{
+				mymodel.nr_particles_group[i] = DIRECT_A1D_ELEM(Msumnr, i);
+			}
+			wsum_model.sumw_group[0] = dsum;
+		}
+
+	}
+	//std::cout << " Hello world23! I am node " << node->rank << " out of " << node->size <<" and my hostname= "<< getenv("HOSTNAME")<< std::endl;
+
+}
+
+void MlOptimiserMpi::expectation()
+{
+
+#ifdef DEBUG
+	std::cerr << "MlOptimiserMpi::expectation: Entering " << std::endl;
+#endif
+
+	MultidimArray<long int> first_last_nr_images(3);
+	MultidimArray<double> metadata;
+	int first_slave = 1;
+	// Use maximum of 100 particles for 3D and 10 particles for 2D estimations
+	int n_trials_acc = (mymodel.ref_dim==3) ? 100 : 10;
+	n_trials_acc = XMIPP_MIN(n_trials_acc, mydata.numberOfOriginalParticles());
+	MPI_Status status;
+
+	// Initialise some stuff
+	// A. Update current size (may have been changed to ori_size in autoAdjustAngularSampling) and resolution pointers
+	updateImageSizeAndResolutionPointers();
+
+	// B. Set the PPref Fourier transforms, initialise wsum_model, etc.
+	// The master only holds metadata, it does not set up the wsum_model (to save memory)
+	if (!node->isMaster())
+	{
+		MlOptimiser::expectationSetup();
+
+		// All slaves no longer need mydata.MD tables
+		mydata.MDimg.clear();
+		mydata.MDmic.clear();
+
+		// Many small new's are not returned to the OS upon free-ing them. To force this, use the following call
+		// from http://stackoverflow.com/questions/10943907/linux-allocator-does-not-release-small-chunks-of-memory
+#if !defined(__APPLE__)
+                malloc_trim(0);
+#endif
+
+	}
+
+	// C. Calculate expected angular errors
+	// Do not do this for maxCC
+	// Only the first (reconstructing) slave (i.e. from half1) calculates expected angular errors
+	if (!(iter==1 && do_firstiter_cc) &&  !(do_skip_align || do_skip_rotate) )
+	{
+		int my_nr_images;
+		if (node->isMaster())
+		{
+			// Master sends metadata (but not imagedata) for first 100 particles to first_slave (for calculateExpectedAngularErrors)
+			MlOptimiser::getMetaAndImageDataSubset(0, n_trials_acc-1, false);
+			my_nr_images = YSIZE(exp_metadata);
+			node->relion_MPI_Send(&my_nr_images, 1, MPI_INT, first_slave, MPITAG_JOB_REQUEST, MPI_COMM_WORLD);
+			node->relion_MPI_Send(MULTIDIM_ARRAY(exp_metadata), MULTIDIM_SIZE(exp_metadata), MPI_DOUBLE, first_slave, MPITAG_METADATA, MPI_COMM_WORLD);
+		}
+		else if (node->rank == first_slave)
+		{
+			// Slave has to receive all metadata from the master!
+			node->relion_MPI_Recv(&my_nr_images, 1, MPI_INT, 0, MPITAG_JOB_REQUEST, MPI_COMM_WORLD, status);
+			exp_metadata.resize(my_nr_images, METADATA_LINE_LENGTH);
+			node->relion_MPI_Recv(MULTIDIM_ARRAY(exp_metadata), MULTIDIM_SIZE(exp_metadata), MPI_DOUBLE, 0, MPITAG_METADATA, MPI_COMM_WORLD, status);
+			calculateExpectedAngularErrors(0, n_trials_acc-1);
+		}
+
+		// The reconstructing slave Bcast acc_rottilt, acc_psi, acc_trans to all other nodes!
+		node->relion_MPI_Bcast(&acc_rot, 1, MPI_DOUBLE, first_slave, MPI_COMM_WORLD);
+		node->relion_MPI_Bcast(&acc_trans, 1, MPI_DOUBLE, first_slave, MPI_COMM_WORLD);
+	}
+
+	// D. Update the angular sampling (all nodes except master)
+	if (!node->isMaster() && do_auto_refine && iter > 1 )
+	{
+		updateAngularSampling(node->rank == 1);
+	}
+	node->relion_MPI_Bcast(&has_fine_enough_angular_sampling, 1, MPI_INT, first_slave, MPI_COMM_WORLD);
+
+	// E. All nodes, except the master, check memory
+	if (!node->isMaster())
+	{
+		// Check whether everything fits into memory, possibly adjust nr_pool and setup thread task managers
+		MlOptimiser::expectationSetupCheckMemory(node->rank == first_slave);
+	}
+	// Slave 1 sends nr_pool and has_converged to everyone else (in particular the master needs it!)
+	// nr_pool was set by all slaves, but not the master, in MlOptimiser::expectationSetupCheckMemory
+	node->relion_MPI_Bcast(&nr_pool, 1, MPI_INT, first_slave, MPI_COMM_WORLD);
+	node->relion_MPI_Bcast(&has_converged, 1, MPI_INT, first_slave, MPI_COMM_WORLD);
+	node->relion_MPI_Bcast(&do_join_random_halves, 1, MPI_INT, first_slave, MPI_COMM_WORLD);
+
+	// Wait until expected angular errors have been calculated
+	MPI_Barrier(MPI_COMM_WORLD);
+	sleep(1);
+
+	// Now perform real expectation step in parallel, use an on-demand master-slave system
+#define JOB_FIRST (first_last_nr_images(0))
+#define JOB_LAST  (first_last_nr_images(1))
+#define JOB_NIMG  (first_last_nr_images(2))
+#define JOB_NPAR  (JOB_LAST - JOB_FIRST + 1)
+
+    if (node->isMaster())
+    {
+        try
+        {
+    		std::cout << " Expectation iteration " << iter;
+    		if (!do_auto_refine)
+    			std::cout << " of " << nr_iter;
+    		std::cout << std::endl;
+        	init_progress_bar(mydata.numberOfOriginalParticles());
+
+			// Master distributes all packages of SomeParticles
+			int nr_slaves_done = 0;
+			int random_subset = 0;
+			long int nr_ori_particles_done = 0;
+			long int prev_step_done = nr_ori_particles_done;
+			long int progress_bar_step_size = ROUND(mydata.numberOfOriginalParticles() / 80);
+			long int nr_ori_particles_done_subset1 = 0;
+			long int nr_ori_particles_done_subset2 = 0;
+			long int my_nr_ori_particles_done = 0;
+
+			while (nr_slaves_done < node->size - 1)
+			{
+				// Receive a job request from a slave
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(first_last_nr_images), MULTIDIM_SIZE(first_last_nr_images), MPI_LONG, MPI_ANY_SOURCE, MPITAG_JOB_REQUEST, MPI_COMM_WORLD, status);
+				// Which slave sent this request?
+				int this_slave = status.MPI_SOURCE;
+
+				//#define DEBUG_MPIEXP2
+#ifdef DEBUG_MPIEXP2
+				std::cerr << " MASTER RECEIVING from slave= " << this_slave<< " JOB_FIRST= " << JOB_FIRST << " JOB_LAST= " << JOB_LAST
+						<< " JOB_NIMG= "<<JOB_NIMG<< " JOB_NPAR= "<<JOB_NPAR<< std::endl;
+#endif
+				// The first time a slave reports it only asks for input, but does not send output of a previous processing task. In that case JOB_NIMG==0
+				// Otherwise, the master needs to receive and handle the updated metadata from the slaves
+				if (JOB_NIMG > 0)
+				{
+					exp_metadata.resize(JOB_NIMG, METADATA_LINE_LENGTH);
+					node->relion_MPI_Recv(MULTIDIM_ARRAY(exp_metadata), MULTIDIM_SIZE(exp_metadata), MPI_DOUBLE, this_slave, MPITAG_METADATA, MPI_COMM_WORLD, status);
+
+					// The master monitors the changes in the optimal orientations and classes
+					monitorHiddenVariableChanges(JOB_FIRST, JOB_LAST);
+
+					// The master then updates the mydata.MDimg table
+					MlOptimiser::setMetaDataSubset(JOB_FIRST, JOB_LAST);
+					if (nr_ori_particles_done - prev_step_done > progress_bar_step_size)
+					{
+						prev_step_done = nr_ori_particles_done;
+						progress_bar(nr_ori_particles_done + JOB_NPAR);
+					}
+				}
+
+				// See which random_subset this slave belongs to, and keep track of the number of ori_particles that have been processed already
+				if (do_split_random_halves)
+				{
+					random_subset = (this_slave % 2 == 1) ? 1 : 2;
+					if (random_subset == 1)
+					{
+						my_nr_ori_particles_done = nr_ori_particles_done_subset1;
+						// random_subset1 is stored in second half of OriginalParticles
+						JOB_FIRST = nr_ori_particles_done_subset1;
+						JOB_LAST  = XMIPP_MIN(mydata.numberOfOriginalParticles(1) - 1, JOB_FIRST + nr_pool - 1);
+					}
+					else
+					{
+						my_nr_ori_particles_done = nr_ori_particles_done_subset2;
+						// random_subset2 is stored in second half of OriginalParticles
+						JOB_FIRST = mydata.numberOfOriginalParticles(1) + nr_ori_particles_done_subset2;
+						JOB_LAST  = XMIPP_MIN(mydata.numberOfOriginalParticles() - 1, JOB_FIRST + nr_pool - 1);
+					}
+				}
+				else
+				{
+					random_subset = 0;
+					my_nr_ori_particles_done = nr_ori_particles_done;
+					JOB_FIRST = nr_ori_particles_done;
+					JOB_LAST  = XMIPP_MIN(mydata.numberOfOriginalParticles() - 1, JOB_FIRST + nr_pool - 1);
+				}
+
+				// Now send out a new job
+				if (my_nr_ori_particles_done < mydata.numberOfOriginalParticles(random_subset))
+				{
+
+					MlOptimiser::getMetaAndImageDataSubset(JOB_FIRST, JOB_LAST);
+					JOB_NIMG = YSIZE(exp_metadata);
+				}
+				else
+				{
+					// There are no more particles in the list
+					JOB_FIRST = -1;
+					JOB_LAST = -1;
+					JOB_NIMG = 0;
+					exp_metadata.clear();
+					exp_imagedata.clear();
+
+					// No more particles, this slave is done now
+					nr_slaves_done++;
+				}
+#ifdef DEBUG_MPIEXP2
+				std::cerr << " MASTER SENDING to slave= " << this_slave<< " JOB_FIRST= " << JOB_FIRST << " JOB_LAST= " << JOB_LAST
+								<< " JOB_NIMG= "<<JOB_NIMG<< " JOB_NPAR= "<<JOB_NPAR<< std::endl;
+#endif
+				node->relion_MPI_Send(MULTIDIM_ARRAY(first_last_nr_images), MULTIDIM_SIZE(first_last_nr_images), MPI_LONG, this_slave, MPITAG_JOB_REPLY, MPI_COMM_WORLD);
+
+				// Master also sends the required metadata and imagedata for this job
+				if (JOB_NIMG > 0)
+				{
+					node->relion_MPI_Send(MULTIDIM_ARRAY(exp_metadata), MULTIDIM_SIZE(exp_metadata), MPI_DOUBLE, this_slave, MPITAG_METADATA, MPI_COMM_WORLD);
+					node->relion_MPI_Send(MULTIDIM_ARRAY(exp_imagedata), MULTIDIM_SIZE(exp_imagedata), MPI_DOUBLE, this_slave, MPITAG_IMAGE, MPI_COMM_WORLD);
+				}
+
+				// Update the total number of particles that has been done already
+				nr_ori_particles_done += JOB_NPAR;
+				if (do_split_random_halves)
+				{
+					// Also update the number of particles that has been done for each subset
+					if (random_subset == 1)
+						nr_ori_particles_done_subset1 += JOB_NPAR;
+					else
+						nr_ori_particles_done_subset2 += JOB_NPAR;
+				}
+			}
+        }
+        catch (RelionError XE)
+        {
+            std::cerr << "master encountered error: " << XE;
+            MlOptimiser::usage();
+            MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
+        }
+
+    }
+    else
+    {
+
+    	try
+    	{
+			// Slaves do the real work (The slave does not need to know to which random_subset he belongs)
+
+			// Start off with an empty job request
+			JOB_FIRST = 0;
+			JOB_LAST = -1; // So that initial nr_particles (=JOB_LAST-JOB_FIRST+1) is zero!
+			JOB_NIMG = 0;
+			node->relion_MPI_Send(MULTIDIM_ARRAY(first_last_nr_images), MULTIDIM_SIZE(first_last_nr_images), MPI_LONG, 0, MPITAG_JOB_REQUEST, MPI_COMM_WORLD);
+
+			while (true)
+			{
+				//Receive a new bunch of particles
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(first_last_nr_images), MULTIDIM_SIZE(first_last_nr_images), MPI_LONG, 0, MPITAG_JOB_REPLY, MPI_COMM_WORLD, status);
+
+				//Check whether I am done
+				if (JOB_NIMG <= 0)
+				{
+#ifdef DEBUG
+					std::cerr <<" slave "<< node->rank << " has finished expectation.."<<std::endl;
+#endif
+					exp_imagedata.clear();
+					exp_metadata.clear();
+					break;
+				}
+				else
+				{
+					// Also receive the imagedata and the metadata for these images from the master
+					exp_metadata.resize(JOB_NIMG, METADATA_LINE_LENGTH);
+					if (has_converged && do_use_reconstruct_images)
+						exp_imagedata.resize(2*JOB_NIMG, mymodel.ori_size, mymodel.ori_size);
+					else
+						exp_imagedata.resize(JOB_NIMG, mymodel.ori_size, mymodel.ori_size);
+
+					node->relion_MPI_Recv(MULTIDIM_ARRAY(exp_metadata), MULTIDIM_SIZE(exp_metadata), MPI_DOUBLE, 0, MPITAG_METADATA, MPI_COMM_WORLD, status);
+					node->relion_MPI_Recv(MULTIDIM_ARRAY(exp_imagedata), MULTIDIM_SIZE(exp_imagedata), MPI_DOUBLE, 0, MPITAG_IMAGE, MPI_COMM_WORLD, status);
+
+					// Now process these images
+#ifdef DEBUG_MPIEXP
+					std::cerr << " SLAVE EXECUTING node->rank= " << node->rank << " JOB_FIRST= " << JOB_FIRST << " JOB_LAST= " << JOB_LAST << std::endl;
+#endif
+					expectationSomeParticles(JOB_FIRST, JOB_LAST);
+
+					// Report to the master how many particles I have processed
+					node->relion_MPI_Send(MULTIDIM_ARRAY(first_last_nr_images), MULTIDIM_SIZE(first_last_nr_images), MPI_LONG, 0, MPITAG_JOB_REQUEST, MPI_COMM_WORLD);
+					// Also send the metadata belonging to those
+					node->relion_MPI_Send(MULTIDIM_ARRAY(exp_metadata), MULTIDIM_SIZE(exp_metadata), MPI_DOUBLE, 0, MPITAG_METADATA, MPI_COMM_WORLD);
+				}
+
+			}
+    	}
+        catch (RelionError XE)
+        {
+            std::cerr << "slave "<< node->rank << " encountered error: " << XE;
+            MlOptimiser::usage();
+            MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
+        }
+
+    }
+
+    // Just make sure the temporary arrays are empty...
+	exp_imagedata.clear();
+	exp_metadata.clear();
+
+    progress_bar(mydata.numberOfOriginalParticles());
+
+#ifdef TIMING
+    // Measure how long I have to wait for the rest
+    timer.tic(TIMING_MPIWAIT);
+    node->barrierWait();
+    timer.toc(TIMING_MPIWAIT);
+    timer.tic(TIMING_MPIPACK);
+#endif
+
+	// Wait until expected angular errors have been calculated
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	// All slaves reset the size of their projector to zero tosave memory
+	if (!node->isMaster())
+	{
+		for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+			mymodel.PPref[iclass].initialiseData(0);
+	}
+
+
+#ifdef DEBUG
+	std::cerr << "MlOptimiserMpi::expectation: done" << std::endl;
+#endif
+
+}
+
+
+void MlOptimiserMpi::combineAllWeightedSumsViaFile()
+{
+
+	MultidimArray<double> Mpack;
+	FileName fn_pack;
+
+	int nr_subsets = (do_split_random_halves) ? 2 : 1;
+
+	// Only need to combine if there are more than one slaves per subset!
+	if ((node->size - 1)/nr_subsets > 1)
+	{
+		// A. First all slaves pack up their wsum_model (this is done simultaneously)
+		if (!node->isMaster())
+		{
+			wsum_model.pack(Mpack); // use negative piece and nr_pieces to only make a single Mpack, i.e. do not split into multiple pieces
+		}
+
+		// B. All slaves write their Mpack to disc. Do this SEQUENTIALLY to prevent heavy load on disc I/O
+		for (int this_slave = 1; this_slave < node->size; this_slave++ )
+		{
+			if (this_slave == node->rank)
+			{
+				fn_pack.compose(fn_out+"_rank", node->rank, "tmp");
+				if (fn_scratch != "")
+					fn_pack = fn_scratch + "/" + fn_pack;
+				Mpack.writeBinary(fn_pack);
+				//std::cerr << "Rank "<< node->rank <<" has written: "<<fn_pack << " sum= "<<Mpack.sum()<< std::endl;
+			}
+			MPI_Barrier(MPI_COMM_WORLD);
+		}
+
+		// C. First slave of each subset reads all other slaves' Mpack; sum; and write sum to disc
+		// Again, do this SEQUENTIALLY to prevent heavy load on disc I/O
+		for (int first_slave = 1; first_slave <= nr_subsets; first_slave++)
+		{
+			if (node->rank == first_slave)
+			{
+				for (int other_slave = first_slave + nr_subsets; other_slave < node->size; other_slave+= nr_subsets )
+				{
+					fn_pack.compose(fn_out+"_rank", other_slave, "tmp");
+					if (fn_scratch != "")
+						fn_pack = fn_scratch + "/" + fn_pack;
+					Mpack.readBinaryAndSum(fn_pack);
+					//std::cerr << "Slave "<<node->rank<<" has read "<<fn_pack<< " sum= "<<Mpack.sum() << std::endl;
+				}
+				// After adding all Mpacks together: write the sum to disc
+				fn_pack.compose(fn_out+"_rank", node->rank, "tmp");
+				if (fn_scratch != "")
+					fn_pack = fn_scratch + "/" + fn_pack;
+				Mpack.writeBinary(fn_pack);
+				//std::cerr << "Slave "<<node->rank<<" is writing total SUM in "<<fn_pack << std::endl;
+			}
+			MPI_Barrier(MPI_COMM_WORLD);
+		}
+
+
+		// D. All other slaves read the summed Mpack from their first_slave
+		// Again, do this SEQUENTIALLY to prevent heavy load on disc I/O
+		for (int this_slave = nr_subsets + 1; this_slave < node->size; this_slave++ )
+		{
+			if (this_slave == node->rank)
+			{
+				// Find out who is the first slave in this subset
+				int first_slave;
+				if (!do_split_random_halves)
+					first_slave = 1;
+				else
+					first_slave = (this_slave % 2 == 1) ? 1 : 2;
+
+				// Read the corresponding Mpack (which now contains the sum of all Mpacks)
+				fn_pack.compose(fn_out+"_rank", first_slave, "tmp");
+				if (fn_scratch != "")
+					fn_pack = fn_scratch + "/" + fn_pack;
+				Mpack.readBinary(fn_pack);
+				//std::cerr << "Rank "<< node->rank <<" has read: "<<fn_pack << " sum= "<<Mpack.sum()<< std::endl;
+			}
+			MPI_Barrier(MPI_COMM_WORLD);
+		}
+
+		// E. All slaves delete their own temporary file
+		// Again, do this SEQUENTIALLY to prevent heavy load on disc I/O
+		for (int this_slave = 1; this_slave < node->size; this_slave++ )
+		{
+			if (this_slave == node->rank)
+			{
+				fn_pack.compose(fn_out+"_rank", node->rank, "tmp");
+				if (fn_scratch != "")
+					fn_pack = fn_scratch + "/" + fn_pack;
+				remove((fn_pack).c_str());
+				//std::cerr << "Rank "<< node->rank <<" has deleted: "<<fn_pack << std::endl;
+			}
+			MPI_Barrier(MPI_COMM_WORLD);
+		}
+
+		// F. Finally all slaves unpack Msum into their wsum_model (do this simultaneously)
+		if (!node->isMaster())
+			wsum_model.unpack(Mpack);
+
+	} // end if ((node->size - 1)/nr_subsets > 1)
+
+}
+
+void MlOptimiserMpi::combineAllWeightedSums()
+{
+
+	// Pack all weighted sums in Mpack
+	MultidimArray<double> Mpack, Msum;
+	MPI_Status status;
+
+	// First slave manually sums over all other slaves of it's subset
+	// And then sends results back to all those slaves
+	// When splitting the data into two random halves, perform two passes: one for each subset
+	int nr_subsets = (do_split_random_halves) ? 2 : 1;
+
+	// Only combine weighted sums if there are more than one slaves per subset!
+	if ((node->size - 1)/nr_subsets > 1)
+	{
+		// Loop over possibly multiple instances of Mpack of maximum size
+		int piece = 0;
+		int nr_pieces = 1;
+		long int pack_size;
+		while (piece < nr_pieces)
+		{
+			// All nodes except those who will reset nr_pieces piece will pass while loop in next pass
+			nr_pieces = 0;
+
+			// First all slaves pack up their wsum_model
+			if (!node->isMaster())
+			{
+				wsum_model.pack(Mpack, piece, nr_pieces);
+				// The first slave(s) set Msum equal to Mpack, the others initialise to zero
+				if (node->rank <= nr_subsets)
+					Msum = Mpack;
+				else
+					Msum.initZeros(Mpack);
+			}
+
+
+			// Loop through all slaves: each slave sends its Msum to the next slave for its subset.
+			// Each next slave sums its own Mpack to the received Msum and sends it on to the next slave
+
+			for (int this_slave = 1; this_slave < node->size; this_slave++ )
+			{
+				// Find out who is the first slave in this subset
+				int first_slave;
+				if (!do_split_random_halves)
+					first_slave = 1;
+				else
+					first_slave = (this_slave % 2 == 1) ? 1 : 2;
+
+				// Find out who is the next slave in this subset
+				int other_slave = this_slave + nr_subsets;
+
+				if (other_slave < node->size)
+				{
+					if (node->rank == this_slave)
+					{
+#ifdef DEBUG
+						std::cerr << " AA SEND node->rank= " << node->rank << " MULTIDIM_SIZE(Msum)= "<< MULTIDIM_SIZE(Msum)
+								<< " this_slave= " << this_slave << " other_slave= "<<other_slave << std::endl;
+#endif
+						node->relion_MPI_Send(MULTIDIM_ARRAY(Msum), MULTIDIM_SIZE(Msum), MPI_DOUBLE, other_slave, MPITAG_PACK, MPI_COMM_WORLD);
+					}
+					else if (node->rank == other_slave)
+					{
+						MPI_Recv(MULTIDIM_ARRAY(Msum), MULTIDIM_SIZE(Msum), MPI_DOUBLE, this_slave, MPITAG_PACK, MPI_COMM_WORLD, &status);
+#ifdef DEBUG
+						std::cerr << " AA RECV node->rank= " << node->rank  << " MULTIDIM_SIZE(Msum)= "<< MULTIDIM_SIZE(Msum)
+								<< " this_slave= " << this_slave << " other_slave= "<<other_slave << std::endl;
+#endif
+						// Add my own Mpack to send onwards in the next step
+						Msum += Mpack;
+					}
+				}
+				else
+				{
+					// Now this_slave has reached the last slave, which passes the final Msum to the first one (i.e. first_slave)
+					if (node->rank == this_slave)
+					{
+#ifdef DEBUG
+						std::cerr << " BB SEND node->rank= " << node->rank  << " MULTIDIM_SIZE(Msum)= "<< MULTIDIM_SIZE(Msum)
+								<< " this_slave= " << this_slave << " first_slave= "<<first_slave << std::endl;
+#endif
+						node->relion_MPI_Send(MULTIDIM_ARRAY(Msum), MULTIDIM_SIZE(Msum), MPI_DOUBLE, first_slave, MPITAG_PACK, MPI_COMM_WORLD);
+					}
+					else if (node->rank == first_slave)
+					{
+						node->relion_MPI_Recv(MULTIDIM_ARRAY(Msum), MULTIDIM_SIZE(Msum), MPI_DOUBLE, this_slave, MPITAG_PACK, MPI_COMM_WORLD, status);
+#ifdef DEBUG
+						std::cerr << " BB RECV node->rank= " << node->rank  << " MULTIDIM_SIZE(Msum)= "<< MULTIDIM_SIZE(Msum)
+								<< " this_slave= " << this_slave << " first_slave= "<<first_slave << std::endl;
+#endif
+					}
+				}
+			} // end for this_slave
+
+			// Now loop through all slaves again to pass around the Msum
+			for (int this_slave = 1; this_slave < node->size; this_slave++ )
+			{
+				// Find out who is the next slave in this subset
+				int other_slave = this_slave + nr_subsets;
+
+				// Do not send to the last slave, because it already had its Msum from the cycle above, therefore subtract nr_subsets from node->size
+				if (other_slave < node->size - nr_subsets)
+				{
+					if (node->rank == this_slave)
+					{
+#ifdef DEBUG
+						std::cerr << " CC SEND node->rank= " << node->rank << " MULTIDIM_SIZE(Msum)= "<< MULTIDIM_SIZE(Msum)
+								<< " this_slave= " << this_slave << " other_slave= "<<other_slave << std::endl;
+#endif
+						node->relion_MPI_Send(MULTIDIM_ARRAY(Msum), MULTIDIM_SIZE(Msum), MPI_DOUBLE, other_slave, MPITAG_PACK, MPI_COMM_WORLD);
+					}
+					else if (node->rank == other_slave)
+					{
+						node->relion_MPI_Recv(MULTIDIM_ARRAY(Msum), MULTIDIM_SIZE(Msum), MPI_DOUBLE, this_slave, MPITAG_PACK, MPI_COMM_WORLD, status);
+#ifdef DEBUG
+						std::cerr << " CC RECV node->rank= " << node->rank << " MULTIDIM_SIZE(Msum)= "<< MULTIDIM_SIZE(Msum)
+								<< " this_slave= " << this_slave << " other_slave= "<<other_slave << std::endl;
+#endif
+					}
+				}
+			} // end for this_slave
+
+
+			// Finally all slaves unpack Msum into their wsum_model
+			if (!node->isMaster())
+			{
+				// Subtract 1 from piece because it was incremented already...
+				wsum_model.unpack(Msum, piece - 1);
+			}
+
+
+		} // end for piece
+
+		MPI_Barrier(MPI_COMM_WORLD);
+	}
+
+
+}
+
+void MlOptimiserMpi::combineWeightedSumsTwoRandomHalvesViaFile()
+{
+	// Just sum the weighted halves from slave 1 and slave 2 and Bcast to everyone else
+	if (!do_split_random_halves)
+		REPORT_ERROR("MlOptimiserMpi::combineWeightedSumsTwoRandomHalvesViaFile BUG: you cannot combineWeightedSumsTwoRandomHalves if you have not split random halves");
+
+	MultidimArray<double> Mpack;
+	FileName fn_pack = fn_out + ".tmp";
+	if (fn_scratch != "")
+		fn_pack = fn_scratch + "/" + fn_pack;
+
+	// Everyone packs up his wsum_model (simultaneously)
+	// The slaves from 3 and onwards also need this in order to have the correct Mpack size to be able to read in the summed Mpack
+	if (!node->isMaster())
+		wsum_model.pack(Mpack);
+
+	// Rank 2 writes it Mpack to file
+	if (node->rank == 2)
+	{
+		Mpack.writeBinary(fn_pack);
+		//std::cerr << "Rank "<< node->rank <<" has written: "<<fn_pack << " sum= "<<Mpack.sum()<< std::endl;
+	}
+
+	// Wait until rank2 is ready
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	// Now rank1 reads the file of rank2 and adds it to its own Mpack and (over)write the sum to disc
+	if (node->rank == 1)
+	{
+		Mpack.readBinaryAndSum(fn_pack);
+		Mpack.writeBinary(fn_pack);
+	}
+
+	// Now all slaves read the sum and unpack
+	// Do this sequentially in order not to have very heavy disc I/O
+	for (int this_slave = 2; this_slave < node->size; this_slave++)
+	{
+		if (node->rank == this_slave)
+			Mpack.readBinary(fn_pack);
+		MPI_Barrier(MPI_COMM_WORLD);
+	}
+
+	// Remove temporary file
+	if (node->rank == 1)
+		remove(fn_pack.c_str());
+
+	// Then everyone except the master unpacks
+	if (!node->isMaster())
+		wsum_model.unpack(Mpack);
+
+}
+
+void MlOptimiserMpi::combineWeightedSumsTwoRandomHalves()
+{
+	// Just sum the weighted halves from slave 1 and slave 2 and Bcast to everyone else
+	if (!do_split_random_halves)
+		REPORT_ERROR("MlOptimiserMpi::combineWeightedSumsTwoRandomHalves BUG: you cannot combineWeightedSumsTwoRandomHalves if you have not split random halves");
+
+	MultidimArray<double> Mpack, Msum;
+	MPI_Status status;
+
+	int piece = 0;
+	int nr_pieces = 1;
+	long int pack_size;
+	while (piece < nr_pieces)
+	{
+		// All nodes except those who will reset nr_pieces will pass while next time
+		nr_pieces = 0;
+
+		if (node->rank == 2)
+		{
+			wsum_model.pack(Mpack, piece, nr_pieces, false); // do not clear the model!
+			node->relion_MPI_Send(MULTIDIM_ARRAY(Mpack), MULTIDIM_SIZE(Mpack), MPI_DOUBLE, 1, MPITAG_PACK, MPI_COMM_WORLD);
+			Mpack.clear();
+		}
+		else if (node->rank == 1)
+		{
+			std::cout << " Combining two random halves ..."<< std::endl;
+			wsum_model.pack(Mpack, piece, nr_pieces);
+			Msum.initZeros(Mpack);
+			node->relion_MPI_Recv(MULTIDIM_ARRAY(Msum), MULTIDIM_SIZE(Msum), MPI_DOUBLE, 2, MPITAG_PACK, MPI_COMM_WORLD, status);
+			Msum += Mpack;
+			// Unpack the sum (subtract 1 from piece because it was incremented already...)
+			wsum_model.unpack(Msum, piece - 1);
+			Msum.clear();
+			Mpack.clear();
+		}
+	}
+
+	// Now slave 1 has the sum of the two halves
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	// Bcast to everyone
+	piece = 0;
+	nr_pieces = 1;
+	while (piece < nr_pieces)
+	{
+
+		// All nodes except those who will reset nr_pieces will pass while next time
+		nr_pieces = 0;
+
+		// The master does not have a wsum_model!
+		if (!node->isMaster())
+		{
+			// Let's have everyone repack their Mpack, so we know the size etc
+			wsum_model.pack(Mpack, piece, nr_pieces);
+
+			// rank one sends Mpack to everyone else
+			if (node->rank == 1)
+			{
+				for (int other_slave = 2; other_slave < node->size; other_slave++)
+					node->relion_MPI_Send(MULTIDIM_ARRAY(Mpack), MULTIDIM_SIZE(Mpack), MPI_DOUBLE, other_slave, MPITAG_PACK, MPI_COMM_WORLD);
+			}
+			else
+			{
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(Mpack), MULTIDIM_SIZE(Mpack), MPI_DOUBLE, 1, MPITAG_PACK, MPI_COMM_WORLD, status);
+			}
+
+			// Everyone unpacks the new Mpack
+			wsum_model.unpack(Mpack, piece - 1);
+			Mpack.clear();
+
+		}
+
+	}
+
+}
+
+void MlOptimiserMpi::maximization()
+{
+#ifdef DEBUG
+	std::cerr << "MlOptimiserMpi::maximization: Entering " << std::endl;
+#endif
+
+#ifdef TIMING
+		timer.tic(TIMING_RECONS);
+#endif
+
+	if (verb > 0)
+	{
+		std::cout << " Maximization ..."<< std::endl;
+		init_progress_bar(mymodel.nr_classes);
+	}
+
+
+	// First reconstruct all classes in parallel
+	for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+    {
+		if (mymodel.pdf_class[iclass] > 0.)
+		{
+			// Parallelise: each MPI-node has a different reference
+
+			// The code below will NOT work if nr_classes > 1 AND do_split_random_halves, but that is disabled anyway...
+			// Master does not participate in reconstruction tasks
+			int reconstruct_rank1 = (iclass % (node->size - 1) ) + 1;
+			//std::cerr << " size00 " <<  MULTIDIM_SIZE(mymodel.Iref[0]) << " rank= "<<node->rank << " iclass= "<<iclass << std::endl;
+			if (node->rank == reconstruct_rank1)
+			{
+				wsum_model.BPref[iclass].reconstruct(mymodel.Iref[iclass], gridding_nr_iter, do_map,
+						mymodel.tau2_fudge_factor, mymodel.tau2_class[iclass], mymodel.sigma2_class[iclass],
+						mymodel.data_vs_prior_class[iclass], mymodel.fsc_halves_class[iclass], wsum_model.pdf_class[iclass],
+						do_split_random_halves, (do_join_random_halves || do_always_join_random_halves), nr_threads, minres_map);
+
+				// Also perform the unregularized reconstruction
+				if (do_auto_refine && has_converged)
+					readTemporaryDataAndWeightArraysAndReconstruct(iclass, 1);
+
+			}
+			//std::cerr << " size01 " <<  MULTIDIM_SIZE(mymodel.Iref[0]) << " rank= "<<node->rank << " iclass= "<<iclass << std::endl;
+			// In some cases there is not enough memory to reconstruct two random halves in parallel
+			// Therefore the following option exists to perform them sequentially
+			if (do_sequential_halves_recons)
+				MPI_Barrier(MPI_COMM_WORLD);
+
+			// When splitting the data into two random halves, perform two reconstructions in parallel: one for each subset
+			if (do_split_random_halves)
+			{
+				int reconstruct_rank2 =(iclass % (node->size - 1) ) + 2;
+
+				if (node->rank == reconstruct_rank2)
+				{
+					// Rank 2 does not need to do the joined reconstruction
+					if (!do_join_random_halves)
+						wsum_model.BPref[iclass].reconstruct(mymodel.Iref[iclass], gridding_nr_iter, do_map,
+								mymodel.tau2_fudge_factor, mymodel.tau2_class[iclass], mymodel.sigma2_class[iclass],
+								mymodel.data_vs_prior_class[iclass], mymodel.fsc_halves_class[iclass], wsum_model.pdf_class[iclass],
+								do_split_random_halves, do_join_random_halves, nr_threads, minres_map);
+
+					// But rank 2 always does the unfiltered reconstruction
+					if (do_auto_refine && has_converged)
+						readTemporaryDataAndWeightArraysAndReconstruct(iclass, 2);
+
+				}
+			}
+
+		} // endif pdf_class[iclass] > 0.
+		else
+		{
+			mymodel.Iref[iclass].initZeros();
+		}
+
+//#define DEBUG_RECONSTRUCT
+#ifdef DEBUG_RECONSTRUCT
+		MPI_Barrier( MPI_COMM_WORLD);
+#endif
+    }
+
+#ifdef DEBUG
+	std::cerr << "rank= "<<node->rank<<" has reached barrier of reconstruction" << std::endl;
+#endif
+	MPI_Barrier(MPI_COMM_WORLD);
+
+#ifdef DEBUG
+	std::cerr << "All classes have been reconstructed" << std::endl;
+#endif
+
+	// Once reconstructed, broadcast new models to all other nodes
+	// This cannot be done in the reconstruction loop itself because then it will be executed sequentially
+	for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+	{
+
+		if (do_split_random_halves && !do_join_random_halves)
+		{
+			MPI_Status status;
+			// Make sure I am sending from the rank where the reconstruction was done (see above) to all other slaves of this subset
+			// Loop twice through this, as each class was reconstructed by two different slaves!!
+			int nr_subsets = 2;
+			for (int isubset = 1; isubset <= nr_subsets; isubset++)
+			{
+				if (node->myRandomSubset() == isubset)
+				{
+					int reconstruct_rank = (iclass % (node->size - 1) ) + isubset; // first pass subset1, second pass subset2
+					int my_first_recv = node->myRandomSubset();
+
+					for (int recv_node = my_first_recv; recv_node < node->size; recv_node += nr_subsets)
+					{
+						if (node->rank == reconstruct_rank && recv_node != node->rank)
+						{
+#ifdef DEBUG
+							std::cerr << "isubset= "<<isubset<<" Sending iclass="<<iclass<<" from node "<<reconstruct_rank<<" to node "<<recv_node << std::endl;
+#endif
+							node->relion_MPI_Send(MULTIDIM_ARRAY(mymodel.Iref[iclass]), MULTIDIM_SIZE(mymodel.Iref[iclass]), MPI_DOUBLE, recv_node, MPITAG_IMAGE, MPI_COMM_WORLD);
+							node->relion_MPI_Send(MULTIDIM_ARRAY(mymodel.data_vs_prior_class[iclass]), MULTIDIM_SIZE(mymodel.data_vs_prior_class[iclass]), MPI_DOUBLE, recv_node, MPITAG_METADATA, MPI_COMM_WORLD);
+							node->relion_MPI_Send(MULTIDIM_ARRAY(mymodel.sigma2_class[iclass]), MULTIDIM_SIZE(mymodel.sigma2_class[iclass]), MPI_DOUBLE, recv_node, MPITAG_DOUBLE, MPI_COMM_WORLD);
+							node->relion_MPI_Send(MULTIDIM_ARRAY(mymodel.fsc_halves_class[iclass]), MULTIDIM_SIZE(mymodel.fsc_halves_class[iclass]), MPI_DOUBLE, recv_node, MPITAG_RANDOMSEED, MPI_COMM_WORLD);
+						}
+						else if (node->rank != reconstruct_rank && node->rank == recv_node)
+						{
+							//std::cerr << "isubset= "<<isubset<< " Receiving iclass="<<iclass<<" from node "<<reconstruct_rank<<" at node "<<node->rank<< std::endl;
+							node->relion_MPI_Recv(MULTIDIM_ARRAY(mymodel.Iref[iclass]), MULTIDIM_SIZE(mymodel.Iref[iclass]), MPI_DOUBLE, reconstruct_rank, MPITAG_IMAGE, MPI_COMM_WORLD, status);
+							node->relion_MPI_Recv(MULTIDIM_ARRAY(mymodel.data_vs_prior_class[iclass]), MULTIDIM_SIZE(mymodel.data_vs_prior_class[iclass]), MPI_DOUBLE, reconstruct_rank, MPITAG_METADATA, MPI_COMM_WORLD, status);
+							node->relion_MPI_Recv(MULTIDIM_ARRAY(mymodel.sigma2_class[iclass]), MULTIDIM_SIZE(mymodel.sigma2_class[iclass]), MPI_DOUBLE, reconstruct_rank, MPITAG_DOUBLE, MPI_COMM_WORLD, status);
+							node->relion_MPI_Recv(MULTIDIM_ARRAY(mymodel.fsc_halves_class[iclass]), MULTIDIM_SIZE(mymodel.fsc_halves_class[iclass]), MPI_DOUBLE, reconstruct_rank, MPITAG_RANDOMSEED, MPI_COMM_WORLD, status);
+#ifdef DEBUG
+							std::cerr << "isubset= "<<isubset<< " Received!!!="<<iclass<<" from node "<<reconstruct_rank<<" at node "<<node->rank<< std::endl;
+#endif
+						}
+					}
+
+				}
+			}
+			// No one should continue until we're all here
+			MPI_Barrier(MPI_COMM_WORLD);
+
+			// Now all slaves have all relevant reconstructions
+			// TODO: someone should also send reconstructions to the master (for comparison with other subset?)
+
+		}
+		else
+		{
+			int reconstruct_rank = (iclass % (node->size - 1) ) + 1;
+			// Broadcast the reconstructed references to all other MPI nodes
+			node->relion_MPI_Bcast(MULTIDIM_ARRAY(mymodel.Iref[iclass]),
+					MULTIDIM_SIZE(mymodel.Iref[iclass]), MPI_DOUBLE, reconstruct_rank, MPI_COMM_WORLD);
+			// Broadcast the data_vs_prior spectra to all other MPI nodes
+			node->relion_MPI_Bcast(MULTIDIM_ARRAY(mymodel.data_vs_prior_class[iclass]),
+					MULTIDIM_SIZE(mymodel.data_vs_prior_class[iclass]), MPI_DOUBLE, reconstruct_rank, MPI_COMM_WORLD);
+			// Broadcast the sigma2_class spectra to all other MPI nodes
+			node->relion_MPI_Bcast(MULTIDIM_ARRAY(mymodel.sigma2_class[iclass]),
+					MULTIDIM_SIZE(mymodel.sigma2_class[iclass]), MPI_DOUBLE, reconstruct_rank, MPI_COMM_WORLD);
+
+		}
+
+		// Re-set the origin (this may be lost in some cases??)
+		mymodel.Iref[iclass].setXmippOrigin();
+	}
+#ifdef TIMING
+		timer.toc(TIMING_RECONS);
+#endif
+
+	if (node->isMaster())
+	{
+		// If we're realinging movies then the master needs to update the priors
+		// These will then be re-distributed to the slaves in the expectation step (through get/setMetadataSubset)
+		// Switch this off, as we're only doing a single round of movie processing anyway!
+		//if (do_realign_movies)
+		//	updatePriorsForMovieFrames();
+
+		// The master also updates the changes in hidden variables
+		updateOverallChangesInHiddenVariables();
+	}
+	else
+	{
+		// Now do the maximisation of all other parameters (and calculate the tau2_class-spectra of the reconstructions
+		// The lazy master never does this: it only handles metadata and does not have the weighted sums
+		maximizationOtherParameters();
+	}
+
+	// The master broadcasts the changes in hidden variables to all other nodes
+	node->relion_MPI_Bcast(&current_changes_optimal_classes, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
+	node->relion_MPI_Bcast(&current_changes_optimal_orientations, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
+	node->relion_MPI_Bcast(&current_changes_optimal_offsets, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
+	node->relion_MPI_Bcast(&nr_iter_wo_large_hidden_variable_changes, 1, MPI_INT, 0, MPI_COMM_WORLD);
+	node->relion_MPI_Bcast(&smallest_changes_optimal_classes, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
+	node->relion_MPI_Bcast(&smallest_changes_optimal_offsets, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
+	node->relion_MPI_Bcast(&smallest_changes_optimal_orientations, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
+
+	if (verb > 0)
+		progress_bar(mymodel.nr_classes);
+
+#ifdef DEBUG
+	std::cerr << "MlOptimiserMpi::maximization: done" << std::endl;
+#endif
+
+}
+
+void MlOptimiserMpi::joinTwoHalvesAtLowResolution()
+{
+#ifdef DEBUG
+	std::cerr << "MlOptimiserMpi::joinTwoHalvesAtLowResolution: Entering " << std::endl;
+#endif
+
+	if (!do_split_random_halves)
+		REPORT_ERROR("BUG: you should not be in MlOptimiserMpi::joinTwoHalvesAtLowResolution!");
+
+	// Loop over all classes (this will be just one class for now...)
+	double myres = XMIPP_MAX(low_resol_join_halves, 1./mymodel.current_resolution);
+	int lowres_r_max = CEIL(mymodel.ori_size * mymodel.pixel_size / myres);
+
+	for (int iclass = 0; iclass < mymodel.nr_classes; iclass++ )
+	{
+		if (node->rank == 1 || node->rank == 2)
+		{
+			MultidimArray<Complex > lowres_data;
+			MultidimArray<double > lowres_weight;
+			wsum_model.BPref[iclass].getLowResDataAndWeight(lowres_data, lowres_weight, lowres_r_max);
+
+			if (node->rank == 2)
+			{
+				MPI_Status status;
+
+				// The second slave sends its lowres_data and lowres_weight to the first slave
+				node->relion_MPI_Send(MULTIDIM_ARRAY(lowres_data), 2*MULTIDIM_SIZE(lowres_data), MPI_DOUBLE, 1, MPITAG_IMAGE, MPI_COMM_WORLD);
+				node->relion_MPI_Send(MULTIDIM_ARRAY(lowres_weight), MULTIDIM_SIZE(lowres_weight), MPI_DOUBLE, 1, MPITAG_DOUBLE, MPI_COMM_WORLD);
+
+				// Now the first slave is calculating the average....
+
+				// Then the second slave receives the average back from the first slave
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(lowres_data), 2*MULTIDIM_SIZE(lowres_data), MPI_DOUBLE, 1, MPITAG_IMAGE, MPI_COMM_WORLD, status);
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(lowres_weight), MULTIDIM_SIZE(lowres_weight), MPI_DOUBLE, 1, MPITAG_DOUBLE, MPI_COMM_WORLD, status);
+
+
+			}
+			else if (node->rank == 1)
+			{
+
+				std::cout << " Averaging half-reconstructions up to " << myres << " Angstrom resolution to prevent diverging orientations ..." << std::endl;
+				std::cout << " Note that only for higher resolutions the FSC-values are according to the gold-standard!" << std::endl;
+				MPI_Status status;
+				MultidimArray<Complex > lowres_data_half2;
+				MultidimArray<double > lowres_weight_half2;
+				lowres_data_half2.resize(lowres_data);
+				lowres_weight_half2.resize(lowres_weight);
+#ifdef DEBUG
+				std::cerr << "AAArank=1 lowresdata: "; lowres_data.printShape();
+				std::cerr << "AAArank=1 lowresdata_half2: "; lowres_data_half2.printShape();
+#endif
+				// The first slave receives the average from the second slave
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(lowres_data_half2), 2*MULTIDIM_SIZE(lowres_data_half2), MPI_DOUBLE, 2, MPITAG_IMAGE, MPI_COMM_WORLD, status);
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(lowres_weight_half2), MULTIDIM_SIZE(lowres_weight_half2), MPI_DOUBLE, 2, MPITAG_DOUBLE, MPI_COMM_WORLD, status);
+
+				// The first slave calculates the average of the two lowres_data and lowres_weight arrays
+#ifdef DEBUG
+				std::cerr << "BBBrank=1 lowresdata: "; lowres_data.printShape();
+				std::cerr << "BBBrank=1 lowresdata_half2: "; lowres_data_half2.printShape();
+#endif
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(lowres_data)
+				{
+					DIRECT_MULTIDIM_ELEM(lowres_data, n)   += DIRECT_MULTIDIM_ELEM(lowres_data_half2, n) ;
+					DIRECT_MULTIDIM_ELEM(lowres_data, n)   /= 2.;
+					DIRECT_MULTIDIM_ELEM(lowres_weight, n) += DIRECT_MULTIDIM_ELEM(lowres_weight_half2, n) ;
+					DIRECT_MULTIDIM_ELEM(lowres_weight, n) /= 2.;
+				}
+
+				// The first slave sends the average lowres_data and lowres_weight also back to the second slave
+				node->relion_MPI_Send(MULTIDIM_ARRAY(lowres_data), 2*MULTIDIM_SIZE(lowres_data), MPI_DOUBLE, 2, MPITAG_IMAGE, MPI_COMM_WORLD);
+				node->relion_MPI_Send(MULTIDIM_ARRAY(lowres_weight), MULTIDIM_SIZE(lowres_weight), MPI_DOUBLE, 2, MPITAG_DOUBLE, MPI_COMM_WORLD);
+
+			}
+
+			// Now that both slaves have the average lowres arrays, set them back into the backprojector
+			wsum_model.BPref[iclass].setLowResDataAndWeight(lowres_data, lowres_weight, lowres_r_max);
+		}
+	}
+
+
+#ifdef DEBUG
+	std::cerr << "MlOptimiserMpi::joinTwoHalvesAtLowResolution: done" << std::endl;
+#endif
+
+}
+
+void MlOptimiserMpi::writeTemporaryDataAndWeightArrays()
+{
+
+	if (mymodel.ref_dim == 3 && (node->rank == 1 || (do_split_random_halves && node->rank == 2) ) )
+	{
+		Image<double> It;
+		FileName fn_root = fn_out + "_half" + integerToString(node->rank);;
+
+		// Write out temporary arrays for all classes
+		for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+		{
+			FileName fn_tmp;
+			fn_tmp.compose(fn_root+"_class", iclass+1, "", 3);
+			if (mymodel.pdf_class[iclass] > 0.)
+			{
+				It().resize(wsum_model.BPref[iclass].data);
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(It())
+				{
+					DIRECT_MULTIDIM_ELEM(It(), n) = (DIRECT_MULTIDIM_ELEM(wsum_model.BPref[iclass].data, n)).real;
+				}
+				It.write(fn_tmp+"_data_real.mrc");
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(It())
+				{
+					DIRECT_MULTIDIM_ELEM(It(), n) = (DIRECT_MULTIDIM_ELEM(wsum_model.BPref[iclass].data, n)).imag;
+				}
+				It.write(fn_tmp+"_data_imag.mrc");
+				It()=wsum_model.BPref[iclass].weight;
+				It.write(fn_tmp+"_weight.mrc");
+			}
+		}
+    }
+
+}
+
+void MlOptimiserMpi::readTemporaryDataAndWeightArraysAndReconstruct(int iclass, int ihalf)
+{
+	if (mymodel.ref_dim == 3)
+	{
+		MultidimArray<double> dummy;
+		Image<double> Iunreg, Itmp;
+		FileName fn_root = fn_out + "_half" + integerToString(ihalf);;
+		fn_root.compose(fn_root+"_class", iclass+1, "", 3);
+
+		// Read temporary arrays back in
+		Itmp.read(fn_root+"_data_real.mrc");
+		Itmp().setXmippOrigin();
+		Itmp().xinit=0;
+		if (!Itmp().sameShape(wsum_model.BPref[iclass].data))
+		{
+			wsum_model.BPref[iclass].data.printShape(std::cerr);
+			Itmp().printShape(std::cerr);
+			REPORT_ERROR("Incompatible size of "+fn_root+"_data_real.mrc");
+		}
+		FOR_ALL_ELEMENTS_IN_ARRAY3D(Itmp())
+		{
+			A3D_ELEM(wsum_model.BPref[iclass].data, k, i, j).real = A3D_ELEM(Itmp(), k, i, j);
+		}
+
+		Itmp.read(fn_root+"_data_imag.mrc");
+		Itmp().setXmippOrigin();
+		Itmp().xinit=0;
+		if (!Itmp().sameShape(wsum_model.BPref[iclass].data))
+		{
+			wsum_model.BPref[iclass].data.printShape(std::cerr);
+			Itmp().printShape(std::cerr);
+			REPORT_ERROR("Incompatible size of "+fn_root+"_data_imag.mrc");
+		}
+		FOR_ALL_ELEMENTS_IN_ARRAY3D(Itmp())
+		{
+			A3D_ELEM(wsum_model.BPref[iclass].data, k, i, j).imag = A3D_ELEM(Itmp(), k, i, j);
+		}
+
+		Itmp.read(fn_root+"_weight.mrc");
+		Itmp().setXmippOrigin();
+		Itmp().xinit=0;
+		if (!Itmp().sameShape(wsum_model.BPref[iclass].weight))
+		{
+			wsum_model.BPref[iclass].weight.printShape(std::cerr);
+			Itmp().printShape(std::cerr);
+			REPORT_ERROR("Incompatible size of "+fn_root+"_weight.mrc");
+		}
+		FOR_ALL_ELEMENTS_IN_ARRAY3D(Itmp())
+		{
+			A3D_ELEM(wsum_model.BPref[iclass].weight, k, i, j) = A3D_ELEM(Itmp(), k, i, j);
+		}
+
+		// Now perform the unregularized reconstruction
+		wsum_model.BPref[iclass].reconstruct(Iunreg(), gridding_nr_iter, false, 1., dummy, dummy, dummy, dummy, 1., false, true, nr_threads, -1);
+
+		// Update header information
+		double avg, stddev, minval, maxval;
+	    Iunreg().computeStats(avg, stddev, minval, maxval);
+	    Iunreg.MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN, minval);
+	    Iunreg.MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX, maxval);
+	    Iunreg.MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG, avg);
+	    Iunreg.MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV, stddev);
+		Iunreg.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_X, mymodel.pixel_size);
+		Iunreg.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Y, mymodel.pixel_size);
+		Iunreg.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Z, mymodel.pixel_size);
+		// And write the resulting model to disc
+		Iunreg.write(fn_root+"_unfil.mrc");
+
+
+		// remove temporary arrays from the disc
+		remove((fn_root+"_data_real.mrc").c_str());
+		remove((fn_root+"_data_imag.mrc").c_str());
+		remove((fn_root+"_weight.mrc").c_str());
+	}
+}
+
+void MlOptimiserMpi::compareTwoHalves()
+{
+#ifdef DEBUG
+	std::cerr << "MlOptimiserMpi::compareTwoHalves: Entering " << std::endl;
+#endif
+
+	if (!do_split_random_halves)
+		REPORT_ERROR("ERROR: you should not be in MlOptimiserMpi::compareTwoHalves!");
+
+	// Loop over all classes
+	for (int iclass = 0; iclass < mymodel.nr_classes; iclass++ )
+	{
+		if (node->rank == 1 || node->rank == 2)
+		{
+
+			// The first two slaves calculate the downsampled average
+			MultidimArray<Complex > avg1;
+			wsum_model.BPref[iclass].getDownsampledAverage(avg1);
+//#define DEBUG_FSC
+#ifdef DEBUG_FSC
+			MultidimArray<Complex > avg;
+			MultidimArray<double> Mavg;
+			Mavg.resize(mymodel.ori_size, mymodel.ori_size, mymodel.ori_size);
+			FourierTransformer transformer_debug;
+			transformer_debug.setReal(Mavg);
+			transformer_debug.getFourierAlias(avg);
+			wsum_model.BPref[0].decenter(avg1,avg, wsum_model.BPref[0].r_max * wsum_model.BPref[0].r_max);
+			transformer_debug.inverseFourierTransform();
+			FileName fnt;
+			fnt.compose("downsampled_avg_half",node->rank,"spi");
+			Image<double> It;
+			CenterFFT(Mavg, true);
+			It()=Mavg;
+			It.write(fnt);
+#endif
+			if (node->rank == 2)
+			{
+				// The second slave sends its average to the first slave
+				node->relion_MPI_Send(MULTIDIM_ARRAY(avg1), 2*MULTIDIM_SIZE(avg1), MPI_DOUBLE, 1, MPITAG_IMAGE, MPI_COMM_WORLD);
+			}
+			else if (node->rank == 1)
+			{
+
+				std::cout << " Calculating gold-standard FSC ..."<< std::endl;
+				// The first slave receives the average from the second slave and calculates the FSC between them
+				MPI_Status status;
+				MultidimArray<Complex > avg2;
+				avg2.resize(avg1);
+				node->relion_MPI_Recv(MULTIDIM_ARRAY(avg2), 2*MULTIDIM_SIZE(avg2), MPI_DOUBLE, 2, MPITAG_IMAGE, MPI_COMM_WORLD, status);
+				wsum_model.BPref[iclass].calculateDownSampledFourierShellCorrelation(avg1, avg2, mymodel.fsc_halves_class[iclass]);
+			}
+
+		}
+
+		// Now slave 1 sends the fsc curve to everyone else
+		node->relion_MPI_Bcast(MULTIDIM_ARRAY(mymodel.fsc_halves_class[iclass]), MULTIDIM_SIZE(mymodel.fsc_halves_class[iclass]), MPI_DOUBLE, 1, MPI_COMM_WORLD);
+	}
+
+#ifdef DEBUG
+	std::cerr << "MlOptimiserMpi::compareTwoHalves: done" << std::endl;
+#endif
+}
+
+void MlOptimiserMpi::iterate()
+{
+#ifdef TIMING
+	// MPI-specific timing stuff goes here...
+	TIMING_MPIWAIT= timer.setNew("mpiWaitEndOfExpectation");
+#endif
+
+
+	// Launch threads etc.
+	MlOptimiser::iterateSetup();
+
+	// Initialize the current resolution
+	updateCurrentResolution();
+
+	for (iter = iter + 1; iter <= nr_iter; iter++)
+    {
+#ifdef TIMING
+		timer.tic(TIMING_EXP);
+#endif
+
+		// Nobody can start the next iteration until everyone has finished
+		MPI_Barrier(MPI_COMM_WORLD);
+
+		if (do_auto_refine && node->rank == 1)
+			printConvergenceStats();
+
+		expectation();
+
+		MPI_Barrier(MPI_COMM_WORLD);
+
+		if (do_skip_maximization)
+		{
+			// Only write data.star file and break from the iteration loop
+			if (node->isMaster())
+			{
+				// The master only writes the data file (he's the only one who has and manages these data!)
+				iter = -1; // write output file without iteration number
+				MlOptimiser::write(DONT_WRITE_SAMPLING, DO_WRITE_DATA, DONT_WRITE_OPTIMISER, DONT_WRITE_MODEL, node->rank);
+				std::cout << " Auto-refine: Skipping maximization step, so stopping now... " << std::endl;
+			}
+			break;
+		}
+
+		// Now combine all weighted sums
+		// Leave the option ot both for a while. Then, if there are no problems with the system via files keep that one and remove the MPI version from the code
+		if (combine_weights_thru_disc)
+			combineAllWeightedSumsViaFile();
+		else
+			combineAllWeightedSums();
+
+		MPI_Barrier(MPI_COMM_WORLD);
+
+		// Write out data and weight arrays to disc in order to also do an unregularized reconstruction
+		if (do_auto_refine && has_converged)
+			writeTemporaryDataAndWeightArrays();
+
+		// Inside iterative refinement: do FSC-calculation BEFORE the solvent flattening, otherwise over-estimation of resolution
+		// anyway, now that this is done inside BPref, there would be no other way...
+		if (do_split_random_halves)
+		{
+
+			// For asymmetric molecules, join 2 half-reconstructions at the lowest resolutions to prevent them from diverging orientations
+			if (low_resol_join_halves > 0.)
+				joinTwoHalvesAtLowResolution();
+
+			// Calculate gold-standard FSC curve
+			compareTwoHalves();
+
+			// For automated sampling procedure
+			if (!node->isMaster()) // the master does not have the correct mymodel.current_size, it only handles metadata!
+			{
+				// Check that incr_size is at least the number of shells as between FSC=0.5 and FSC=0.143
+				int fsc05   = -1;
+				int fsc0143 = -1;
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(mymodel.fsc_halves_class[0])
+				{
+					if (DIRECT_A1D_ELEM(mymodel.fsc_halves_class[0], i) < 0.5 && fsc05 < 0)
+						fsc05 = i;
+					if (DIRECT_A1D_ELEM(mymodel.fsc_halves_class[0], i) < 0.143 && fsc0143 < 0)
+						fsc0143 = i;
+				}
+				// At least fsc05 - fsc0143 + 5 shells as incr_size
+				incr_size = XMIPP_MAX(incr_size, fsc0143 - fsc05 + 5);
+				has_high_fsc_at_limit = (DIRECT_A1D_ELEM(mymodel.fsc_halves_class[0], mymodel.current_size/2 - 1) > 0.2);
+			}
+
+			// Upon convergence join the two random halves
+			if (do_join_random_halves || do_always_join_random_halves)
+			{
+				if (combine_weights_thru_disc)
+					combineWeightedSumsTwoRandomHalvesViaFile();
+				else
+					combineWeightedSumsTwoRandomHalves();
+
+			}
+		}
+
+#ifdef TIMING
+		timer.toc(TIMING_EXP);
+		timer.tic(TIMING_MAX);
+#endif
+
+		maximization();
+
+		// Make sure all nodes have the same resolution, set the data_vs_prior array from half1 also for half2
+		if (do_split_random_halves)
+			for (int iclass = 0; iclass < mymodel.nr_classes; iclass++)
+				node->relion_MPI_Bcast(MULTIDIM_ARRAY(mymodel.data_vs_prior_class[iclass]), MULTIDIM_SIZE(mymodel.data_vs_prior_class[iclass]), MPI_DOUBLE, 1, MPI_COMM_WORLD);
+
+#ifdef TIMING
+		timer.toc(TIMING_MAX);
+#endif
+
+		MPI_Barrier(MPI_COMM_WORLD);
+
+		// Mask the reconstructions to get rid of noisy solvent areas
+		// Skip masking upon convergence (for validation purposes)
+		if (do_solvent && !has_converged)
+			solventFlatten();
+
+		// Re-calculate the current resolution, do this before writing to get the correct values in the output files
+		updateCurrentResolution();
+
+		// If we are joining random halves, then do not write an optimiser file so that it cannot be restarted!
+		bool do_write_optimiser = !do_join_random_halves;
+		// Write out final map without iteration number in the filename
+		if (do_join_random_halves)
+			iter = -1;
+
+		if (node->rank == 1 || (do_split_random_halves && !do_join_random_halves && node->rank == 2) )
+			//Only the first_slave of each subset writes model to disc (do not write the data.star file, only master will do this)
+			MlOptimiser::write(DO_WRITE_SAMPLING, DONT_WRITE_DATA, do_write_optimiser, DO_WRITE_MODEL, node->rank);
+		else if (node->isMaster())
+			// The master only writes the data file (he's the only one who has and manages these data!)
+			MlOptimiser::write(DONT_WRITE_SAMPLING, DO_WRITE_DATA, DONT_WRITE_OPTIMISER, DONT_WRITE_MODEL, node->rank);
+
+		if (do_auto_refine && has_converged)
+		{
+			if (verb > 0)
+			{
+				std::cout << " Auto-refine: Refinement has converged, stopping now... " << std::endl;
+				std::cout << " Auto-refine: + Final reconstruction from all particles is saved as: " <<  fn_out << "_class001.mrc" << std::endl;
+				std::cout << " Auto-refine: + Final model parameters are stored in: " << fn_out << "_model.star" << std::endl;
+				std::cout << " Auto-refine: + Final data parameters are stored in: " << fn_out << "_data.star" << std::endl;
+				std::cout << " Auto-refine: + Final resolution (without masking) is: " << 1./mymodel.current_resolution << std::endl;
+				if (acc_rot < 10.)
+					std::cout << " Auto-refine: + But you may want to run relion_postprocess to mask the unfil.mrc maps and calculate a higher resolution FSC" << std::endl;
+				else
+				{
+					std::cout << " Auto-refine: + WARNING: The angular accuracy is worse than 10 degrees, so basically you cannot align your particles!" << std::endl;
+					std::cout << " Auto-refine: + WARNING: This has been observed to lead to spurious FSC curves, so be VERY wary of inflated resolution estimates..." << std::endl;
+					std::cout << " Auto-refine: + WARNING: You most probably do NOT want to publish these results!" << std::endl;
+					std::cout << " Auto-refine: + WARNING: Sometimes it is better to tune resolution yourself by adjusting T in a 3D-classification with a single class." << std::endl;
+				}
+				if (do_use_reconstruct_images)
+					std::cout << " Auto-refine: + Used rlnReconstructImageName images for final reconstruction. Ignore filtered map, and only assess the unfiltered half-reconstructions!" << std::endl;
+			}
+			break;
+		}
+
+		// Check whether we have converged by now
+		// Master does not have all info, only slaves do this and then broadcast has_converged so also master has it
+		// If we have, set do_join_random_halves and do_use_all_data for the next iteration
+		if (!node->isMaster() && do_auto_refine)
+			checkConvergence();
+		node->relion_MPI_Bcast(&has_converged, 1, MPI_INT, 1, MPI_COMM_WORLD);
+
+
+
+#ifdef TIMING
+		// Only first slave prints it timing information
+		else if (node->rank == 1)
+			timer.printTimes(false);
+#endif
+
+
+    }
+
+	// delete threads etc.
+	MlOptimiser::iterateWrapUp();
+
+}
+
diff --git a/src/ml_optimiser_mpi.h b/src/ml_optimiser_mpi.h
new file mode 100644
index 0000000..8cc3184
--- /dev/null
+++ b/src/ml_optimiser_mpi.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef ML_OPTIMISER_MPI_H_
+#define ML_OPTIMISER_MPI_H_
+#include "src/mpi.h"
+#include "src/ml_optimiser.h"
+
+#define MPITAG_JOB_REQUEST 0
+#define MPITAG_JOB_REPLY 1
+#define MPITAG_METADATA 2
+#define MPITAG_RANDOMSEED 3
+#define MPITAG_IMAGE 4
+#define MPITAG_PACK 5
+#define MPITAG_DOUBLE 6
+#define MPITAG_INT 7
+
+#ifdef TIMING
+	int TIMING_MPIPACK, TIMING_MPIWAIT;
+#endif
+
+class MlOptimiserMpi: public MlOptimiser
+{
+
+private:
+	MpiNode *node;
+
+public:
+
+#ifdef TIMINGMPI
+    int MPIR_PACK, MPIR_ALLREDUCE, MPIR_UNPACK, MPIR_EXP, MPIR_MAX, MPIR_BCAST;
+#endif
+
+    // Name of the directory to write temporary files to
+    FileName fn_scratch;
+
+	/** Destructor, calls MPI_Finalize */
+    ~MlOptimiserMpi()
+    {
+        delete node;
+    }
+
+    /** Read
+     * This could take care of mpi-parallelisation-dependent variables
+     */
+    void read(int argc, char **argv);
+
+    /** Finalise
+     * Free some memory
+     */
+    void finalise();
+
+    void initialise();
+
+    /** Initialise the work load: divide images equally over all nodes
+     * Also initialise the same random seed for all nodes
+     */
+    void initialiseWorkLoad();
+
+    /** Perform individual power spectra calculation in parallel */
+    void calculateSumOfPowerSpectraAndAverageImage(MultidimArray<double> &Mavg);
+
+    /** Expectation
+     *  This cares care of gathering all weighted sums after the expectation
+     */
+    void expectation();
+
+    /** After expectation combine all weighted sum arrays across all nodes
+     *  Use read/write to temporary files instead of MPI
+     */
+    void combineAllWeightedSumsViaFile();
+
+    /** Join the sums from two random halves
+     *  Use read/write to temporary files instead of MPI
+     */
+    void combineWeightedSumsTwoRandomHalvesViaFile();
+
+    /** After expectation combine all weighted sum arrays across all nodes
+     */
+    void combineAllWeightedSums();
+
+    /** Join the sums from two random halves
+     */
+    void combineWeightedSumsTwoRandomHalves();
+
+    /** Maximization
+     * This takes care of the parallel reconstruction of the classes
+     */
+    void maximization();
+
+    /**
+     *  Write temporary data and weight arrays from the backprojector to disc to allow unregularized reconstructions
+     */
+    void writeTemporaryDataAndWeightArrays();
+
+    /**
+     *  Read temporary data and weight arrays from disc and perform unregularized reconstructions
+     *  Also write the unregularized reconstructions to disc.
+     */
+    void readTemporaryDataAndWeightArraysAndReconstruct(int iclass, int ihalf);
+
+    /**
+     * Join two independent reconstructions ate the lowest frequencies to avoid convergence in distinct orientations
+     */
+    void joinTwoHalvesAtLowResolution();
+
+    /** When refining two random halves separately, the master receives both models, calculates FSC and the power of their difference
+     *  and sends these curves, together with new tau2_class estimates to all slaves...
+     */
+    void compareTwoHalves();
+
+    /** Do the real work
+     * Expectation is split in image subsets over all nodes, each reconstruction is done on a separate node
+     */
+    void iterate();
+
+
+
+};
+
+
+#endif /*  ML_OPTIMISER_MPI_H_ */
diff --git a/src/mpi.cpp b/src/mpi.cpp
new file mode 100644
index 0000000..a197fd6
--- /dev/null
+++ b/src/mpi.cpp
@@ -0,0 +1,250 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+/***************************************************************************
+ * Authors:     J.M. de la Rosa Trevin (jmdelarosa at cnb.csic.es)
+ *
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include "src/mpi.h"
+
+//------------ MPI ---------------------------
+MpiNode::MpiNode(int &argc, char ** argv)
+{
+    //MPI Initialization
+    MPI_Init(&argc, &argv);
+    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+    MPI_Comm_size(MPI_COMM_WORLD, &size);
+    // Handle errors
+    MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
+}
+
+MpiNode::~MpiNode()
+{
+    MPI_Finalize();
+}
+
+bool MpiNode::isMaster() const
+{
+    return rank == 0;
+}
+
+int MpiNode::myRandomSubset() const
+{
+	if (rank == 0)
+		return 0;
+	else
+		return (rank % 2 == 0) ? 2 : 1;
+}
+
+void MpiNode::barrierWait()
+{
+  MPI_Barrier(MPI_COMM_WORLD);
+}
+
+// MPI_TEST will be executed every this many seconds: so this determines the minimum time taken for every send operation!!
+//#define VERBOSE_MPISENDRECV
+int MpiNode::relion_MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
+{
+
+	int result;
+	double start_time = MPI_Wtime();
+
+#define ONLY_NORMAL_SEND
+#ifdef ONLY_NORMAL_SEND
+	result = MPI_Send(buf, count, datatype, dest, tag, comm);
+	if (result != MPI_SUCCESS)
+	{
+		report_MPI_ERROR(result);
+	}
+#else
+	// Only use Bsend for larger messages, otherwise use normal send
+	if (count > 100)
+	{
+		int size;
+		MPI_Pack_size( count, datatype, comm, &size );
+		char *membuff;
+
+		// Allocate memory for the package to be sent
+		int attach_result = MPI_Buffer_attach( malloc(size + MPI_BSEND_OVERHEAD ), size + MPI_BSEND_OVERHEAD );
+		if (attach_result != MPI_SUCCESS)
+		{
+			report_MPI_ERROR(result);
+		}
+
+		// Actually start sending the message
+		result = MPI_Bsend(buf, count, datatype, dest, tag, comm);
+		if (result != MPI_SUCCESS)
+		{
+			report_MPI_ERROR(result);
+		}
+
+		// The following will only complete once the message has been successfully sent (i.e. also received on the other side)
+		int deattach_result = MPI_Buffer_detach( &membuff, &size);
+		if (deattach_result != MPI_SUCCESS)
+		{
+			report_MPI_ERROR(result);
+		}
+	}
+	else
+	{
+		result = MPI_Send(buf, count, datatype, dest, tag, comm);
+		if (result != MPI_SUCCESS)
+		{
+			report_MPI_ERROR(result);
+		}
+	}
+#endif
+
+#ifdef VERBOSE_MPISENDRECV
+	if (count > 100)
+		std::cerr <<" relion_MPI_Send: message to " << dest << " of size "<< count << " arrived in " << MPI_Wtime() - start_time << " seconds" << std::endl;
+#endif
+	return result;
+
+}
+
+int MpiNode::relion_MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status &status)
+{
+	int result;
+	MPI_Request request;
+	double current_time = MPI_Wtime();
+	double start_time = current_time;
+
+	// First make a non-blocking receive
+	int result_irecv = MPI_Irecv(buf, count, datatype, source, tag, comm, &request);
+	if (result_irecv != MPI_SUCCESS)
+	{
+		report_MPI_ERROR(result_irecv);
+	}
+
+	// I could do something in between. If not, Irecv == Recv
+	// Wait for it to finish (MPI_Irecv + MPI_Wait == MPI_Recv)
+	result = MPI_Wait(&request, &status);
+	if (result != MPI_SUCCESS)
+	{
+		report_MPI_ERROR(result);
+	}
+
+#ifdef VERBOSE_MPISENDRECV
+	if (count > 100)
+		std::cerr <<" relion_MPI_Recv: message from "<<source << " of size "<< count <<" arrived in " << MPI_Wtime() - start_time << " seconds" << std::endl;
+#endif
+	return result;
+
+}
+
+
+int MpiNode::relion_MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm)
+{
+	int result;
+
+	result = MPI_Bcast(buffer, count, datatype, root, comm);
+	if (result != MPI_SUCCESS)
+	{
+		report_MPI_ERROR(result);
+	}
+
+	return result;
+
+}
+
+void MpiNode::report_MPI_ERROR(int error_code)
+{
+	char error_string[200];
+	int length_of_error_string, error_class;
+	MPI_Error_class(error_code, &error_class);
+	MPI_Error_string(error_class, error_string, &length_of_error_string);
+	fprintf(stderr, "%3d: %s\n", rank, error_string);
+	MPI_Error_string(error_code, error_string, &length_of_error_string);
+	fprintf(stderr, "%3d: %s\n", rank, error_string);
+
+	std::cerr.flush();
+	REPORT_ERROR("Encountered an MPI-related error, see above. Now exiting...");
+
+}
+
+
+
+void printMpiNodesMachineNames(MpiNode &node, int nthreads)
+{
+
+    char nodename[64] = "undefined";
+    gethostname(nodename,sizeof(nodename));
+
+    if (node.isMaster())
+    {
+    	std::cout << " === RELION MPI setup ===" << std::endl;
+    	std::cout << " + Number of MPI processes             = " << node.size << std::endl;
+    	if (nthreads > 1)
+    	{
+    		std::cout << " + Number of threads per MPI process  = " << nthreads << std::endl;
+    		std::cout << " + Total number of threads therefore  = " << nthreads * node.size << std::endl;
+		}
+    	std::cout << " + Master  (0) runs on host            = " << nodename << std::endl;
+    	std::cout.flush();
+    }
+    node.barrierWait();
+
+    for (int slave = 1; slave < node.size; slave++)
+    {
+    	if (slave == node.rank)
+    	{
+    		std::cout << " + Slave ";
+    		std::cout.width(5);
+    		std::cout << slave;
+    		std::cout << " runs on host            = " << nodename << std::endl;
+    		std::cout.flush();
+		}
+    	node.barrierWait();
+    }
+
+    if (node.isMaster())
+    {
+            std::cout << " =================" << std::endl;
+    }
+    std::cout.flush();
+
+    // Try to flush all std::cout of all MPI processes before proceeding...
+    sleep(1);
+    node.barrierWait();
+
+}
+
diff --git a/src/mpi.h b/src/mpi.h
new file mode 100644
index 0000000..1efd3bb
--- /dev/null
+++ b/src/mpi.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ * Authors:     J.M. de la Rosa Trevin (jmdelarosa at cnb.csic.es)
+ *
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef MPI_H_
+#define MPI_H_
+#include <mpi.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "src/error.h"
+
+ /** Class to wrapp some MPI common calls in an work node.
+ *
+ */
+class MpiNode
+{
+
+public:
+    int rank, size;
+    MpiNode(int &argc, char ** argv);
+
+    ~MpiNode();
+
+    // Only true if rank == 0
+    bool isMaster() const;
+
+    // Prints the random subset for this rank
+    int myRandomSubset() const;
+
+    /** Wait on a barrier for the other MPI nodes */
+    void barrierWait();
+
+    /** Build in some better error handling and (hopefully better) robustness to communication failures in the MPI_Send/MPI_Recv pairs....
+     */
+    int relion_MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm);
+
+    int relion_MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status &status);
+
+    int relion_MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm);
+
+    /* Better error handling of MPI error messages */
+    void report_MPI_ERROR(int errno);
+
+};
+
+// General function to print machinenames on all MPI nodes
+void printMpiNodesMachineNames(MpiNode &node, int nthreads = 1);
+
+
+#endif /* MPI_H_ */
diff --git a/src/multidim_array.cpp b/src/multidim_array.cpp
new file mode 100644
index 0000000..7225e14
--- /dev/null
+++ b/src/multidim_array.cpp
@@ -0,0 +1,77 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include "src/multidim_array.h"
+
+
+// Show a complex array ---------------------------------------------------
+std::ostream& operator<<(std::ostream& ostrm,
+    const MultidimArray< Complex >& v)
+{
+    if (v.xdim == 0)
+        ostrm << "NULL MultidimArray\n";
+    else
+        ostrm << std::endl;
+
+    for (int l = 0; l < NSIZE(v); l++)
+    {
+        if (NSIZE(v)>1) ostrm << "Image No. " << l << std::endl;
+        for (int k = STARTINGZ(v); k <= FINISHINGZ(v); k++)
+        {
+            if (ZSIZE(v)>1) ostrm << "Slice No. " << k << std::endl;
+            for (int i = STARTINGY(v); i <= FINISHINGY(v); i++)
+            {
+                for (int j = STARTINGX(v); j <= FINISHINGX(v); j++)
+                    ostrm << "(" << A3D_ELEM(v, k, i, j).real << "," << A3D_ELEM(v, k, i, j).imag <<")" << ' ';
+                ostrm << std::endl;
+            }
+        }
+    }
+
+    return ostrm;
+}
+
+
+
+
diff --git a/src/multidim_array.h b/src/multidim_array.h
new file mode 100644
index 0000000..7ab11a4
--- /dev/null
+++ b/src/multidim_array.h
@@ -0,0 +1,4261 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef MULTIDIM_ARRAY_H
+#define MULTIDIM_ARRAY_H
+
+#include <typeinfo>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "src/funcs.h"
+#include "src/error.h"
+#include "src/args.h"
+#include "src/matrix1d.h"
+#include "src/matrix2d.h"
+#include "src/complex.h"
+
+
+extern int bestPrecision(float F, int _width);
+extern std::string floatToString(float F, int _width, int _prec);
+
+/// @defgroup MultidimensionalArrays Multidimensional Arrays
+/// @ingroup DataLibrary
+//@{
+/** @name MultidimArraysSpeedUp Speed up macros
+ *
+ * This macros are defined to allow high speed in critical parts of your
+ * program. They shouldn't be used systematically as usually there is no
+ * checking on the correctness of the operation you are performing. Speed comes
+ * from three facts: first, they are macros and no function call is performed
+ * (although most of the critical functions are inline functions), there is no
+ * checking on the correctness of the operation (it could be wrong and you are
+ * not warned of it), and destination vectors are not returned saving time in
+ * the copy constructor and in the creation/destruction of temporary vectors.
+ */
+//@{
+/** Returns the first X valid logical index
+ */
+#define STARTINGX(v) ((v).xinit)
+
+/** Returns the last X valid logical index
+ */
+#define FINISHINGX(v) ((v).xinit + (v).xdim - 1)
+
+/** Returns the first Y valid logical index
+ */
+#define STARTINGY(v) ((v).yinit)
+
+/** Returns the last Y valid logical index
+ */
+#define FINISHINGY(v) ((v).yinit + (v).ydim - 1)
+
+/** Returns the first Z valid logical index
+ */
+#define STARTINGZ(v) ((v).zinit)
+
+/** Returns the last Z valid logical index
+ */
+#define FINISHINGZ(v) ((v).zinit + (v).zdim - 1)
+
+/** Access to X dimension (size)
+ */
+#define XSIZE(v) ((v).xdim)
+
+/** Access to Y dimension (size)
+ */
+#define YSIZE(v) ((v).ydim)
+
+/** Access to Z dimension (size)
+ */
+#define ZSIZE(v) ((v).zdim)
+
+/** Access to N dimension (size)
+ */
+#define NSIZE(v) ((v).ndim)
+
+/** Access to XY dimension (Ysize*Xsize)
+ */
+#define YXSIZE(v) ((v).yxdim)
+
+/** Access to XYZ dimension (Zsize*Ysize*Xsize)
+ */
+#define ZYXSIZE(v) ((v).zyxdim)
+
+/** Access to XYZN dimension (Nsize*Zsize*Ysize*Xsize)
+ */
+#define MULTIDIM_SIZE(v) ((v).nzyxdim)
+
+/** Access to XYZN dimension (Nsize*Zsize*Ysize*Xsize)
+ */
+#define NZYXSIZE(v) ((v).nzyxdim)
+
+/** Array access.
+ *
+ * This macro gives you access to the array (T **)
+ */
+#ifndef MULTIDIM_ARRAY
+#define MULTIDIM_ARRAY(v) ((v).data)
+#endif
+
+/** Access to a direct element.
+ * v is the array, l is the image, k is the slice, i is the Y index and j is the X index.
+ * i and j) within the slice.
+ */
+#define DIRECT_NZYX_ELEM(v, l, k, i, j) ((v).data[(l)*ZYXSIZE(v)+(k)*YXSIZE(v)+((i)*XSIZE(v))+(j)])
+
+/** Multidim element: Logical access.
+ */
+#define NZYX_ELEM(v, l, k, i, j)  \
+    DIRECT_NZYX_ELEM((v), (l), (k) - STARTINGZ(v), (i) - STARTINGY(v), (j) - STARTINGX(v))
+
+/** Access to a direct element.
+ * v is the array, k is the slice and n is the number of the pixel (combined i and j)
+ * within the slice.
+ */
+#define DIRECT_MULTIDIM_ELEM(v,n) ((v).data[(n)])
+
+/** For all direct elements in the array
+ *
+ * This macro is used to generate loops for the array in an easy manner. It
+ * defines an internal index 'n' which goes over the slices and 'n' that
+ * goes over the pixels in each slice.
+ *
+ * @code
+ * FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(v)
+ * {
+ *     std::cout << DIRECT_MULTIDIM_ELEM(v,n) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(v) \
+    for (long int n=0; n<NZYXSIZE(v); ++n)
+
+/** For all direct elements in the array
+ *
+ * This macro is used to generate loops for the array in an easy
+ * manner. It defines internal indexes 'l', 'k','i' and 'j' which
+ * ranges over the n volume using its physical definition.
+ *
+ * @code
+ * FOR_ALL_DIRECT_NZYX_ELEMENTS_IN_MULTIDIMARRAY(v)
+ * {
+ *     std::cout << DIRECT_NZYX_ELEM(v,l, k, i, j) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_DIRECT_NZYX_ELEMENTS_IN_MULTIDIMARRAY(V) \
+    for (long int l=0; l<NSIZE(V); l++) \
+        for (long int k=0; k<ZSIZE(V); k++) \
+            for (long int i=0; i<YSIZE(V); i++)      \
+                for (long int j=0; j<XSIZE(V); j++)
+
+/** For all direct elements in the array
+ *
+ * This macro is used to generate loops for the array in an easy
+ * manner. It defines internal indexes 'l', 'k','i' and 'j' which
+ * ranges over the n volume using its logical definition.
+ *
+ * @code
+ * FOR_ALL_NZYX_ELEMENTS_IN_MULTIDIMARRAY(v)
+ * {
+ *     std::cout << NZYX_ELEM(v,l, k, i, j) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_NZYX_ELEMENTS_IN_MULTIDIMARRAY(V) \
+    for (long int l=0; l<NSIZE(V); l++) \
+        for (long int k=STARTINGZ(V); k<=FINISHINGZ(V); k++) \
+            for (long int i=STARTINGY(V); i<=FINISHINGY(V); i++)     \
+                for (long int j=STARTINGX(V); j<=FINISHINGX(V); j++)
+
+/** For all direct elements in the array, pointer version
+ *
+ * This macro is used to generate loops for the array in an easy manner. It
+ * defines an internal index 'k' which goes over the slices and 'n' that
+ * goes over the pixels in each slice. Each element can be accessed through
+ * an external pointer called ptr.
+ *
+ * @code
+ * T* ptr=NULL;
+ * long int n;
+ * FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(v,n,ptr)
+ * {
+ *     std::cout << *ptr << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(v,n,ptr) \
+    for ((n)=0, (ptr)=(v).data; (n)<NZYXSIZE(v); ++(n), ++(ptr))
+
+/** Access to a direct element.
+ * v is the array, k is the slice (Z), i is the Y index and j is the X index.
+ */
+#define DIRECT_A3D_ELEM(v,k,i,j) ((v).data[(k)*YXSIZE(v)+((i)*XSIZE(v))+(j)])
+
+/** A short alias for the previous function.
+ *
+ */
+#define dAkij(V, k, i, j) DIRECT_A3D_ELEM(V, k, i, j)
+
+/** Volume element: Logical access.
+ *
+ * @code
+ * A3D_ELEM(V, -1, -2, 1) = 1;
+ * val = A3D_ELEM(V, -1, -2, 1);
+ * @endcode
+ */
+#define A3D_ELEM(V, k, i, j) \
+    DIRECT_A3D_ELEM((V),(k) - STARTINGZ(V), (i) - STARTINGY(V), (j) - STARTINGX(V))
+
+/** For all elements in the array.
+ *
+ * This macro is used to generate loops for the volume in an easy way. It
+ * defines internal indexes 'k','i' and 'j' which ranges the volume using its
+ * mathematical definition (ie, logical access).
+ *
+ * @code
+ * FOR_ALL_ELEMENTS_IN_ARRAY3D(V)
+ * {
+ *     std::cout << V(k, i, j) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_ELEMENTS_IN_ARRAY3D(V) \
+    for (long int k=STARTINGZ(V); k<=FINISHINGZ(V); k++) \
+        for (long int i=STARTINGY(V); i<=FINISHINGY(V); i++) \
+            for (long int j=STARTINGX(V); j<=FINISHINGX(V); j++)
+
+/** For all elements in common.
+ *
+ * This macro is used to generate loops for all the elements logically in common
+ * between two volumes in an easy manner. Then k, i and j (locally defined)
+ * range from
+ *
+ * MAX(STARTINGZ(V1),STARTINGZ(V2)) to MIN(FINISHINGZ(V1),FINISHINGZ(V2)),
+ * MAX(STARTINGY(V1),STARTINGY(V2)) to MIN(FINISHINGY(V1),FINISHINGY(V2)),
+ * MAX(STARTINGX(V1),STARTINGX(V2)) to MIN(FINISHINGX(V1),FINISHINGX(V2))
+ *
+ * (included limits) respectively. You need to define SPEED_UP_temps.
+ *
+ * @code
+ * SPEED_UP_temps;
+ * MultidimArray< double > V1(10, 10, 10), V2(20, 20, 20);
+ * V1.setXmippOrigin();
+ * V2.setXmippOrigin();
+ *
+ * FOR_ALL_ELEMENTS_IN_COMMON_IN_ARRAY3D(V1, V2)
+ * {
+ *    // ...
+ * }
+ * @endcode
+ */
+#define FOR_ALL_ELEMENTS_IN_COMMON_IN_ARRAY3D(V1, V2) \
+    ispduptmp0 = XMIPP_MAX(STARTINGZ(V1), STARTINGZ(V2)); \
+    ispduptmp1 = XMIPP_MIN(FINISHINGZ(V1),FINISHINGZ(V2)); \
+    ispduptmp2 = XMIPP_MAX(STARTINGY(V1), STARTINGY(V2)); \
+    ispduptmp3 = XMIPP_MIN(FINISHINGY(V1),FINISHINGY(V2)); \
+    ispduptmp4 = XMIPP_MAX(STARTINGX(V1), STARTINGX(V2)); \
+    ispduptmp5 = XMIPP_MIN(FINISHINGX(V1),FINISHINGX(V2)); \
+    for (long int k=ispduptmp0; k<=ispduptmp1; k++) \
+        for (long int i=ispduptmp2; i<=ispduptmp3; i++) \
+            for (long int j=ispduptmp4; j<=ispduptmp5; j++)
+
+/** For all direct elements in the array.
+ *
+ * This macro is used to generate loops for the volume in an easy way. It
+ * defines internal indexes 'k','i' and 'j' which ranges the volume using its
+ * physical definition.
+ *
+ * @code
+ * FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(V)
+ * {
+ *     std::cout << DIRECT_A3D_ELEM(m, k, i, j) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(V) \
+    for (long int k=0; k<ZSIZE(V); k++) \
+        for (long int i=0; i<YSIZE(V); i++) \
+            for (long int j=0; j<XSIZE(V); j++)
+
+/** Access to a direct element of a matrix.
+ * v is the array, i and j define the element v_ij.
+ *
+ * Be careful because this is physical access, usually matrices follow the C
+ * convention of starting index==0 (X and Y). This function should not be used
+ * as it goes against the vector library philosophy unless you explicitly want
+ * to access directly to any value in the matrix without taking into account its
+ * logical position
+ *
+ * @code
+ * DIRECT_A2D_ELEM(m, 0, 0) = 1;
+ * val = DIRECT_A2D_ELEM(m, 0, 0);
+ * @endcode
+ */
+#define DIRECT_A2D_ELEM(v,i,j) ((v).data[(i)*(v).xdim+(j)])
+
+/** Short alias for DIRECT_A2D_ELEM
+ */
+#define dAij(M, i, j) DIRECT_A2D_ELEM(M, i, j)
+
+/** Matrix element: Logical access
+ *
+ * @code
+ * A2D_ELEM(m, -2, 1) = 1;
+ * val = A2D_ELEM(m, -2, 1);
+ * @endcode
+ */
+#define A2D_ELEM(v, i, j) \
+    DIRECT_A2D_ELEM(v, (i) - STARTINGY(v), (j) - STARTINGX(v))
+
+/** TRUE if both arrays have the same shape
+ *
+ * Two arrays have the same shape if they have the same size and the same
+ * starting point. Be aware that this is a macro which simplifies to a boolean.
+ */
+#define SAME_SHAPE2D(v1, v2) \
+    (XSIZE(v1) == XSIZE(v2) && \
+     YSIZE(v1) == YSIZE(v2) && \
+     STARTINGX(v1) == STARTINGX(v2) && \
+     STARTINGY(v1) == STARTINGY(v2))
+
+/** For all elements in the array
+ *
+ * This macro is used to generate loops for the matrix in an easy way. It
+ * defines internal indexes 'i' and 'j' which ranges the matrix using its
+ * mathematical definition (ie, logical access).
+ *
+ * @code
+ * FOR_ALL_ELEMENTS_IN_ARRAY2D(m)
+ * {
+ *     std::cout << m(i, j) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_ELEMENTS_IN_ARRAY2D(m) \
+    for (long int i=STARTINGY(m); i<=FINISHINGY(m); i++) \
+        for (long int j=STARTINGX(m); j<=FINISHINGX(m); j++)
+
+/** For all elements in the array, accessed physically
+ *
+ * This macro is used to generate loops for the matrix in an easy way using
+ * physical indexes. It defines internal indexes 'i' and 'j' which ranges the
+ * matrix using its physical definition.
+ *
+ * @code
+ * FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(m)
+ * {
+ *     std::cout << DIRECT_A2D_ELEM(m, i, j) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(m) \
+    for (long int i=0; i<YSIZE(m); i++) \
+        for (long int j=0; j<XSIZE(m); j++)
+
+/** Vector element: Physical access
+ *
+ * Be careful because this is physical access, usually vectors follow the C
+ * convention of starting index==0. This function should not be used as it goes
+ * against the vector library philosophy unless you explicitly want to access
+ * directly to any value in the vector without taking into account its logical
+ * position.
+ *
+ * @code
+ * DIRECT_A1D_ELEM(v, 0) = 1;
+ * val = DIRECT_A1D_ELEM(v, 0);
+ * @endcode
+ */
+#define DIRECT_A1D_ELEM(v, i) ((v).data[(i)])
+
+/** A short alias to previous function
+ */
+#define dAi(v, i) DIRECT_A1D_ELEM(v, i)
+
+/** Vector element: Logical access
+ *
+ * @code
+ * A1D_ELEM(v, -2) = 1;
+ * val = A1D_ELEM(v, -2);
+ * @endcode
+ */
+#define A1D_ELEM(v, i) DIRECT_A1D_ELEM(v, (i) - ((v).xinit))
+
+/** For all elements in the array
+ *
+ * This macro is used to generate loops for the vector in an easy manner. It
+ * defines an internal index 'i' which ranges the vector using its mathematical
+ * definition (ie, logical access).
+ *
+ * @code
+ * FOR_ALL_ELEMENTS_IN_ARRAY1D(v)
+ * {
+ *     std::cout << v(i) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_ELEMENTS_IN_ARRAY1D(v) \
+    for (long int i=STARTINGX(v); i<=FINISHINGX(v); i++)
+
+/** For all elements in the array, accessed physically
+ *
+ * This macro is used to generate loops for the vector in an easy way using
+ * physical indexes. It defines internal the index 'i' which ranges the vector
+ * using its physical definition.
+ *
+ * @code
+ * FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(v)
+ * {
+ *     std::cout << DIRECT_A1D_ELEM(v, i) << " ";
+ * }
+ * @endcode
+ */
+#define FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(v) \
+    for (long int i=0; i<v.xdim; i++)
+//@}
+
+// Forward declarations ====================================================
+template<typename T>
+class MultidimArray;
+
+template<typename T>
+void coreArrayByScalar(const MultidimArray<T>& op1, const T& op2,
+                       MultidimArray<T>& result, char operation);
+
+template<typename T>
+void coreScalarByArray(const T& op1, const MultidimArray<T>& op2,
+                       MultidimArray<T>& result, char operation);
+
+template<typename T>
+void coreArrayByArray(const MultidimArray<T>& op1, const MultidimArray<T>& op2,
+                      MultidimArray<T>& result, char operation);
+
+/** Template class for Xmipp arrays.
+  * This class provides physical and logical access.
+*/
+template<typename T>
+class MultidimArray
+{
+public:
+    /* The array itself.
+       The array is always a 3D array (Z,Y,X). For vectors the size of the array
+       is (1,1,X) and for matrices (1,Y,X). The pixel (i,j) (y,x) is at the
+       position data[i*Xdim+j] or data[y*Xdim+x]
+    */
+    T* data;
+
+    // Destroy data
+    bool destroyData;
+
+    // Number of images
+    long int ndim;
+
+    // Number of elements in Z
+    long int zdim;
+
+    // Number of elements in Y
+    long int ydim;
+
+    // Number of elements in X
+    long int xdim;
+
+    // Number of elements in YX
+    long int yxdim;
+
+    // Number of elements in ZYX
+    long int zyxdim;
+
+    // Number of elements in NZYX
+    long int nzyxdim;
+
+    // Z init
+    long int zinit;
+
+    // Y init
+    long int yinit;
+
+    // X init
+    long int xinit;
+
+    //Alloc memory or map to a file
+    bool     mmapOn;
+    // Mapped File name
+    FileName mapFile;
+    //Mapped file handler
+    int      mFd;
+    // Number of elements in NZYX in allocated memory
+    long int nzyxdimAlloc;
+
+public:
+    /// @name Constructors
+    //@{
+
+    /** Empty constructor.
+     * The empty constructor creates an array with no memory associated,
+     * size=0.
+     */
+    MultidimArray()
+    {
+        coreInit();
+    }
+
+    /** Size constructor with 4D size.
+     * The Size constructor creates an array with memory associated,
+     * and fills it with zeros.
+     */
+    MultidimArray(long int Ndim, long int Zdim, long int Ydim, long int Xdim)
+    {
+        coreInit();
+        resize(Ndim, Zdim, Ydim, Xdim);
+    }
+
+    /** Size constructor with 3D size.
+     * The Size constructor creates an array with memory associated,
+     * and fills it with zeros.
+     */
+    MultidimArray(long int Zdim, long int Ydim, long int Xdim)
+    {
+        coreInit();
+        resize(1, Zdim, Ydim, Xdim);
+    }
+
+    /** Size constructor with 2D size.
+     * The Size constructor creates an array with memory associated,
+     * and fills it with zeros.
+     */
+    MultidimArray(long int Ydim, long int Xdim)
+    {
+        coreInit();
+        resize(1, 1, Ydim, Xdim);
+    }
+
+    /** Size constructor with 1D size.
+     * The Size constructor creates an array with memory associated,
+     * and fills it with zeros.
+     */
+    MultidimArray(long int Xdim)
+    {
+        coreInit();
+        resize(1, 1, 1, Xdim);
+    }
+
+    /** Copy constructor
+     *
+     * The created volume is a perfect copy of the input array but with a
+     * different memory assignment.
+     *
+     * @code
+     * MultidimArray< double > V2(V1);
+     * @endcode
+     */
+    MultidimArray(const MultidimArray<T>& V)
+    {
+    	coreInit();
+        *this = V;
+    }
+
+    /** Copy constructor from a Matrix1D.
+     * The Size constructor creates an array with memory associated,
+     * and fills it with zeros.
+     */
+    MultidimArray(const Matrix1D<T>& V)
+    {
+        coreInit();
+        resize(1, 1, 1, V.size());
+        for (long int i = 0; i < V.size(); i++)
+            (*this)(i) = V(i);
+    }
+
+    /** Constructor from vector 1D
+     * This will create a MultidimArray 1D
+     * the size and elements will be copied from
+     * the std::vector
+     */
+    MultidimArray(const std::vector<T> &vector)
+    {
+        coreInit();
+        resize(1, 1, 1, vector.size());
+        for (long int i = 0; i < vector.size(); i++)
+            (*this)(i) = vector[i];
+    }
+
+    /** Destructor.
+     */
+    ~MultidimArray()
+    {
+        coreDeallocate();
+    }
+
+    /** Clear.
+     */
+    void clear()
+    {
+        coreDeallocate();
+        coreInit();
+    }
+    //@}
+
+    /// @name Core memory operations
+    //@{
+
+    /** Core init.
+     * Initialize everything to 0
+     */
+    void coreInit()
+    {
+        xdim=0;
+        yxdim=0;
+        zyxdim=0;
+        nzyxdim=0;
+        ydim=1;
+        zdim=1;
+        ndim=1;
+        zinit=0;
+        yinit=0;
+        xinit=0;
+        data=NULL;
+        nzyxdimAlloc = 0;
+        destroyData=true;
+        mmapOn = false;
+        mFd=0;
+    }
+
+    /** Core allocate with dimensions.
+     */
+    void coreAllocate(long int _ndim, long int _zdim, long int _ydim, long int _xdim)
+    {
+        if (_ndim <= 0 || _zdim <= 0 || _ydim<=0 || _xdim<=0)
+        {
+            clear();
+            return;
+        }
+        if(data!=NULL)
+            REPORT_ERROR( "do not allocate space for an image if you have not deallocate it first");
+
+        ndim=_ndim;
+        zdim=_zdim;
+        ydim=_ydim;
+        xdim=_xdim;
+        yxdim=ydim*xdim;
+        zyxdim=zdim*yxdim;
+        nzyxdim=ndim*zyxdim;
+
+        coreAllocate();
+    }
+
+    /** Core allocate without dimensions.
+     *
+     * It is supposed the dimensions are set previously with setXdim(x), setYdim(y)
+     * setZdim(z), setNdim(n) or with setDimensions(Xdim, Ydim, Zdim, Ndim);
+     *
+     */
+    void coreAllocate()
+    {
+        if(data!=NULL)
+            REPORT_ERROR( "do not allocate space for an image if you have not deallocate it first");
+        if (nzyxdim < 0)
+            REPORT_ERROR("coreAllocate:Cannot allocate a negative number of bytes");
+
+        if (mmapOn)
+        {
+            mapFile.initRandom(8);
+            mapFile = mapFile.addExtension("tmp");
+
+
+            if ( ( mFd = open(mapFile.c_str(),  O_RDWR | O_CREAT | O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) ) == -1 )
+                REPORT_ERROR("MultidimArray::coreAllocate: Error creating map file.");
+
+            if ((lseek(mFd, nzyxdim*sizeof(T), SEEK_SET) == -1)|| (::write(mFd,"",1) == -1))// Use of :: to call write from global space due to confict with multidimarray::write
+            {
+                close(mFd);
+                REPORT_ERROR("MultidimArray::coreAllocate: Error 'stretching' the map file.");
+            }
+
+            if ( (data = (T*) mmap(0,nzyxdim*sizeof(T), PROT_READ | PROT_WRITE, MAP_SHARED, mFd, 0)) == (void*) -1 )
+                REPORT_ERROR("MultidimArray::coreAllocate: mmap failed.");
+        }
+        else
+        {
+            data = new T [nzyxdim];
+            if (data == NULL)
+                REPORT_ERROR( "Allocate: No space left");
+        }
+        nzyxdimAlloc = nzyxdim;
+    }
+
+    /** Core allocate without dimensions.
+     *
+     * It is supposed the dimensions are set previously with setXdim(x), setYdim(y)
+     * setZdim(z), setNdim(n) or with setDimensions(Xdim, Ydim, Zdim, Ndim);
+     *
+     */
+    void coreAllocateReuse()
+    {
+        if(data != NULL && nzyxdim <= nzyxdimAlloc)
+            return;
+        else if (nzyxdim > nzyxdimAlloc)
+            coreDeallocate();
+
+        if (nzyxdim < 0)
+            REPORT_ERROR("coreAllocateReuse:Cannot allocate a negative number of bytes");
+
+        if (mmapOn)
+        {
+            mapFile.initRandom(8);
+            mapFile = mapFile.addExtension("tmp");
+
+            if ( ( mFd = open(mapFile.c_str(),  O_RDWR | O_CREAT | O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) ) == -1 )
+                REPORT_ERROR("MultidimArray::coreAllocateReuse: Error creating map file.");
+            if ((lseek(mFd, nzyxdim*sizeof(T), SEEK_SET) == -1) || (::write(mFd,"",1) == -1))// Use of :: to call write from global space due to confict with multidimarray::write
+            {
+                close(mFd);
+                REPORT_ERROR("MultidimArray::coreAllocateReuse: Error 'stretching' the map file.");
+            }
+
+            if ( (data = (T*) mmap(0,nzyxdim*sizeof(T), PROT_READ | PROT_WRITE, MAP_SHARED, mFd, 0)) == (void*) -1 )
+                REPORT_ERROR("MultidimArray::coreAllocateReuse: mmap failed.");
+        }
+        else
+        {
+            data = new T [nzyxdim];
+            if (data == NULL)
+                REPORT_ERROR( "Allocate: No space left");
+        }
+        nzyxdimAlloc = nzyxdim;
+    }
+
+    /** Sets mmap.
+     *
+     * Sets on/off mmap flag to allocate memory in a file.
+     *
+     */
+    void setMmap(bool mmap)
+    {
+        mmapOn = mmap;
+    }
+
+    /** Core deallocate.
+     * Free all data.
+     */
+    void coreDeallocate()
+    {
+        if (data != NULL && destroyData)
+        {
+            if (mmapOn)
+            {
+                munmap(data,nzyxdimAlloc*sizeof(T));
+                close(mFd);
+                remove(mapFile.c_str());
+            }
+            else
+                delete[] data;
+        }
+        data=NULL;
+        nzyxdimAlloc = 0;
+    }
+
+    /** Alias a multidimarray.
+     *
+     * Treat the multidimarray as if it were a volume. The data is not copied
+     * into new memory, but a pointer to the multidimarray is copied.
+     * You should not make any operation on this volume such that the
+     * memory locations are changed
+     */
+    void alias(const MultidimArray<T> &m)
+    {
+        copyShape(m);
+        this->data=m.data;
+        this->destroyData=false;
+    }
+    //@}
+
+    /// @name Size
+    //@{
+
+    /** Sets new 4D dimensions.
+      *
+      *  Note that the dataArray is NOT resized. This should be done separately with coreAllocate()
+      *
+      */
+    void setDimensions(long int Xdim, long int Ydim, long int Zdim, long int Ndim)
+    {
+        ndim=Ndim;
+        zdim=Zdim;
+        ydim=Ydim;
+        xdim=Xdim;
+        yxdim=ydim*xdim;
+        zyxdim=zdim*yxdim;
+        nzyxdim=ndim*zyxdim;
+    }
+
+    /** Sets new N dimension.
+     *
+     *  Note that the dataArray is NOT resized. This should be done separately with coreAllocate()
+     *
+     */
+    void setNdim(long int Ndim)
+    {
+        ndim = Ndim;
+        nzyxdim=ndim*zyxdim;
+    }
+
+    /** Sets new Z dimension.
+     *
+     *  Note that the dataArray is NOT resized. This should be done separately with coreAllocate()
+     *
+     */
+    void setZdim(long int Zdim)
+    {
+        zdim = Zdim;
+        zyxdim=zdim*yxdim;
+        nzyxdim=ndim*zyxdim;
+    }
+
+    /** Sets new Y dimension.
+     *
+     *  Note that the dataArray is NOT resized. This should be done separately with coreAllocate()
+     *
+     */
+    void setYdim(long int Ydim)
+    {
+        ydim = Ydim;
+        yxdim=ydim*xdim;
+        zyxdim=zdim*yxdim;
+        nzyxdim=ndim*zyxdim;
+    }
+
+    /** Sets new X dimension.
+      *
+      *  Note that the dataArray is NOT resized. This should be done separately with coreAllocate()
+      *
+      */
+    void setXdim(long int Xdim)
+    {
+        xdim = Xdim;
+        yxdim=ydim*xdim;
+        zyxdim=zdim*yxdim;
+        nzyxdim=ndim*zyxdim;
+    }
+
+    /** Copy the shape parameters
+     *
+     */
+    void copyShape(const MultidimArray<T> &m)
+    {
+        ndim=m.ndim;
+        zdim=m.zdim;
+        ydim=m.ydim;
+        xdim=m.xdim;
+        yxdim=m.yxdim;
+        zyxdim=m.zyxdim;
+        nzyxdim=m.nzyxdim;
+        zinit=m.zinit;
+        yinit=m.yinit;
+        xinit=m.xinit;
+    }
+
+    /** Resize to a given size
+     *
+     * This function resize the actual array to the given size. The origin is
+     * not modified. If the actual array is larger than the pattern then the
+     * values outside the new size are lost, if it is smaller then 0's are
+     * added. An exception is thrown if there is no memory.
+     *
+     * @code
+     * V1.resize(3, 3, 2);
+     * @endcode
+     */
+    void resize(long int Ndim, long int Zdim, long int Ydim, long int Xdim)
+    {
+        if (Ndim*Zdim*Ydim*Xdim == nzyxdimAlloc && data != NULL)
+            return;
+
+        if (Xdim <= 0 || Ydim <= 0 || Zdim <= 0 || Ndim <= 0)
+        {
+            clear();
+            return;
+        }
+
+        // data can be NULL while xdim etc are set to non-zero values
+        // (This can happen for reading of images...)
+        // In that case, initialize data to zeros.
+        if (NZYXSIZE(*this) > 0 && data == NULL)
+        {
+            coreAllocate();
+            return;
+        }
+
+        // Ask for memory
+        size_t YXdim=Ydim*Xdim;
+        size_t ZYXdim=Zdim*YXdim;
+        size_t NZYXdim=Ndim*ZYXdim;
+        int    new_mFd = 0;
+        FileName   newMapFile;
+
+        T * new_data;
+
+        try
+        {
+            if (mmapOn)
+            {
+                newMapFile.initRandom(8);
+                newMapFile = newMapFile.addExtension("tmp");
+
+                if ( ( new_mFd = open(newMapFile.c_str(),  O_RDWR | O_CREAT | O_TRUNC,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) ) == -1 )
+                    REPORT_ERROR("MultidimArray::resize: Error creating map file.");
+                if ((lseek(new_mFd, NZYXdim*sizeof(T)-1, SEEK_SET) == -1) || (::write(new_mFd,"",1) == -1))
+                {
+                    close(new_mFd);
+                    REPORT_ERROR("MultidimArray::resize: Error 'stretching' the map file.");
+                }
+
+                if ( (new_data = (T*) mmap(0,NZYXdim*sizeof(T), PROT_READ | PROT_WRITE, MAP_SHARED, new_mFd, 0)) == (void*) -1 )
+                    REPORT_ERROR("MultidimArray::resize: mmap failed.");
+            }
+            else
+                new_data = new T [NZYXdim];
+        }
+        catch (std::bad_alloc &)
+        {
+            REPORT_ERROR( "Allocate: No space left");
+        }
+
+        // Copy needed elements, fill with 0 if necessary
+        for (long int l = 0; l < Ndim; l++)
+            for (long int k = 0; k < Zdim; k++)
+                for (long int i = 0; i < Ydim; i++)
+                    for (long int j = 0; j < Xdim; j++)
+                    {
+                        T val;
+                        if (k >= ZSIZE(*this))
+                            val = 0;
+                        else if (i >= YSIZE(*this))
+                            val = 0;
+                        else if (j >= XSIZE(*this))
+                            val = 0;
+                        else
+                            val = DIRECT_A3D_ELEM(*this, k, i, j);
+                        new_data[l*ZYXdim + k*YXdim+i*Xdim+j] = val;
+                    }
+
+        // deallocate old vector
+        coreDeallocate();
+
+        // assign *this vector to the newly created
+        data = new_data;
+        ndim = Ndim;
+        xdim = Xdim;
+        ydim = Ydim;
+        zdim = Zdim;
+        yxdim = Ydim * Xdim;
+        zyxdim = Zdim * yxdim;
+        nzyxdim = Ndim * zyxdim;
+        mFd = new_mFd;
+        mapFile = newMapFile;
+        nzyxdimAlloc = nzyxdim;
+    }
+
+    /** Resize a single 3D image
+     *
+     * This function assumes n is 1
+     * @code
+     * V1.resize(3, 3, 2);
+     * @endcode
+     */
+    void resize(long int Zdim, long int Ydim, long int Xdim)
+    {
+        resize(1, Zdim, Ydim, Xdim);
+    }
+
+    /** Resize a single 2D image
+     *
+     * This function assumes n and z are 1
+     * @code
+     * V1.resize(3, 2);
+     * @endcode
+     */
+    void resize(long int Ydim, long int Xdim)
+    {
+        resize(1, 1, Ydim, Xdim);
+    }
+
+    /** Resize a single 1D image
+     *
+     * This function assumes n and z and y are 1
+     * @code
+     * V1.resize(2);
+     * @endcode
+     */
+    void resize(long int Xdim)
+    {
+        resize(1, 1, 1, Xdim);
+    }
+
+    /** Resize according to a pattern.
+     *
+     * This function resize the actual array to the same size and origin
+     * as the input pattern. If the actual array is larger than the pattern
+     * then the trailing values are lost, if it is smaller then 0's are
+     * added at the end
+     *
+     * @code
+     * v2.resize(v1);
+     * // v2 has got now the same structure as v1
+     * @endcode
+     */
+    template<typename T1>
+    void resize(const MultidimArray<T1> &v)
+    {
+        if (NSIZE(*this) != NSIZE(v) || XSIZE(*this) != XSIZE(v) ||
+            YSIZE(*this) != YSIZE(v) || ZSIZE(*this) != ZSIZE(v) || data==NULL)
+            resize(NSIZE(v), ZSIZE(v), YSIZE(v), XSIZE(v));
+
+        STARTINGX(*this) = STARTINGX(v);
+        STARTINGY(*this) = STARTINGY(v);
+        STARTINGZ(*this) = STARTINGZ(v);
+    }
+
+    /** Returns the multidimArray N,Z, Y and X dimensions.
+     *
+     * @code
+     * V.getDimensions(Xdim, Ydim, Zdim, Ndim);
+     * @endcode
+     */
+    void getDimensions(long int& Xdim, long int& Ydim, long int& Zdim, long int &Ndim) const
+    {
+        Xdim = XSIZE(*this);
+        Ydim = YSIZE(*this);
+        Zdim = ZSIZE(*this);
+        Ndim = NSIZE(*this);
+    }
+
+    /** Returns the total size of the multidimArray
+     *
+     * @code
+     * if (V.getSize() > 1) ...
+     * @endcode
+     */
+    long int getSize() const
+    {
+        return NZYXSIZE(*this);
+    }
+
+    /** Returns the multidimArray dimension.
+     *
+     * @code
+     * int dim = V.getDim();
+     * @endcode
+     */
+    inline int getDim() const
+    {
+        if (NZYXSIZE(*this) < 1)
+            return 0;
+        if (ZSIZE(*this) > 1)
+            return 3;
+        if (YSIZE(*this) > 1)
+            return 2;
+        else
+            return 1;
+    }
+
+    /** Check dimension.
+     *
+     * returns true if the dimension is equal to the argument and false otherwise
+     * It also prints an error message in the latter case.
+     */
+#define checkDimension(dim) checkDimensionWithDebug(dim,__FILE__,__LINE__)
+    void checkDimensionWithDebug(int dim, const char *file, int line) const
+    {
+        if (getDim() != dim)
+        {
+            std::cerr<<" Check for dimension: "  << dim <<std::endl;
+            std::cerr << "MultidimArray shape: ";
+            printShape(std::cerr);
+            std::cerr << std::endl;
+            std::cerr << "Check called from file "<<file<<" line "<<line<<std::endl;
+            exit(1);
+        }
+    }
+
+    /** Get size.
+     *
+     * Returns the size of the object in a 4D vector. If the object is a matrix
+     * or a vector, then the higher order dimensions will be set to 1, ie,
+     * (Xdim, 1, 1) or (Xdim, Ydim, 1).
+     *
+     * This function is not ported to Python.
+     */
+    void getSize(int* size) const
+    {
+        size[0] = xdim;
+        size[1] = ydim;
+        size[2] = zdim;
+        size[3] = ndim;
+    }
+
+    /** Generic window routine (dim independent)
+     *
+     * This function will call to 3D,2D or 1D specific window routines
+     */
+    void window(long int n0, long int z0, long int y0, long int x0,
+                long int nF, long int zF, long int yF, long int xF,
+                T init_value = 0, long n = 0)
+    {
+        if (this->ndim >1)
+            REPORT_ERROR("stack windowing not implemented");
+        if (this->zdim >1)
+        {//call 3Dwindow
+            window( z0,  y0,  x0,
+                    zF,  yF,  xF,
+                    init_value ,n );
+        }
+        else if (this->ydim >1)
+        {//call 2Dwindow
+            window( y0,  x0,
+                    yF,  xF,
+                    init_value ,  n );
+
+        }
+        else if (this->xdim >1)
+        {//call 1Dwindow
+            window( x0,
+                    xF,
+                    init_value = 0,  n );
+        }
+    }
+
+    /** Put a 3D window to the nth volume
+     *
+     * The volume is windowed within the two positions given to this function.
+     * Indexes always refer to logical indexes. If a position is outside the
+     * actual matrix range then the matrix is padded init_value until the
+     * new position is reached. In the following example suppose that m1
+     * is the following and that the origin is (-1,-1,-1).
+     *
+     * @code
+     * slice 0
+     * [01 02 03          [
+     *  04 05 06           04 05 06 0
+     *  07 08 09]          07 08 09 0]
+     *
+     * ----->
+     *
+     * slice 1
+     * [11 12 13          [
+     *  14 15 16           14 15 16 0
+     *  17 18 19]          17 18 19 0]
+     * @endcode
+     *
+     * @code
+     * V1.window(0, 0, -1, 1, 1, 2);
+     * @endcode
+     */
+    void window(MultidimArray<T> &result, long int z0, long int y0, long int x0, long int zF, long int yF, long int xF,
+                T init_value = 0, long n = 0) const
+    {
+        result.resize(zF - z0 + 1, yF - y0 + 1, xF - x0 + 1);
+        result.zinit = z0;
+        result.yinit = y0;
+        result.xinit = x0;
+
+        for (long int k = z0; k <= zF; k++)
+            for (long int i = y0; i <= yF; i++)
+                for (long int j = x0; j <= xF; j++)
+                    if ((k >= STARTINGZ(*this) && k <= FINISHINGZ(*this)) &&
+                        (i >= STARTINGY(*this) && i <= FINISHINGY(*this)) &&
+                        (j >= STARTINGX(*this) && j <= FINISHINGX(*this)))
+                        A3D_ELEM(result, k, i, j) = NZYX_ELEM(*this, n, k, i, j);
+                    else
+                        A3D_ELEM(result, k, i, j) = init_value;
+    }
+
+    // As above but acts on itself
+    void window(long int z0, long int y0, long int x0, long int zF, long int yF, long int xF,
+                T init_value = 0, long n = 0)
+    {
+        MultidimArray<T> result;
+        window(result, z0, y0, x0, zF, yF, xF, init_value, n);
+        *this = result;
+    }
+
+    /** Put a 2D window to the nth matrix
+     *
+     * The matrix is windowed within the two positions given to this function.
+     * Indexes always refer to logical indexes. If a position is outside the
+     * actual matrix range then the matrix is padded with init_value until the
+     * new position is reached. In the following examples suppose that m1 is the
+     * following and that the origin is (-1,-1).
+     *
+     * @code
+     *      [1 2 3               [1 2 3 0
+     * m1 =  4 5 6    --->  m1 =  4 5 6 0
+     *       7 8 9]               7 8 9 0]
+     *
+     * @endcode
+     *
+     * @code
+     * m1.window(-1, -1, 1, 2);
+     * @endcode
+     */
+    void window(MultidimArray<T> &result, long int y0, long int x0, long int yF, long int xF, T init_value = 0, long n = 0) const
+    {
+        result.resize(yF - y0 + 1, xF - x0 + 1);
+        STARTINGY(result) = y0;
+        STARTINGX(result) = x0;
+
+        FOR_ALL_ELEMENTS_IN_ARRAY2D(result)
+        if (j >= STARTINGX(*this) && j <= FINISHINGX(*this) &&
+            i >= STARTINGY(*this) && i <= FINISHINGY(*this))
+            A2D_ELEM(result, i, j) = NZYX_ELEM(*this, n, 0, i, j);
+        else
+            A2D_ELEM(result, i, j) = init_value;
+
+    }
+
+    // As above but acts on itself
+    void window(long int y0, long int x0, long int yF, long int xF, T init_value = 0, long n = 0)
+    {
+        MultidimArray<T> result;
+        window(result, y0, x0, yF, xF, init_value, n);
+        *this = result;
+    }
+
+    /** Put a 1D window to the nth vector
+     *
+     * The vector is windowed within the two indexes given to this function.
+     * Indexes always refer to logical indexes. If an index is outside the
+     * actual vector range then the vector is padded winit_value. In the
+     * following examples suppose that v1=[-2 -1 0 1 2] and that the origin is
+     * -2.
+     *
+     * @code
+     * v1.window(-1, 2); // v1=[-1 0 1 2]; v1.startingX() == -1
+     *
+     * v1.window(-3, 1); // v1=[0 -2 -1 0 1]; v1.startingX() == -3
+     * @endcode
+     */
+    void window(MultidimArray<T> &result, long int x0, long int xF, T init_value = 0, long n = 0) const
+    {
+    	result.resize(xF - x0 + 1);
+        STARTINGX(result) = x0;
+
+        for (long int j = x0; j <= xF; j++)
+            if (j >= STARTINGX(*this) && j <= FINISHINGX(*this))
+                A1D_ELEM(result, j) = NZYX_ELEM(*this, n, 0, 0, j);
+            else
+                A1D_ELEM(result, j) = init_value;
+
+    }
+
+    // As above but acts on itself
+    void window(long int x0, long int xF, T init_value = 0, long n = 0)
+    {
+    	MultidimArray<T> result;
+    	window(result, x0, xF, init_value, n);
+        *this = result;
+    }
+
+    /** Print shape of multidimensional array.
+     *
+     * This function shows the size, starting and finishing indexes of the
+     * given array. No end of line is printed neither at the beginning nor
+     * the end.
+     *
+     * @code
+     * v.printShape();
+     *
+     * std::ofstream fh;
+     * ...;
+     * v.printShape(fh);
+     * @endcode
+     */
+    void printShape(std::ostream& out = std::cout) const
+    {
+        if (NSIZE(*this) > 1)
+            out << " Number of images = "<<NSIZE(*this);
+
+        int dim = getDim();
+        if (dim == 3)
+            out<< " Size(Z,Y,X): " << ZSIZE(*this) << "x" << YSIZE(*this) << "x" << XSIZE(*this)
+            << " k=[" << STARTINGZ(*this) << ".." << FINISHINGZ(*this) << "]"
+            << " i=[" << STARTINGY(*this) << ".." << FINISHINGY(*this) << "]"
+            << " j=[" << STARTINGX(*this) << ".." << FINISHINGX(*this) << "]";
+        else if (dim == 2)
+            out<< " Size(Y,X): " << YSIZE(*this) << "x" << XSIZE(*this)
+            << " i=[" << STARTINGY(*this) << ".." << FINISHINGY(*this) << "]"
+            << " j=[" << STARTINGX(*this) << ".." << FINISHINGX(*this) << "]";
+        else if (dim == 1)
+            out<< " Size(X): " << XSIZE(*this)
+            << " j=[" << STARTINGX(*this) << ".." << FINISHINGX(*this) << "]";
+        else
+            out << " Empty MultidimArray!";
+        out<<"\n";
+
+    }
+
+    /** Same shape.
+     *
+     * Returns true if this object has got the same shape (origin and size)
+     * than the argument
+     */
+    template <typename T1>
+    inline bool sameShape(const MultidimArray<T1>& op) const
+    {
+        return (NSIZE(*this) == NSIZE(op) &&
+                XSIZE(*this) == XSIZE(op) &&
+                YSIZE(*this) == YSIZE(op) &&
+                ZSIZE(*this) == ZSIZE(op) &&
+                STARTINGX(*this) == STARTINGX(op) &&
+                STARTINGY(*this) == STARTINGY(op) &&
+                STARTINGZ(*this) == STARTINGZ(op));
+    }
+
+
+    /** Outside for 3D matrices
+     *
+     * TRUE if the logical index given is outside the definition region of this
+     * array.
+     */
+    bool outside(long int k, long int i, long int j) const
+    {
+        return (j < STARTINGX(*this) || j > FINISHINGX(*this) ||
+                i < STARTINGY(*this) || i > FINISHINGY(*this) ||
+                k < STARTINGZ(*this) || k > FINISHINGZ(*this));
+    }
+
+    /** Outside for 2D matrices
+     *
+     * TRUE if the logical index given is outside the definition region of this
+     * array.
+     */
+    bool outside(long int i, long int j) const
+    {
+        return (j < STARTINGX(*this) || j > FINISHINGX(*this) ||
+                i < STARTINGY(*this) || i > FINISHINGY(*this));
+    }
+
+    /** Outside for 1D matrices
+     *
+     * TRUE if the logical index given is outside the definition region of this
+     * array.
+     */
+    bool outside(long int i) const
+    {
+        return (i < STARTINGX(*this) || i > FINISHINGX(*this));
+    }
+
+    /** Outside
+     *
+     * TRUE if the logical index given is outside the definition region of this
+     * array.
+     */
+    bool outside(const Matrix1D<double> &r) const
+    {
+        if (r.size() < 1)
+        {
+            REPORT_ERROR( "Outside: index vector has not got enough components");
+        }
+        else if (r.size()==1)
+        {
+            return (XX(r) < STARTINGX(*this) || XX(r) > FINISHINGX(*this));
+        }
+        else if (r.size()==2)
+        {
+            return (XX(r) < STARTINGX(*this) || XX(r) > FINISHINGX(*this) ||
+                    YY(r) < STARTINGY(*this) || YY(r) > FINISHINGY(*this));
+        }
+        else if (r.size()==3)
+        {
+            return (XX(r) < STARTINGX(*this) || XX(r) > FINISHINGX(*this) ||
+                    YY(r) < STARTINGY(*this) || YY(r) > FINISHINGY(*this) ||
+                    ZZ(r) < STARTINGZ(*this) || ZZ(r) > FINISHINGZ(*this));
+        }
+        else
+            REPORT_ERROR("Outside: index vector has too many components");
+    }
+
+    /** Returns Y dimension.
+     */
+    inline long int rowNumber() const
+    {
+        return ydim;
+    }
+
+    /** Returns X dimension.
+     */
+    inline long int colNumber() const
+    {
+        return xdim;
+    }
+
+    /** Set logical origin in Xmipp fashion.
+     *
+     * This function adjust the starting points in the array such that the
+     * center of the array is defined in the Xmipp fashion.
+     *
+     * @code
+     * V.setXmippOrigin();
+     * @endcode
+     */
+    void setXmippOrigin()
+    {
+        zinit = FIRST_XMIPP_INDEX(zdim);
+        yinit = FIRST_XMIPP_INDEX(ydim);
+        xinit = FIRST_XMIPP_INDEX(xdim);
+    }
+
+    /** Move origin to.
+      *
+      * This function adjust logical indexes such that the Xmipp origin of the
+      * array moves to the specified position. For instance, an array whose x
+      * indexes go from -1 to 1, if we move the origin to 4, then the x indexes
+      * go from 3 to 5. This is very useful for convolution operations where you
+      * only need to move the logical starting of the array.
+      *
+      */
+    void moveOriginTo(long int k, long int i, long int j)
+    {
+        zinit = k + FIRST_XMIPP_INDEX(zdim);
+        yinit = i + FIRST_XMIPP_INDEX(ydim);
+        xinit = j + FIRST_XMIPP_INDEX(xdim);
+    }
+
+    /** Move origin to.
+      *
+      * This function adjust logical indexes such that the Xmipp origin of the
+      * array moves to the specified position. For instance, an array whose x
+      * indexes go from -1 to 1, if we move the origin to 4, then the x indexes
+      * go from 3 to 5. This is very useful for convolution operations where you
+      * only need to move the logical starting of the array.
+      *
+      */
+    void moveOriginTo(long int i, long int j)
+    {
+        yinit = i + FIRST_XMIPP_INDEX(ydim);
+        xinit = j + FIRST_XMIPP_INDEX(xdim);
+    }
+
+    /** Returns the first valid logical Z index.
+      */
+    inline long int startingZ() const
+    {
+        return zinit;
+    }
+
+    /** Returns the last valid logical Z index.
+     */
+    inline long int finishingZ() const
+    {
+        return zinit + zdim - 1;
+    }
+
+    /** Returns the first valid logical Y index.
+     */
+    inline long int startingY() const
+    {
+        return yinit;
+    }
+
+    /** Returns the last valid logical Y index.
+     */
+    inline long int finishingY() const
+    {
+        return yinit + ydim - 1;
+    }
+
+    /** Returns the first valid logical X index.
+     */
+    inline long int startingX() const
+    {
+        return xinit;
+    }
+
+    /** Returns the last valid logical X index.
+     */
+    inline long int finishingX() const
+    {
+        return xinit + xdim - 1;
+    }
+
+    /** IsCorner (in 2D or 3D matrix)
+     *
+     * TRUE if the logical index given is a corner of the definition region of this
+     * array.
+     */
+    bool isCorner(const Matrix1D< double >& v) const
+    {
+        if (v.size() < 2)
+            REPORT_ERROR( "isCorner: index vector has got not enough components");
+
+        else if (XSIZE(*this)==2)
+            return ((XX(v) == STARTINGX(*this)  && YY(v) == STARTINGY(*this))  ||
+                    (XX(v) == STARTINGX(*this)  && YY(v) == FINISHINGY(*this)) ||
+                    (XX(v) == FINISHINGX(*this) && YY(v) == STARTINGY(*this))  ||
+                    (XX(v) == FINISHINGX(*this) && YY(v) == FINISHINGY(*this)));
+        else if (XSIZE(*this)==3)
+            return ((XX(v) == STARTINGX(*this)  && YY(v) == STARTINGY(*this)  && ZZ(v) == STARTINGZ(*this)) ||
+                    (XX(v) == STARTINGX(*this)  && YY(v) == FINISHINGY(*this) && ZZ(v) == STARTINGZ(*this)) ||
+                    (XX(v) == FINISHINGX(*this) && YY(v) == STARTINGY(*this)  && ZZ(v) == STARTINGZ(*this))  ||
+                    (XX(v) == FINISHINGX(*this) && YY(v) == FINISHINGY(*this) && ZZ(v) == STARTINGZ(*this)) ||
+                    (XX(v) == STARTINGX(*this)  && YY(v) == STARTINGY(*this)  && ZZ(v) == FINISHINGZ(*this)) ||
+                    (XX(v) == STARTINGX(*this)  && YY(v) == FINISHINGY(*this) && ZZ(v) == FINISHINGZ(*this)) ||
+                    (XX(v) == FINISHINGX(*this) && YY(v) == STARTINGY(*this)  && ZZ(v) == FINISHINGZ(*this))  ||
+                    (XX(v) == FINISHINGX(*this) && YY(v) == FINISHINGY(*this) && ZZ(v) == FINISHINGZ(*this)));
+        else
+            REPORT_ERROR( "isCorner: index vector has too many components");
+    }
+    //@}
+
+    ///@name Access to the pixel values
+    //@{
+
+    /** Volume element access via double vector.
+     *
+     * Returns the value of a matrix logical position, but this time the
+     * element position is determined by a R3 vector. The elements can be used
+     * either by value or by reference. An exception is thrown if the index is
+     * outside the logical range. Pay attention in the following example that
+     * we are accessing the same element as in the previous function but, now
+     * we have to give first the X position because we are building first a
+     * vector of the form (x,y,z).
+     *
+     * @code
+     * V(vectorR3(1, -2, 0)) = 1;
+     * val = V(vectorR3(1, -2, 0));
+     * @endcode
+     */
+    T& operator()(const Matrix1D< double >& v) const
+    {
+        switch (VEC_XSIZE(v))
+        {
+        case 1:
+            return A1D_ELEM((*this), ROUND(XX(v)));
+        case 2:
+            return A2D_ELEM((*this), ROUND(YY(v)), ROUND(XX(v)));
+        case 3:
+            return A3D_ELEM((*this), ROUND(ZZ(v)), ROUND(YY(v)), ROUND(XX(v)));
+        }
+    }
+
+    /** Volume element access via integer vector.
+     */
+    T& operator()(const Matrix1D< long int >& v) const
+    {
+        switch (VEC_XSIZE(v))
+        {
+        case 1:
+            return A1D_ELEM((*this), XX(v));
+        case 2:
+            return A2D_ELEM((*this), YY(v), XX(v));
+        case 3:
+            return A3D_ELEM((*this), ZZ(v), YY(v), XX(v));
+        }
+    }
+
+    /** 4D element access via index.
+    *
+    * Returns the value of a matrix logical position. In our example we could
+    * access from v(0, 0,-2,-1) to v(0, 1,2,1). The elements can be used either by
+    * value or by reference. An exception is thrown if the index is outside
+    * the logical range. Be careful that the argument order is (Z,Y,X).
+    *
+    * @code
+    * V(0, 0, -2, 1) = 1;
+    * val = V(0, 0, -2, 1);
+    * @endcode
+    */
+    inline T& operator()(long n, long int k, long int i, long int j) const
+    {
+        return NZYX_ELEM(*this, n, k, i, j);
+    }
+
+    /** 3D element access via index.
+    *
+    * Returns the value of a matrix logical position. In our example we could
+    * access from v(0,-2,-1) to v(1,2,1). The elements can be used either by
+    * value or by reference. An exception is thrown if the index is outside
+    * the logical range. Be careful that the argument order is (Z,Y,X).
+    *
+    * @code
+    * V(0, -2, 1) = 1;
+    * val = V(0, -2, 1);
+    * @endcode
+    */
+    inline T& operator()(long int k, long int i, long int j) const
+    {
+        return A3D_ELEM(*this, k, i, j);
+    }
+
+    /** 3D element access via index (getVoxel).
+    *
+    * Same function as operator() but with a name. Needed by swig.
+    *
+    */
+    inline T getVoxel(long int k, long int i, long int j) const
+    {
+        return A3D_ELEM(*this, k, i, j);
+    }
+
+    /** 3D element access via index (setVoxel).
+    *
+    * Same function as operator() but with a name. Needed by swig.
+    *
+    */
+    inline void setVoxel(long int k, long int i, long int j, T newval)
+    {
+        A3D_ELEM(*this, k, i, j)=newval;
+    }
+
+    /** Matrix element access via index
+     *
+     * Returns the value of a matrix logical position. In our example we could
+     * access from v(-2,-1) to v(2,1). The elements can be used either by value
+     * or by reference. An exception is thrown if the index is outside the
+     * logical range. The first argument is the Y position and the second the X
+     * position.
+     *
+     * @code
+     * m(-2, 1) = 1;
+     * val = m(-2, 1);
+     * @endcode
+     */
+    inline T& operator()(long int i, long int j) const
+    {
+        return A2D_ELEM(*this, i, j);
+    }
+
+    /** Vector element access
+     *
+     * Returns the value of a vector logical position. In our example we could
+     * access from v(-2) to v(2). The elements can be used either by value or by
+     * reference. An exception is thrown if the index is outside the logical
+     * range.
+     *
+     * @code
+     * v(-2) = 1;
+     * val = v(-2);
+     * @endcode
+     */
+    inline T& operator()(long int i) const
+    {
+        return A1D_ELEM(*this, i);
+    }
+
+    /** Get a single 1,2 or 3D image from a multi-image array
+     *
+     * This function extracts a single-image array from a multi-image one.
+     * @code
+     * V.getImage(0, m);
+     * @endcode
+     */
+    void getImage(long n, MultidimArray<T>& M) const
+    {
+        if (XSIZE(*this) == 0)
+        {
+            M.clear();
+            return;
+        }
+
+        if (n > NSIZE(*this))
+            REPORT_ERROR(" Multidimarray getImage: n larger than NSIZE");
+
+        M.resize(1, ZSIZE(*this), YSIZE(*this), XSIZE(*this));
+        FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(M)
+        DIRECT_A2D_ELEM(M, i, j) = DIRECT_NZYX_ELEM(*this, n, k, i, j);
+
+        STARTINGX(M) = STARTINGX(*this);
+        STARTINGY(M) = STARTINGY(*this);
+        STARTINGZ(M) = STARTINGZ(*this);
+    }
+
+    /** Set a single 1,2 or 3D image in a multi-image array
+     *
+     * This function sets a single-image array in a multi-image one.
+     * @code
+     * V.setImage(0, m);
+     * @endcode
+     */
+    void setImage(long n, MultidimArray<T>& M) const
+    {
+        if (xdim == 0)
+            return;
+
+        if (n < 0 || n > NSIZE(*this))
+            REPORT_ERROR( "setImage: MultidimArray subscript (n) out of range");
+
+        if ( ZSIZE(M) != ZSIZE(*this) || YSIZE(M) != YSIZE(*this) || XSIZE(M) != XSIZE(*this))
+            REPORT_ERROR( "setImage: MultidimArray dimensions different from the input image ones");
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(M)
+			DIRECT_NZYX_ELEM(*this, n, k, i, j) = DIRECT_A3D_ELEM(M, k, i, j);
+
+    }
+
+    /** 2D Slice access for reading.
+     *
+     * This function returns a slice (a 2D matrix) corresponding to the choosen
+     * slice inside the nth 3D matrix, the numbering of the slices is also logical not
+     * physical. This function differs from the previous one in that this one
+     * cuts and assign in a single step instead of in two steps, as in
+     * the previous example.
+     *
+     * @code
+     * V.slice(0, m);
+     * @endcode
+     */
+    void getSlice(long int k, MultidimArray<T>& M, char axis = 'Z', long n = 0) const
+    {
+        if (XSIZE(*this) == 0)
+        {
+            M.clear();
+            return;
+        }
+
+        switch (axis)
+        {
+        case 'Z':
+            if (k < STARTINGZ(*this) || k > FINISHINGZ(*this))
+                REPORT_ERROR( "Slice: Multidim subscript (k) out of range");
+
+            k = k - STARTINGZ(*this);
+            M.resize(1, 1, YSIZE(*this), XSIZE(*this));
+            FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(M)
+            DIRECT_A2D_ELEM(M, i, j) = DIRECT_NZYX_ELEM(*this, n, k, i, j);
+            STARTINGX(M) = STARTINGX(*this);
+            STARTINGY(M) = STARTINGY(*this);
+            break;
+        case 'Y':
+            if (k < STARTINGY(*this) || k > FINISHINGY(*this))
+                REPORT_ERROR( "Slice: Multidim subscript (i) out of range");
+
+            k = k - STARTINGY(*this);
+            M.resize(ZSIZE(*this), XSIZE(*this));
+            FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(M)
+            DIRECT_A2D_ELEM(M, i, j) = DIRECT_NZYX_ELEM(*this, n, i, k, j);
+            STARTINGX(M) = STARTINGX(*this);
+            STARTINGY(M) = STARTINGZ(*this);
+            break;
+        case 'X':
+            if (k < STARTINGX(*this) || k > FINISHINGX(*this))
+                REPORT_ERROR( "Slice: Multidim subscript (j) out of range");
+
+            k = k - STARTINGX(*this);
+            M.resize(ZSIZE(*this), YSIZE(*this));
+            FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(M)
+            DIRECT_A2D_ELEM(M, i, j) = DIRECT_NZYX_ELEM(*this, n, i, j, k);
+            STARTINGX(M) = STARTINGY(*this);
+            STARTINGY(M) = STARTINGZ(*this);
+            break;
+        default:
+            REPORT_ERROR( (std::string) "Slice: not supported axis " + axis);
+        }
+    }
+
+    /** Slice access for writing.
+     *
+     * This function sets a 2D matrix corresponding to the choosen slice inside the nth
+     * volume, the numbering of the slices is also logical not physical.
+     *
+     * @code
+     * // Copies slice 0 in slice 1
+     * V.setSlice(1, (V.slice(0)));
+     * @endcode
+     */
+    void setSlice(long int k, const MultidimArray<T>& v, long n = 0)
+    {
+        if (xdim == 0)
+            return;
+
+        if (k < STARTINGZ(*this) || k > FINISHINGZ(*this))
+            REPORT_ERROR( "setSlice: MultidimArray subscript (k) out of range");
+
+        if (v.rowNumber() != YSIZE(*this) || v.colNumber() != XSIZE(*this))
+            REPORT_ERROR( "setSlice: MultidimArray dimensions different from the matrix ones");
+
+        k = k - STARTINGZ(*this);
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(v)
+        DIRECT_NZYX_ELEM(*this, n, k, i, j) = DIRECT_A2D_ELEM(v, i, j);
+    }
+
+    /** Get Column
+     *
+     * This function returns a column vector corresponding to the
+     * choosen column.
+     *
+     * @code
+     * std::vector< double > v;
+     * m.getCol(-1, v);
+     * @endcode
+     */
+    void getCol(long int j, MultidimArray<T>& v) const
+    {
+        if (xdim == 0 || ydim == 0)
+        {
+            v.clear();
+            return;
+        }
+
+        if (j < 0 || j >= xdim)
+            REPORT_ERROR("getCol: Matrix subscript (j) greater than matrix dimension");
+
+        v.resize(ydim);
+        for (long int i = 0; i < ydim; i++)
+            v(i) = (*this)(i, j);
+    }
+
+    /** Set Column
+     *
+     * This function sets a column vector corresponding to the choosen column
+     * inside matrix.
+     *
+     * @code
+     * m.setCol(0, (m.row(1)).transpose()); // Copies row 1 in column 0
+     * @endcode
+     */
+    void setCol(long int j, const MultidimArray<T>& v)
+    {
+        if (xdim == 0 || ydim == 0)
+            REPORT_ERROR( "setCol: Target matrix is empty");
+
+        if (j < 0 || j>= xdim)
+            REPORT_ERROR( "setCol: Matrix subscript (j) out of range");
+
+        if (v.xdim != ydim)
+            REPORT_ERROR( "setCol: Vector dimension different from matrix one");
+
+        for (long int i = 0; i < ydim; i++)
+            (*this)(i, j) = v(i);
+    }
+
+    /** Get row
+     *
+     * This function returns a row vector corresponding to the choosen
+     * row inside the nth 2D matrix, the numbering of the rows is also
+     * logical not physical.
+     *
+     * @code
+     * std::vector< double > v;
+     * m.getRow(-2, v);
+     * @endcode
+     */
+    void getRow(long int i, MultidimArray<T>& v) const
+    {
+        if (xdim == 0 || ydim == 0)
+        {
+            v.clear();
+            return;
+        }
+
+        if (i < 0 || i >= ydim)
+            REPORT_ERROR( "getRow: Matrix subscript (i) greater than matrix dimension");
+
+        v.resize(xdim);
+        for (long int j = 0; j < xdim; j++)
+            v(j) = (*this)(i, j);
+    }
+
+    /** Set Row
+     *
+     * This function sets a row vector corresponding to the choosen row in the 2D Matrix
+     *
+     * @code
+     * m.setRow(-2, m.row(1)); // Copies row 1 in row -2
+     * @endcode
+     */
+    void setRow(long int i, const MultidimArray<T>& v)
+    {
+        if (xdim == 0 || ydim == 0)
+            REPORT_ERROR( "setRow: Target matrix is empty");
+
+        if (i < 0 || i >= ydim)
+            REPORT_ERROR( "setRow: Matrix subscript (i) out of range");
+
+        if (v.xdim != xdim)
+            REPORT_ERROR( "setRow: Vector dimension different from matrix one");
+
+        for (long int j = 0; j < xdim; j++)
+            (*this)(i, j) = v(j);
+    }
+
+    /** 3D Logical to physical index translation.
+     *
+     * This function returns the physical position of a logical one.
+     *
+     * @code
+     * m.toPhysical(k_log, i_log, j_log, k_phys, i_phys, j_phys);
+     * @endcode
+     */
+    void toPhysical(long int k_log, long int i_log, long int j_log,
+                    long int& k_phys, long int& i_phys, long int& j_phys) const
+    {
+        k_phys = k_log - STARTINGZ(*this);
+        i_phys = i_log - STARTINGY(*this);
+        j_phys = j_log - STARTINGX(*this);
+    }
+
+    /** 3D Physical to logical index translation.
+     *
+     * This function returns the logical position of a physical one.
+     *
+     * @code
+     * m.toLogical(i_phys, j_phys, i_log, j_log);
+     * @endcode
+     */
+    void toLogical(long int k_phys, long int i_phys, long int j_phys,
+                   long int& k_log, long int& i_log, long int& j_log) const
+    {
+        k_log = k_phys + STARTINGZ(*this);
+        i_log = i_phys + STARTINGY(*this);
+        j_log = j_phys + STARTINGX(*this);
+    }
+
+    /** 2D Logical to physical index translation
+     *
+     * This function returns the physical position of a logical one.
+     *
+     * @code
+     * m.toPhysical(i_log, j_log, i_phys, j_phys);
+     * @endcode
+     */
+    void toPhysical(long int i_log, long int j_log, long int& i_phys, long int& j_phys) const
+    {
+        i_phys = i_log - STARTINGY(*this);
+        j_phys = j_log - STARTINGX(*this);
+    }
+
+    /** 2D Physical to logical index translation
+     *
+     * This function returns the logical position of a physical one.
+     *
+     * @code
+     * m.toLogical(i_phys, j_phys, i_log, j_log);
+     * @endcode
+     */
+    void toLogical(long int i_phys, long int j_phys, long int &i_log, long int& j_log) const
+    {
+        i_log = i_phys + STARTINGY(*this);
+        j_log = j_phys + STARTINGX(*this);
+    }
+
+    /** 1D Logical to physical index translation
+     *
+     * This function returns the physical position of a logical one.
+     *
+     * @code
+     * v.toPhysical(i_log, i_phys);
+     * @endcode
+     */
+    void toPhysical(long int i_log, long int& i_phys) const
+    {
+        i_phys = i_log - STARTINGX(*this);
+    }
+
+    /** 1D Physical to logical index translation.
+     *
+     * This function returns the logical position of a physical one.
+     *
+     * @code
+     * v.toLogical(i_phys, i_log);
+     * @endcode
+     */
+    void toLogical(long int i_phys, long int& i_log) const
+    {
+        i_log = i_phys + STARTINGX(*this);
+    }
+
+    /** Interpolates the value of the nth 3D matrix M at the point (x,y,z).
+     *
+     * (x,y,z) are in logical coordinates.
+     */
+    T interpolatedElement3D(double x, double y, double z, T outside_value = (T) 0, long int n = 0)
+    {
+        long int x0 = FLOOR(x);
+        double fx = x - x0;
+        long int x1 = x0 + 1;
+
+        long int y0 = FLOOR(y);
+        double fy = y - y0;
+        long int y1 = y0 + 1;
+
+        long int z0 = FLOOR(z);
+        double fz = z - z0;
+        long int z1 = z0 + 1;
+
+        T d000 = (outside(z0, y0, x0)) ? outside_value : NZYX_ELEM(*this, n, z0, y0, x0);
+        T d001 = (outside(z0, y0, x1)) ? outside_value : NZYX_ELEM(*this, n, z0, y0, x1);
+        T d010 = (outside(z0, y1, x0)) ? outside_value : NZYX_ELEM(*this, n, z0, y1, x0);
+        T d011 = (outside(z0, y1, x1)) ? outside_value : NZYX_ELEM(*this, n, z0, y1, x1);
+        T d100 = (outside(z1, y0, x0)) ? outside_value : NZYX_ELEM(*this, n, z1, y0, x0);
+        T d101 = (outside(z1, y0, x1)) ? outside_value : NZYX_ELEM(*this, n, z1, y0, x1);
+        T d110 = (outside(z1, y1, x0)) ? outside_value : NZYX_ELEM(*this, n, z1, y1, x0);
+        T d111 = (outside(z1, y1, x1)) ? outside_value : NZYX_ELEM(*this, n, z1, y1, x1);
+
+        double dx00 = LIN_INTERP(fx, (double) d000, (double) d001);
+        double dx01 = LIN_INTERP(fx, (double) d100, (double) d101);
+        double dx10 = LIN_INTERP(fx, (double) d010, (double) d011);
+        double dx11 = LIN_INTERP(fx, (double) d110, (double) d111);
+        double dxy0 = LIN_INTERP(fy, (double) dx00, (double) dx10);
+        double dxy1 = LIN_INTERP(fy, (double) dx01, (double) dx11);
+
+        return (T) LIN_INTERP(fz, dxy0, dxy1);
+    }
+
+    /** Interpolates the value of the nth 2D matrix M at the point (x,y)
+     *
+     * Bilinear interpolation. (x,y) are in logical coordinates.
+     */
+    inline T interpolatedElement2D(double x, double y, T outside_value = (T) 0, long int n = 0) const
+    {
+        long int x0 = FLOOR(x);
+        double fx = x - x0;
+        long int x1 = x0 + 1;
+        long int y0 = FLOOR(y);
+        double fy = y - y0;
+        long int y1 = y0 + 1;
+
+        T d00 = outside(y0, x0) ? outside_value : NZYX_ELEM(*this, n, 0, y0, x0);
+        T d10 = outside(y1, x0) ? outside_value : NZYX_ELEM(*this, n, 0, y1, x0);
+        T d11 = outside(y1, x1) ? outside_value : NZYX_ELEM(*this, n, 0, y1, x1);
+        T d01 = outside(y0, x1) ? outside_value : NZYX_ELEM(*this, n, 0, y0, x1);
+
+        double d0 = (T) LIN_INTERP(fx, (double) d00, (double) d01);
+        double d1 = (T) LIN_INTERP(fx, (double) d10, (double) d11);
+        return (T) LIN_INTERP(fy, d0, d1);
+    }
+    //@}
+
+    /// @name Statistics functions
+    //@{
+
+    /** Print statistics in current line.
+     *
+     * No end of line character is written after this print out.
+     *
+     * @code
+     * a.computeStats();
+     * std::cout << "Statistics of variable a ";
+     * a.printStats();
+     * std::cout << std::endl;
+     * @endcode
+     */
+    void printStats(std::ostream& out = std::cout) const
+    {
+        T minval, maxval;
+        double avgval, devval;
+
+        computeStats(avgval, devval, minval, maxval);
+
+        out.setf(std::ios::showpoint);
+        int old_prec = out.precision(7);
+
+        out << " min= ";
+        out.width(9);
+        out << minval;
+        out << " max= ";
+        out.width(9);
+        out << maxval;
+        out << " avg= ";
+        out.width(9);
+        out << avgval;
+        out << " dev= ";
+        out.width(9);
+        out << devval;
+
+        out.precision(old_prec);
+    }
+
+    /** Maximum of the values in the array.
+     *
+     * The returned value is of the same type as the type of the array.
+     */
+    T computeMax() const
+    {
+        if (NZYXSIZE(*this) <= 0)
+            return static_cast< T >(0);
+
+        T maxval = data[0];
+
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        if (*ptr > maxval)
+            maxval = *ptr;
+
+        return maxval;
+    }
+
+    /** Minimum of the values in the array.
+     *
+     * The returned value is of the same type as the type of the array.
+     */
+    T computeMin() const
+    {
+        if (NZYXSIZE(*this) <= 0)
+            return static_cast< T >(0);
+
+        T minval = data[0];
+
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        if (*ptr < minval)
+            minval = *ptr;
+
+        return minval;
+    }
+
+    /** 4D Indices for the minimum element.
+     *
+     * This function returns the index of the minimum element of an array.
+     * array(l,k,i,j). Returns -1 if the array is empty
+     */
+    void minIndex(long int &lmin, long int& kmin, long int& imin, long int& jmin) const
+    {
+        if (XSIZE(*this) == 0)
+        {
+            lmin = kmin = imin = jmin = -1;
+            return;
+        }
+
+        kmin = STARTINGZ(*this);
+        imin = STARTINGY(*this);
+        jmin = STARTINGX(*this);
+        lmin = 0;
+        T minval = NZYX_ELEM(*this, lmin, kmin, imin, jmin);
+
+
+        FOR_ALL_NZYX_ELEMENTS_IN_MULTIDIMARRAY(*this)
+        if (NZYX_ELEM(*this, l, k, i, j) > minval)
+        {
+            minval = NZYX_ELEM(*this, l, k, i, j);
+            lmin = l;
+            kmin = k;
+            imin = i;
+            jmin = j;
+        }
+
+    }
+
+    /** 3D Indices for the minimum element.
+     *
+     * This function just calls to the 4D function
+     */
+    void minIndex(long int& kmin, long int& imin, long int& jmin) const
+    {
+        long int zeroInt=0;
+        minIndex(zeroInt,kmin,imin,jmin);
+    }
+
+    /** 2D Indices for the minimum element.
+     *
+     * This function just calls to the 4D function
+     */
+    void minIndex(long int& imin, long int& jmin) const
+    {
+        long int zeroInt=0;
+        minIndex(zeroInt,zeroInt,imin,jmin);
+    }
+
+    /** 1D Indices for the minimum element.
+     *
+     * This function just calls to the 4D function
+     */
+    void minIndex(long int& jmin) const
+    {
+        long int zeroInt=0;
+        minIndex(zeroInt,zeroInt,zeroInt,jmin);
+    }
+
+    /** 4D Indices for the maximum element.
+     *
+     * This function returns the index of the maximum element of an array.
+     * array(l,k,i,j). Returns -1 if the array is empty
+     */
+    void maxIndex(long int &lmax, long int& kmax, long int& imax, long int& jmax) const
+    {
+        if (XSIZE(*this) == 0)
+        {
+            lmax = kmax = imax = jmax = -1;
+            return;
+        }
+
+        kmax = STARTINGZ(*this);
+        imax = STARTINGY(*this);
+        jmax = STARTINGX(*this);
+        lmax = 0;
+        T maxval = NZYX_ELEM(*this, lmax, kmax, imax, jmax);
+
+        FOR_ALL_NZYX_ELEMENTS_IN_MULTIDIMARRAY(*this)
+        if (NZYX_ELEM(*this, l, k, i, j) > maxval)
+        {
+            maxval = NZYX_ELEM(*this, l, k, i, j);
+            lmax = l;
+            kmax = k;
+            imax = i;
+            jmax = j;
+        }
+    }
+
+    /** 3D Indices for the maximum element.
+     *
+     * This function just calls to the 4D function
+     */
+    void maxIndex(long int& kmax, long int& imax, long int& jmax) const
+    {
+        long int dum;
+        maxIndex(dum, kmax, imax, jmax);
+    }
+
+    /** 2D Indices for the maximum element.
+     *
+     * This function just calls to the 4D function
+     */
+    void maxIndex(long int& imax, long int& jmax) const
+    {
+        long int dum;
+        maxIndex(dum, dum, imax, jmax);
+    }
+
+    /** 1D Indices for the maximum element.
+     *
+     * This function just calls to the 4D function
+     */
+    void maxIndex(long int& jmax) const
+    {
+        long int dum;
+        maxIndex(dum, dum, dum, jmax);
+    }
+
+    /** Minimum and maximum of the values in the array.
+     *
+     * As doubles.
+     */
+    void computeDoubleMinMax(double& minval, double& maxval) const
+    {
+        if (NZYXSIZE(*this) <= 0)
+            return;
+
+        minval = maxval = static_cast< double >(data[0]);
+
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        {
+            T val=*ptr;
+            if (val < minval)
+                minval = static_cast< double >(val);
+            else if (val > maxval)
+                maxval = static_cast< double >(val);
+        }
+    }
+
+    /** Average of the values in the array.
+     *
+     * The returned value is always double, independently of the type of the
+     * array.
+     */
+    double computeAvg() const
+    {
+        if (NZYXSIZE(*this) <= 0)
+            return 0;
+
+        double sum = 0;
+
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        sum += static_cast< double >(*ptr);
+
+        return sum / NZYXSIZE(*this);
+    }
+
+    /** Standard deviation of the values in the array.
+     *
+     * Be careful that the standard deviation and NOT the variance is returned.
+     * The returned value is always double, independently of the type of the
+     * array.
+     */
+    double computeStddev() const
+    {
+        if (NZYXSIZE(*this) <= 1)
+            return 0;
+
+        double avg = 0, stddev = 0;
+
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        {
+            double val=static_cast< double >(*ptr);
+            avg += val;
+            stddev += val * val;
+        }
+
+        avg /= NZYXSIZE(*this);
+        stddev = stddev / NZYXSIZE(*this) - avg * avg;
+        stddev *= NZYXSIZE(*this) / (NZYXSIZE(*this) - 1);
+
+        // Foreseeing numerical instabilities
+        stddev = sqrt(static_cast<double>((ABS(stddev))));
+
+        return stddev;
+    }
+
+    /** Compute statistics.
+     *
+     * The average, standard deviation, minimum and maximum value are
+     * returned.
+     */
+    void computeStats(double& avg, double& stddev, T& minval, T& maxval) const
+    {
+        if (NZYXSIZE(*this) <= 0)
+            return;
+
+        avg = 0;
+        stddev = 0;
+
+        minval = maxval = data[0];
+
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        {
+            T Tval=*ptr;
+            double val=static_cast< double >(Tval);
+            avg += val;
+            stddev += val * val;
+
+            if (Tval > maxval)
+                maxval = Tval;
+            else if (Tval < minval)
+                minval = Tval;
+        }
+
+        avg /= NZYXSIZE(*this);
+
+        if (NZYXSIZE(*this) > 1)
+        {
+            stddev = stddev / NZYXSIZE(*this) - avg * avg;
+            stddev *= NZYXSIZE(*this) / (NZYXSIZE(*this) - 1);
+
+            // Foreseeing numerical instabilities
+            stddev = sqrt(static_cast< double >(ABS(stddev)));
+        }
+        else
+            stddev = 0;
+    }
+
+    /** Median
+     *
+     * Calculate the median element.
+     *
+     * @code
+     * med = v1.computeMedian();
+     * @endcode
+     */
+    double computeMedian() const
+    {
+        if (XSIZE(*this) == 0)
+            return 0;
+
+        if (XSIZE(*this) == 1)
+            return DIRECT_MULTIDIM_ELEM(*this,0);
+
+        // Initialise data
+        MultidimArray< double > temp(*this);
+
+        // Sort indexes
+        temp.sort();
+
+        // Get median
+        if (NZYXSIZE(*this)%2==0)
+            return 0.5*(DIRECT_MULTIDIM_ELEM(temp,NZYXSIZE(*this)/2-1)+
+                        DIRECT_MULTIDIM_ELEM(temp,NZYXSIZE(*this)/2  ));
+        else
+            return DIRECT_MULTIDIM_ELEM(temp,NZYXSIZE(*this)/2);
+    }
+
+    /** Adjust the range of the array to a given one.
+     *
+     * A linear operation is performed on the values of the array such that
+     * after it, the values of the array are comprissed between the two values
+     * set. The actual array is modified itself
+     *
+     * @code
+     * v.rangeAdjust(0, 1);
+     * // The array is now ranging from 0 to 1
+     * @endcode
+     */
+    void rangeAdjust(T minF, T maxF)
+    {
+        if (NZYXSIZE(*this) <= 0)
+            return;
+
+        double min0, max0;
+        computeDoubleMinMax(min0, max0);
+
+        // If max0==min0, it means that the vector is a constant one, so the
+        // only possible transformation is to a fixed minF
+        double slope;
+        if (max0 != min0)
+            slope = static_cast< double >(maxF - minF) /
+                    static_cast< double >(max0 - min0);
+        else
+            slope = 0;
+
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = minF + static_cast< T >(slope *
+                                       static_cast< double >(*ptr - min0));
+    }
+
+    /** Adjust the range of the array to a given one within a mask.
+     *
+     * A linear operation is performed on the values of the array such that
+     * after it, the values of the array are comprissed between the two values
+     * set. The actual array is modified itself. The linear transformation
+    * is computed within the mask, but it is applied everywhere.
+     *
+     * @code
+     * v.rangeAdjust(0, 1, mask);
+     * // The array is now ranging from 0 to 1
+     * @endcode
+     */
+    // This function must be explictly implemented outside
+    void rangeAdjust(T minF, T maxF, MultidimArray<int> &mask)
+    {
+        if (MULTIDIM_SIZE(*this) <= 0)
+            return;
+
+        double min0, max0;
+        bool first=true;
+        T* ptr=NULL;
+        long int n;
+        int * ptrMask=MULTIDIM_ARRAY(mask);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        {
+            if (*ptrMask)
+            {
+                T val= *ptr;
+                if (first)
+                {
+                    min0=max0=(double)val;
+                    first=false;
+                }
+                else
+                {
+                    min0=XMIPP_MIN(min0,val);
+                    max0=XMIPP_MAX(max0,val);
+                }
+            }
+            ptrMask++;
+        }
+
+        // If max0==min0, it means that the vector is a constant one, so the
+        // only possible transformation is to a fixed minF
+        double slope;
+        if (max0 != min0)
+            slope = static_cast< double >(maxF - minF) /
+                    static_cast< double >(max0 - min0);
+        else
+            slope = 0;
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = minF + static_cast< T >(slope *
+                                       static_cast< double >(*ptr - min0));
+    }
+
+    /** Adjust the range of the array to the range of another array in
+        a least squares sense.
+     *
+     * A linear operation is performed on the values of the array such that
+     * after it, the values of the self array are as similar as possible
+     * (L2 sense) to the values of the array shown as sample
+     */
+
+    //As written this will only work for T=double
+    //nevertheless since this is used is better
+    //to use T than double or will create problem for int multidim arrays
+    void rangeAdjust(const MultidimArray<T> &example,
+                     const MultidimArray<int> *mask=NULL)
+    {
+        if (NZYXSIZE(*this) <= 0)
+            return;
+
+        // y=a+bx
+        double sumx=0, sumy=0, sumxy=0, sumx2=0;
+
+        T* ptrExample=MULTIDIM_ARRAY(example);
+        int* ptrMask=NULL;
+        if (mask!=NULL)
+            ptrMask=MULTIDIM_ARRAY(*mask);
+        T* ptr=NULL;
+        long int n;
+        double N=0;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        {
+            bool process=true;
+            if (mask!=NULL)
+                if (*ptrMask==0)
+                    process=false;
+            if (process)
+            {
+                T x=*ptr;
+                T y=*ptrExample;
+                sumy+=y;
+                sumxy+=x*y;
+                sumx+=x;
+                sumx2+=x*x;
+                N++;
+            }
+            ptrExample++;
+            if (mask!=NULL)
+                ptrMask++;
+        }
+        double b=(N*sumxy-sumx*sumy)/(N*sumx2-sumx*sumx);
+        double a=sumy/N-b*sumx/N;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = static_cast< double >(a+b * static_cast< double > (*ptr));
+    }
+
+    /** Adjust the average and stddev of the array to given values.
+     *
+     * A linear operation is performed on the values of the array such
+     * that after it, the average and standard deviation of the array
+     * are the two values set. The actual array is modified itself
+     *
+     * @code
+     * v.statisticsAdjust(0,1);
+     * // The array has got now 0 mean and stddev=1
+     * @endcode
+     */
+    // This function must be explictly implemented outside.
+    void statisticsAdjust(double avgF, double stddevF)
+    {
+        double avg0, stddev0;
+        double a, b;
+
+        if (NZYXSIZE(*this) == 0)
+            return;
+
+        T minval, maxval;
+        computeStats(avg0, stddev0, minval, maxval);
+
+        if (stddev0 != 0)
+            a = static_cast< double >(stddevF) / static_cast< double >(stddev0);
+        else
+            a = 0;
+
+        b = static_cast< double >(avgF) - a * static_cast< double >(avg0);
+
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = static_cast< T >(a * static_cast< double > (*ptr) + b);
+    }
+    //@}
+
+    /** @name Array "by" array operations.
+     *
+     * These are operations that are performed between 2 arrays of the
+     * SAME type (two integer vectors, two double matrices, ...). If they
+     * are not of the same type you can convert one of the arrays to the
+     * desired type using the function typeCast. The result must have been
+     * defined to be of the same type as the operands.
+     *
+     * In this kind of operations each element of array 1 is operated with its
+     * homologous in array 2, it is very important that both have got the
+     * same size and starting origins. The result has also got the same
+     * shape as the two operated arrays and its former content is lost.
+     */
+    //@{
+
+    /** Core array by array operation.
+     *
+     * It assumes that the result is already resized.
+     */
+    inline friend void coreArrayByArray(const MultidimArray<T>& op1,
+                                        const MultidimArray<T>& op2, MultidimArray<T>& result,
+                                        char operation)
+    {
+        T* ptrResult=NULL;
+        T* ptrOp1=NULL;
+        T* ptrOp2=NULL;
+        long int n;
+        for (n=0, ptrResult=result.data, ptrOp1=op1.data,ptrOp2=op2.data;
+             n<op1.zyxdim; ++n, ++ptrResult, ++ptrOp1, ++ptrOp2)
+            switch (operation)
+            {
+            case '+':
+                *ptrResult = *ptrOp1 + *ptrOp2;
+                break;
+            case '-':
+                *ptrResult = *ptrOp1 - *ptrOp2;
+                break;
+            case '*':
+                *ptrResult = *ptrOp1 * *ptrOp2;
+                break;
+            case '/':
+                *ptrResult = *ptrOp1 / *ptrOp2;
+                break;
+            }
+    }
+
+    /** Array by array
+     *
+     * This function must take two vectors of the same size, and operate element
+     * by element according to the operation required. This is the function
+     * which really implements the operations. Simple calls to it perform much
+     * faster than calls to the corresponding operators. Although it is supposed
+     * to be a hidden function not useable by normal programmers.
+     *
+     */
+    inline friend void arrayByArray(const MultidimArray<T>& op1,
+                                    const MultidimArray<T>& op2, MultidimArray<T>& result,
+                                    char operation)
+    {
+        if (!op1.sameShape(op2))
+            REPORT_ERROR( (std::string) "Array_by_array: different shapes (" +
+                         operation + ")");
+        if (result.data == NULL || !result.sameShape(op1))
+            result.resize(op1);
+        coreArrayByArray(op1, op2, result, operation);
+    }
+
+    /** v3 = v1 + v2.
+     */
+    MultidimArray<T> operator+(const MultidimArray<T>& op1) const
+    {
+        MultidimArray<T> tmp;
+        arrayByArray(*this, op1, tmp, '+');
+        return tmp;
+    }
+
+    /** v3 = v1 - v2.
+     */
+    MultidimArray<T> operator-(const MultidimArray<T>& op1) const
+    {
+        MultidimArray<T> tmp;
+        arrayByArray(*this, op1, tmp, '-');
+        return tmp;
+    }
+
+    /** v3 = v1 * v2.
+     */
+    MultidimArray<T> operator*(const MultidimArray<T>& op1) const
+    {
+        MultidimArray<T> tmp;
+        arrayByArray(*this, op1, tmp, '*');
+        return tmp;
+    }
+
+    /** v3 = v1 / v2.
+     */
+    MultidimArray<T> operator/(const MultidimArray<T>& op1) const
+    {
+        MultidimArray<T> tmp;
+        arrayByArray(*this, op1, tmp, '/');
+        return tmp;
+    }
+
+    /** v3 += v2.
+     */
+    void operator+=(const MultidimArray<T>& op1)
+    {
+        arrayByArray(*this, op1, *this, '+');
+    }
+
+    /** v3 -= v2.
+     */
+    void operator-=(const MultidimArray<T>& op1)
+    {
+        arrayByArray(*this, op1, *this, '-');
+    }
+
+    /** v3 *= v2.
+     */
+    void operator*=(const MultidimArray<T>& op1)
+    {
+        arrayByArray(*this, op1, *this, '*');
+    }
+
+    /** v3 /= v2.
+     */
+    void operator/=(const MultidimArray<T>& op1)
+    {
+        arrayByArray(*this, op1, *this, '/');
+    }
+    //@}
+
+    /** @name Array "by" scalar operations
+     *
+     * These operations are between an array and a scalar (of the same type as
+     * the array). The result must have been defined to be of the same type as
+     * the operands.
+     *
+     * In this kind of operations each element of array 1 is operated with the
+     * given constant. The result has also got the same shape as the input
+     * array and its former content is lost
+     */
+    //@{
+
+    /** Core array by scalar operation.
+     *
+     * It assumes that the result is already resized.
+     *
+     * This function is not ported to Python.
+     */
+    inline friend void coreArrayByScalar(const MultidimArray<T>& op1,
+                                         const T& op2,
+                                         MultidimArray<T>& result,
+                                         char operation)
+    {
+        T* ptrResult=NULL;
+        T* ptrOp1=NULL;
+        long int n;
+        for (n=0, ptrResult=result.data, ptrOp1=op1.data;
+             n<op1.zyxdim; ++n, ++ptrResult, ++ptrOp1)
+            switch (operation)
+            {
+            case '+':
+                *ptrResult = *ptrOp1 + op2;
+                break;
+            case '-':
+                *ptrResult = *ptrOp1 - op2;
+                break;
+            case '*':
+                *ptrResult = *ptrOp1 * op2;
+                break;
+            case '/':
+                *ptrResult = *ptrOp1 / op2;
+                break;
+            }
+    }
+
+    /** Array by scalar.
+     *
+     * This function must take one vector and a constant, and operate element
+     * by element according to the operation required. This is the function
+     * which really implements the operations. Simple calls to it perform much
+     * faster than calls to the corresponding operators. Although it is
+     * supposed to be a hidden function not useable by normal programmers.
+     *
+     * This function is not ported to Python.
+     */
+    inline friend void arrayByScalar(const MultidimArray<T>& op1,
+                                     T op2,
+                                     MultidimArray<T>& result,
+                                     char operation)
+    {
+        if (result.data == NULL || !result.sameShape(op1))
+            result.resize(op1);
+        coreArrayByScalar(op1, op2, result, operation);
+    }
+
+    /** v3 = v1 + k.
+     */
+    MultidimArray<T> operator+(T op1) const
+    {
+        MultidimArray<T> tmp;
+        arrayByScalar(*this, op1, tmp, '+');
+        return tmp;
+    }
+
+    /** v3 = v1 - k.
+     */
+    MultidimArray<T> operator-(T op1) const
+    {
+        MultidimArray<T> tmp;
+        arrayByScalar(*this, op1, tmp, '-');
+        return tmp;
+    }
+
+    /** v3 = v1 * k.
+     */
+    MultidimArray<T> operator*(T op1) const
+    {
+        MultidimArray<T> tmp;
+        arrayByScalar(*this, op1, tmp, '*');
+        return tmp;
+    }
+
+    /** v3 = v1 / k.
+     */
+    MultidimArray<T> operator/(T op1) const
+    {
+        MultidimArray<T> tmp;
+        arrayByScalar(*this, op1, tmp, '/');
+        return tmp;
+    }
+
+    /** v3 += k.
+     *
+     * This function is not ported to Python.
+     */
+    void operator+=(const T& op1)
+    {
+        arrayByScalar(*this, op1, *this, '+');
+    }
+
+    /** v3 -= k.
+     *
+     * This function is not ported to Python.
+     */
+    void operator-=(const T& op1)
+    {
+        arrayByScalar(*this, op1, *this, '-');
+    }
+
+    /** v3 *= k.
+     *
+     * This function is not ported to Python.
+     */
+    void operator*=(const T& op1)
+    {
+        arrayByScalar(*this, op1, *this, '*');
+    }
+
+    /** v3 /= k.
+     *
+     * This function is not ported to Python.
+     */
+    void operator/=(const T& op1)
+    {
+        arrayByScalar(*this, op1, *this, '/');
+    }
+    //@}
+
+    /** @name Scalar "by" array operations
+     *
+     * These operations are between a scalar (of the same type as the array)
+     * and an array. The result must have been defined to be of the same type
+     * as the operand. The former content of the result array is lost after
+     * the operation.
+     *
+     * In this kind of operations the constant is operated with each element
+     * of array 2. The result has also got the same shape as the input array
+     * and its former content is lost
+     */
+    //@{
+
+    /** Core array by scalar operation.
+     *
+     * It assumes that the result is already resized.
+     *
+     * This function is not ported to Python.
+     */
+    inline friend void coreScalarByArray(const T& op1,
+                                         const MultidimArray<T>& op2,
+                                         MultidimArray<T>& result,
+                                         char operation)
+    {
+        T* ptrResult=NULL;
+        T* ptrOp2=NULL;
+        long int n;
+        for (n=0, ptrResult=result.data, ptrOp2=op2.data;
+             n<op2.zyxdim; ++n, ++ptrResult, ++ptrOp2)
+            switch (operation)
+            {
+            case '+':
+                *ptrResult = op1 + *ptrOp2;
+                break;
+            case '-':
+                *ptrResult = op1 - *ptrOp2;
+                break;
+            case '*':
+                *ptrResult = op1 * *ptrOp2;
+                break;
+            case '/':
+                *ptrResult = op1 / *ptrOp2;
+                break;
+            }
+    }
+
+    /** Scalar by array.
+     *
+     * This function must take one scalar and a vector, and operate element by
+     * element according to the operation required. This is the function which
+     * really implements the operations. Simple calls to it perform much faster
+     * than calls to the corresponding operators. Although it is supposed to
+     * be a hidden function not useable by normal programmers.
+     *
+     * This function is not ported to Python.
+     */
+    inline friend void scalarByArray(T op1,
+                                     const MultidimArray<T>& op2,
+                                     MultidimArray<T>& result,
+                                     char operation)
+    {
+        if (result.data == NULL || !result.sameShape(op2))
+            result.resize(op2);
+        coreScalarByArray(op1, op2, result, operation);
+    }
+
+    /** v3 = k + v2.
+     */
+    friend MultidimArray<T> operator+(T op1, const MultidimArray<T>& op2)
+    {
+        MultidimArray<T> tmp;
+        scalarByArray(op1, op2, tmp, '+');
+        return tmp;
+    }
+
+    /** v3 = k - v2.
+     */
+    friend MultidimArray<T> operator-(T op1, const MultidimArray<T>& op2)
+    {
+        MultidimArray<T> tmp;
+        scalarByArray(op1, op2, tmp, '-');
+        return tmp;
+    }
+
+    /** v3 = k * v2.
+     */
+    friend MultidimArray<T> operator*(T op1, const MultidimArray<T>& op2)
+    {
+        MultidimArray<T> tmp;
+        scalarByArray(op1, op2, tmp, '*');
+        return tmp;
+    }
+
+    /** v3 = k / v2
+     */
+    friend MultidimArray<T> operator/(T op1, const MultidimArray<T>& op2)
+    {
+        MultidimArray<T> tmp;
+        scalarByArray(op1, op2, tmp, '/');
+        return tmp;
+    }
+    //@}
+
+    /// @name Initialization
+    /// @{
+
+    /** Same value in all components.
+     *
+     * The constant must be of a type compatible with the array type, ie,
+     * you cannot  assign a double to an integer array without a casting.
+     * It is not an error if the array is empty, then nothing is done.
+     *
+     * @code
+     * v.initConstant(3.14);
+     * @endcode
+     */
+    void initConstant(T val)
+    {
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = val;
+    }
+
+    /** Initialize to zeros following a pattern.
+     *
+     * All values are set to 0, and the origin and size of the pattern are
+     * adopted.
+     *
+     * @code
+     * v2.initZeros(v1);
+     * @endcode
+     */
+    template <typename T1>
+    void initZeros(const MultidimArray<T1>& op)
+    {
+        if (data == NULL || !sameShape(op))
+            resize(op);
+        memset(data,0,nzyxdim*sizeof(T));
+    }
+
+    /** Initialize to zeros with current size.
+     *
+     * All values are set to 0. The current size and origin are kept. It is not
+     * an error if the array is empty, then nothing is done.
+     *
+     * @code
+     * v.initZeros();
+     * @endcode
+     */
+    inline void initZeros()
+    {
+        memset(data,0,nzyxdim*sizeof(T));
+    }
+
+    /** Initialize to zeros with a given size.
+     */
+    inline void initZeros(long int Ndim, long int Zdim, long int Ydim, long int Xdim)
+    {
+        if (xdim!=Xdim || ydim!=Ydim || zdim!=Zdim || ndim!=Ndim)
+            resize(Ndim, Zdim,Ydim,Xdim);
+        memset(data,0,nzyxdim*sizeof(T));
+    }
+
+    /** Initialize to zeros with a given size.
+     */
+    void initZeros(long int Xdim)
+    {
+        initZeros(1, 1, 1, Xdim);
+    }
+
+    /** Initialize to zeros with a given size.
+     */
+    void initZeros(long int Ydim, long int Xdim)
+    {
+        initZeros(1, 1, Ydim, Xdim);
+    }
+
+    /** Initialize to zeros with a given size.
+     */
+    void initZeros(long int Zdim, long int Ydim, long int Xdim)
+    {
+        initZeros(1, Zdim, Ydim, Xdim);
+    }
+
+    /** Linear initialization (only for 1D)
+     *
+     * The 1D vector is filled with values increasing/decreasing linearly within a
+     * range or at given steps.
+     *
+     * Increment functionality: The default increment is 1, the initial point is
+     * incremented by this value until the upper limit is reached. This is the
+     * default working mode for the function.
+     *
+     * @code
+     * v1.initLinear(1, 3); // v1=[1 2 3]
+     * v1.initLinear(1.5, 3.1); // v1=[1.5 2.5]
+     * v1.initLinear(0, 10, 3); // v1=[0 3 6 9]
+     * v1.initLinear(0, 10, 3, "incr"); // v1=[0 3 6 9]
+     * @endcode
+     *
+     * Step functionality: The given range is divided in as many points as
+     * indicated (in the example 6 points).
+     *
+     * @code
+     * v1.initLinear(0, 10, 6, "steps"); // v1=[0 2 4 6 8 10]
+     * @endcode
+     */
+    void initLinear(T minF, T maxF, int n = 1, const std::string& mode = "incr")
+    {
+        double slope;
+        int steps;
+
+        if (mode == "incr")
+        {
+            steps = 1 + (int) FLOOR((double) ABS((maxF - minF)) / ((double) n));
+            slope = n * SGN(maxF - minF);
+        }
+        else if (mode == "steps")
+        {
+            steps = n;
+            slope = (maxF - minF) / (steps - 1);
+        }
+        else
+            REPORT_ERROR( "Init_linear: Mode not supported (" + mode + ")");
+
+        if (steps == 0)
+            clear();
+        else
+        {
+            resize(steps);
+            for (int i = 0; i < steps; i++)
+                A1D_ELEM(*this, i) = (T)((double) minF + slope * i);
+        }
+    }
+
+    /** Initialize with random values.
+     *
+     * This function allows you to initialize the array with a set of random
+     * values picked from a uniform random distribution or a gaussian one. You
+     * must choose two parameters for each, for the uniform distribution they
+     * mean the range where to generate the random numbers, while in the
+     * gaussian case they are the mean and the standard deviation. By default
+     * the uniform distribution is selected. The size and origin of the array
+     * are not modified.
+     *
+     * @code
+     * v.initRandom(0, 1);
+     * // uniform distribution between 0 and 1
+     *
+     * v.initRandom(0, 1, "uniform");
+     * // the same
+     *
+     * v.initRandom(0, 1, "gaussian");
+     * // gaussian distribution with 0 m
ean and stddev=1
+     * @endcode
+     */
+    void initRandom(double op1, double op2, const std::string& mode = "uniform")
+    {
+        T* ptr=NULL;
+        long int n;
+        if (mode == "uniform")
+            FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+            *ptr = static_cast< T >(rnd_unif(op1, op2));
+        else if (mode == "gaussian")
+            FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+            *ptr = static_cast< T >(rnd_gaus(op1, op2));
+        else
+            REPORT_ERROR( static_cast< std::string >("InitRandom: Mode not supported (" +
+                                                    mode + ")"));
+    }
+
+    /** Add noise to actual values.
+     *
+     * This function add some noise to the actual values of the array according
+     * to a certain random distribution. You must choose two parameters for
+     * each, for the uniform distribution they mean the range where to generate
+     * the random numbers, while in the gaussian case they are the mean and the
+     * standard deviation. By default the uniform distribution is selected. The
+     * size and origin of the array are not modified. The array itself is
+     * modified.
+     *
+     * @code
+     * v1.addNoise(0, 1);
+     * // uniform distribution between 0 and 1
+     *
+     * v1.addNoise(0, 1, "uniform");
+     * // the same
+     *
+     * v1.addNoise(0, 1, "gaussian");
+     * // gaussian distribution with 0 mean and stddev=1
+     *
+     * v1.addNoise(0, 1, "student", 3);
+     * // t-student distribution with 0 mean and stddev=1, and 3 degrees of freedom
+     *
+
+     * @endcode
+     */
+    void addNoise(double op1,
+                  double op2,
+                  const std::string& mode = "uniform",
+                  double df = 3.) const
+    {
+        T* ptr=NULL;
+        unsigned long int n;
+        if (mode == "uniform")
+            FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+            *ptr += static_cast< T >(rnd_unif(op1, op2));
+        else if (mode == "gaussian")
+            FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+            *ptr += static_cast< T >(rnd_gaus(op1, op2));
+        else if (mode == "student")
+            FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+            *ptr += static_cast< T >(rnd_student_t(df, op1, op2));
+        else
+            REPORT_ERROR( static_cast< std::string >("AddNoise: Mode not supported (" +
+                                                    mode + ")"));
+    }
+    //@}
+
+    /** @name Utilities
+     *
+     * Here you have several easy functions to manage the values of
+     * the array.
+     */
+    //@{
+
+    /** Produce a 3D array suitable for working with Numerical Recipes.
+     *
+     * This function must be used only as a preparation for routines which need
+     * that the first physical index is 1 and not 0 as it usually is in C. New
+     * memory is needed to hold the new double pointer array.
+     */
+    T*** adaptForNumericalRecipes3D(long int n = 0) const
+    {
+        T*** m = NULL;
+        ask_Tvolume(m, 1, ZSIZE(*this), 1, YSIZE(*this), 1, XSIZE(*this));
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(*this)
+        m[k+1][i+1][j+1] = DIRECT_NZYX_ELEM(*this, n, k, i, j);
+
+        return m;
+    }
+
+    /** Kill a 3D array produced for numerical recipes.
+     */
+    void killAdaptationForNumericalRecipes3D(T*** m) const
+    {
+        free_Tvolume(m, 1, ZSIZE(*this), 1, YSIZE(*this), 1, XSIZE(*this));
+    }
+
+    /** Produce a 2D array suitable for working with Numerical Recipes
+     *
+     * This function must be used only as a preparation for routines which need
+     * that the first physical index is 1 and not 0 as it usually is in C. New
+     * memory is needed to hold the new double pointer array.
+     */
+    T** adaptForNumericalRecipes2D(long int n = 0) const
+    {
+        T** m = NULL;
+        ask_Tmatrix(m, 1, YSIZE(*this), 1, XSIZE(*this));
+
+        FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY2D(*this)
+        m[i+1][j+1] = DIRECT_NZYX_ELEM(*this, n, 0, i, j);
+
+        return m;
+    }
+
+    /** Produce a 1D pointer suitable for working with Numerical Recipes (2)
+     *
+     * This function meets the same goal as the one before, however this one
+     * work with 2D arrays as a single pointer. The first element of the array
+     * is pointed by result[1*Xdim+1], and in general result[i*Xdim+j]
+     */
+    T* adaptForNumericalRecipes22D() const
+    {
+        return MULTIDIM_ARRAY(*this) - 1 - XSIZE(*this);
+    }
+
+    /** Load 2D array from numerical recipes result.
+     */
+    void loadFromNumericalRecipes2D(T** m, long int Ydim, long int Xdim)
+    {
+        resize(Ydim, Xdim);
+
+        for (long int i = 1; i <= Ydim; i++)
+            for (long int j = 1; j <= Xdim; j++)
+                (*this)(i - 1, j - 1) = m[i][j];
+    }
+
+    /** Kill a 2D array produced for numerical recipes
+     *
+     * The allocated memory is freed.
+     */
+    void killAdaptationForNumericalRecipes2D(T** m) const
+    {
+        free_Tmatrix(m, 1, YSIZE(*this), 1, XSIZE(*this));
+    }
+
+    /** Kill a 2D array produced for numerical recipes, 2.
+     *
+     * Nothing needs to be done.
+     */
+    void killAdaptationForNumericalRecipes22D(T** m) const
+        {}
+
+    /** Produce a 1D array suitable for working with Numerical Recipes
+     *
+     * This function must be used only as a preparation for routines which need
+     * that the first physical index is 1 and not 0 as it usually is in C. In
+     * fact the vector provided for Numerical recipes is exactly this same one
+     * but with the indexes changed.
+     *
+     * This function is not ported to Python.
+     */
+    T* adaptForNumericalRecipes1D() const
+    {
+        return MULTIDIM_ARRAY(*this) - 1;
+    }
+
+    /** Kill a 1D array produced for Numerical Recipes.
+     *
+     * Nothing needs to be done in fact.
+     *
+     * This function is not ported to Python.
+     */
+    void killAdaptationForNumericalRecipes1D(T* m) const
+        {}
+
+    /** Computes the center of mass of the nth array
+     */
+    void centerOfMass(Matrix1D< double >& center, void * mask=NULL, long int n = 0)
+    {
+        center.initZeros(3);
+        double mass = 0;
+        MultidimArray< int >* imask = (MultidimArray< int >*) mask;
+
+        FOR_ALL_ELEMENTS_IN_ARRAY3D(*this)
+        {
+            if ((imask == NULL || NZYX_ELEM(*imask, n, k, i, j)) &&
+                A3D_ELEM(*this, k, i, j) > 0)
+            {
+                XX(center) += j * NZYX_ELEM(*this, n, k, i, j);
+                YY(center) += i * NZYX_ELEM(*this, n, k, i, j);
+                ZZ(center) += k * NZYX_ELEM(*this, n, k, i, j);
+
+                mass += NZYX_ELEM(*this, n, k, i, j);
+            }
+        }
+
+        if (mass != 0)
+            center /= mass;
+
+        // resize center to the correct dimensionality
+        if (getDim() == 2)
+        	center.resize(2);
+        else if (getDim() == 1)
+        	center.resize(1);
+
+    }
+
+    /** Sort 1D vector elements
+     *
+     * Sort in ascending order the vector elements. You can use the "selfReverseX"
+     * function to sort in descending order.
+     *
+     * @code
+     * v1.sort();
+     * @endcode
+     */
+    void sort()
+    {
+        checkDimension(1);
+        std::sort(MULTIDIM_ARRAY(*this), MULTIDIM_ARRAY(*this) + xdim);
+    }
+
+    /** Get the indices that sort the 1D vector elements (original array intact)
+     *
+     * @code
+	 * MultidimArray<long int> idx(v1.size());
+     * v1.sorted_index(idx);
+     * @endcode
+     */
+    // TODO: check this function!
+    void sorted_index(MultidimArray<long> &idx) const
+    {
+        checkDimension(1);
+        //Set up a vector of pairs
+        std::vector<std::pair<T,long int> > vp;
+        vp.reserve(XSIZE(*this));
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(*this)
+        {
+        	vp.push_back(std::make_pair(DIRECT_MULTIDIM_ELEM(*this,n), n));
+        }
+        // Sort on the first elements of the pairs
+        std::sort(vp.begin(), vp.end());
+        idx.resize(XSIZE(*this));
+        // Fill the output array with the second elements of the sorted vp
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(idx)
+        {
+        	DIRECT_MULTIDIM_ELEM(idx, n) = vp[n].second;
+        }
+    }
+
+
+    /** Several thresholding.
+     *
+     * Apply a threshold to the array, the object is modified itself. There
+     * are several kinds of thresholding and you must specify it, the values
+     * given in the fuction have different meanings according to the threshold
+     * applied.
+     *
+     * abs_above: if |x|>a => x=b
+     * abs_below: if |x|<a => x=b
+     * above:     if  x >a => x=b
+     * below:     if  x <a => x=b
+     * range:     if  x <a => x=a   and    if x>b => x=b
+     *
+     * @code
+     * v.threshold("abs_above", 10, 10);
+     * // any value whose absolute value is above 10 will be substituted by
+     * // -10 (if it is negative) or 10 (if it is positive)
+     *
+     * v.threshold("abs_below", 0.1, 0);
+     * // any value whose absolute value is below 0.1 will be substituted by
+     * // -0 (if it is negative) or 0 (if it is positive)
+     *
+     * v.threshold("above", 10, 10);
+     * // any value above 10 will be substituted by 10
+     *
+     * v.threshold("below", -10, -10);
+     * // any value below -10 will be substituted by -10
+     *
+     * v.threshold("range", 0, 1);
+     * // v is "saturated" by values 0 and 1, any value outside this range
+     * // will be substituted by its nearest border
+     * @endcode
+     */
+    void threshold(const std::string& type,
+                   T a,
+                   T b,
+                   MultidimArray<int> * mask = NULL )
+    {
+        int mode;
+
+        if (type == "abs_above")
+            mode = 1;
+        else if (type == "abs_below")
+            mode = 2;
+        else if (type == "above")
+            mode = 3;
+        else if (type == "below")
+            mode = 4;
+        else if (type == "range")
+            mode = 5;
+        else
+            REPORT_ERROR( static_cast< std::string >("Threshold: mode not supported (" +
+                                                    type + ")"));
+
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        {
+            if (mask == NULL || DIRECT_MULTIDIM_ELEM(*mask,n) > 0 )
+            {
+                switch (mode)
+                {
+                case 1:
+                    if (ABS(*ptr) > a)
+                        *ptr = SGN(*ptr) * b;
+                    break;
+                case 2:
+                    if (ABS(*ptr) < a)
+                        *ptr = SGN(*ptr) * b;
+                    break;
+                case 3:
+                    if (*ptr > a)
+                        *ptr = b;
+                    break;
+                case 4:
+                    if (*ptr < a)
+                        *ptr = b;
+                    break;
+                case 5:
+                    if (*ptr < a)
+                        *ptr = a;
+                    else if (*ptr > b)
+                        *ptr = b;
+                    break;
+                }
+            }
+        }
+    }
+
+    /** Count with threshold.
+     *
+     * This function returns the number of elements meeting the threshold
+     * condition.
+     */
+    long int countThreshold(const std::string& type,
+                                 T a,
+                                 T b,
+                                 MultidimArray<int> * mask = NULL )
+    {
+        int mode;
+
+        if (type == "abs_above")
+            mode = 1;
+        else if (type == "abs_below")
+            mode = 2;
+        else if (type == "above")
+            mode = 3;
+        else if (type == "below")
+            mode = 4;
+        else if (type == "range")
+            mode = 5;
+        else
+            REPORT_ERROR( static_cast< std::string >("CountThreshold: mode not supported (" +
+                                                    type + ")"));
+
+        long int ret = 0;
+
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        if (mask == NULL || DIRECT_MULTIDIM_ELEM(*mask,n) > 0 )
+        {
+            switch (mode)
+            {
+            case 1:
+                if (ABS(*ptr) > a)
+                    ret++;
+                break;
+            case 2:
+                if (ABS(*ptr) < a)
+                    ret++;
+                break;
+            case 3:
+                if (*ptr > a)
+                    ret++;
+                break;
+            case 4:
+                if (*ptr < a)
+                    ret++;
+                break;
+            case 5:
+                if (*ptr >= a && *ptr <= b)
+                    ret++;
+                break;
+            }
+        }
+        return ret;
+    }
+
+    /** Substitute a value by another.
+     *
+     * Substitute an old value by a new one. The accuracy is used to say if
+     * the value in the array is equal to the old value. Set it to 0 for
+     * perfect accuracy.
+     */
+    void substitute(T oldv,
+                    T newv,
+                    double accuracy = XMIPP_EQUAL_ACCURACY,
+                    MultidimArray<int> * mask = NULL )
+    {
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        if (mask == NULL || DIRECT_MULTIDIM_ELEM(*mask,n) > 0 )
+            if (ABS(*ptr - oldv) <= accuracy)
+                *ptr = newv;
+    }
+
+    /** Substitute a given value by a sample from a Gaussian distribution.
+     *
+     * Substitute  a given value by a sample from a Gaussian distribution.
+     * The accuracy is used to say if the value in the array is equal
+     * to the old value.  Set it to 0 for perfect accuracy.
+     */
+    void randomSubstitute(T oldv,
+                          T avgv,
+                          T sigv,
+                          double accuracy = XMIPP_EQUAL_ACCURACY,
+                          MultidimArray<int> * mask = NULL )
+    {
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        if (mask == NULL || DIRECT_MULTIDIM_ELEM(*mask,n) > 0 )
+            if (ABS(*ptr - oldv) <= accuracy)
+                *ptr = rnd_gaus(avgv, sigv);
+    }
+
+    /** Binarize.
+     *
+     * This functions substitutes all values in a volume which are greater
+     * than val+accuracy by 1 and the rest are set to 0. Use threshold to get a
+     * very powerful binarization.
+     */
+    void binarize(double val = 0,
+                  double accuracy = XMIPP_EQUAL_ACCURACY,
+                  MultidimArray<int> * mask = NULL )
+    {
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        if ((mask == NULL) || (DIRECT_MULTIDIM_ELEM(*mask,n) > 0) )
+        {
+        	if (*ptr <= val + accuracy)
+        	{
+        		*ptr = 0;
+        	}
+            else
+            {
+            	*ptr = 1;
+            }
+        }
+    }
+
+    /** ROUND
+     *
+     * Applies a ROUND (look for the nearest integer) to each array element.
+     */
+    void selfROUND()
+    {
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = ROUND(*ptr);
+    }
+
+    /** CEILING
+     *
+     * Applies a CEILING (look for the nearest larger integer) to each
+     * array element.
+     */
+    void selfCEIL()
+    {
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = CEIL(*ptr);
+    }
+
+    /** FLOOR
+     *
+     * Applies a FLOOR (look for the nearest larger integer) to each
+     * array element.
+     */
+    void selfFLOOR()
+    {
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = FLOOR(*ptr);
+    }
+
+    /** ABS
+     *
+     * Applies an ABS (absolute value) to each array element.
+     */
+    void selfABS()
+    {
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = ABS(*ptr);
+    }
+
+    /** MAX
+     *
+     * Each component of the result is the maximum of the correspoing
+     * components of the two input arrays. They must have the same shape, if
+     * not an exception is thrown
+     */
+    friend void MAX(const MultidimArray<T>& v1, const MultidimArray<T>& v2,
+                    MultidimArray<T>& result)
+    {
+        if (!v1.sameShape(v2))
+            REPORT_ERROR( "MAX: arrays of different shape");
+
+        result.resize(v1);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(result)
+        DIRECT_MULTIDIM_ELEM(result,n) = XMIPP_MAX(
+                                             DIRECT_MULTIDIM_ELEM(v1,n),
+                                             DIRECT_MULTIDIM_ELEM(v2,n));
+    }
+
+    /** MIN
+     *
+     * Each component of the result is the minimum of the correspoing
+     * components of the two input arrays. They must have the same shape, if
+     * not an exception is thrown
+     */
+    friend void MIN(const MultidimArray<T>& v1, const MultidimArray<T>& v2,
+                    MultidimArray<T>& result)
+    {
+        if (!v1.sameShape(v2))
+            REPORT_ERROR( "MIN: arrays of different shape");
+
+        result.resize(v1);
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(result)
+        DIRECT_MULTIDIM_ELEM(result,n) = XMIPP_MIN(
+                                             DIRECT_MULTIDIM_ELEM(v1,n),
+                                             DIRECT_MULTIDIM_ELEM(v2,n));
+    }
+
+    /** Sqrt.
+     *
+     * Each component of the result is the square root of the original
+     * component.
+     */
+    void selfSQRT()
+    {
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = static_cast< T >(sqrt(static_cast< double >(*ptr)));
+    }
+
+    /** Sum of matrix values.
+     *
+     * This function returns the sum of all internal values.
+     *
+     * @code
+     * double sum = m.sum();
+     * @endcode
+     */
+    double sum() const
+    {
+        double sum = 0;
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        sum += *ptr;
+        return sum;
+    }
+
+    /** Sum of squared vector values.
+     *
+     * This function returns the sum of all internal values to the second
+     * power_class.
+     *
+     * @code
+     * double sum2 = m.sum2();
+     * @endcode
+     */
+    double sum2() const
+    {
+        double sum = 0;
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        sum += *ptr * *ptr;
+        return sum;
+    }
+
+    /** Log10.
+     *
+     * Each component of the result is the log10 of the original components.
+     */
+    void selfLog10()
+    {
+        T* ptr=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this,n,ptr)
+        *ptr = static_cast< T >(log10(static_cast< double >(*ptr)));
+    }
+
+    /** Reverse matrix values over X axis, keep in this object.
+     *
+     * Maybe better with an example:
+     *
+     * @code
+     * slice 0
+     * [01 02 03          [07 08 09
+     *  04 05 06           04 05 06
+     *  07 08 09]          01 02 03]
+     *
+     * ----->
+     *
+     * slice 1
+     * [11 12 13          [17 18 19
+     *  14 15 16           14 15 16
+     *  17 18 19]          11 12 13]
+     * @endcode
+     *
+     */
+    void selfReverseX()
+    {
+        long int xsize = XSIZE(*this);
+        long int halfSizeX = (long int)(xsize-1)/2;
+        long int ysize = YSIZE(*this);
+        long int zsize = ZSIZE(*this);
+        long int nsize = NSIZE(*this);
+        //0 column should be handled in a different way
+        //for even and odd matrices
+        long int start_x = ((xsize%2) ? 0: 1);
+
+        for (long int l = 0; l < nsize; l++)
+            for (long int k = 0; k < zsize; k++)
+                for (long int i = 0; i < ysize; i++)
+                    for (long int j = start_x; j <=  halfSizeX; j++)
+                    {
+                        T aux;
+                        SWAP(DIRECT_NZYX_ELEM(*this, l, k, i, j),
+                             DIRECT_NZYX_ELEM(*this, l, k, i, xsize - j),
+                             aux);
+                    }
+        //NOTE: line x=0 should not be modified since gets itself by wrapping
+        //NOTE center hyper-plane  (dimx/2,y,z)  should remain unchanged
+
+    }
+
+    /** Reverse matrix values over Y axis, keep in this object.
+     *
+     * Maybe better with an example:
+     *
+     * @code
+     * slice 0
+     * [01 02 03          [03 02 01
+     *  04 05 06           06 05 04
+     *  07 08 09]          09 08 07]
+     *
+     * ----->
+     *
+     * slice 1
+     * [11 12 13          [13 12 11
+     *  14 15 16           16 15 14
+     *  17 18 19]          19 18 17]
+     * @endcode
+     *
+     */
+    void selfReverseY()
+    {
+        long int xsize = XSIZE(*this);
+        long int ysize = YSIZE(*this);
+        long int halfSizeY = (long int)(ysize-1)/2;
+        long int zsize = ZSIZE(*this);
+        long int nsize = NSIZE(*this);
+        //0 column should be handled in a different way
+        //for even and odd matrices
+        long int start_y = ((ysize%2) ? 0: 1);
+
+        for (long int l = 0; l < nsize; l++)
+            for (long int k = 0; k < zsize; k++)
+                for (long int i = start_y; i <= halfSizeY; i++)
+                    for (long int j = 0; j < xsize; j++)
+                    {
+                        T aux;
+                        SWAP(DIRECT_NZYX_ELEM(*this, l, k, i, j),
+                             DIRECT_NZYX_ELEM(*this, l, k, ysize - i, j),
+                             aux);
+                    }
+
+        STARTINGY(*this) = -FINISHINGY(*this);
+    }
+
+    /** Reverse matrix values over Z axis, keep in this object.
+     *
+     * Maybe better with an example:
+     *
+     * @code
+     * slice 0
+     * [01 02 03          [11 12 13
+     *  04 05 06           14 15 16
+     *  07 08 09]          17 18 19]
+     *
+     *  ----->
+     *
+     * slice 1
+     * [11 12 13          [01 02 03
+     *  14 15 16           04 05 06
+     *  17 18 19]          07 08 09]
+     * @endcode
+     *
+     */
+    void selfReverseZ()
+    {
+        long int xsize = XSIZE(*this);
+        long int ysize = YSIZE(*this);
+        long int zsize = ZSIZE(*this);
+        long int halfSizeZ = (long int)(zsize-1)/2;
+        long int nsize = NSIZE(*this);
+        //0 column should be handled in a different way
+        //for even and odd matrices
+        long int start_z = ((zsize%2) ? 0: 1);
+
+
+        for (int l = 0; l < nsize; l++)
+            for (int k = start_z; k <= halfSizeZ; k++)
+                for (int i = 0; i <ysize; i++)
+                    for (int j = 0; j < xsize; j++)
+                    {
+                        T aux;
+                        SWAP(DIRECT_NZYX_ELEM(*this, l, k, i, j),
+                             DIRECT_NZYX_ELEM(*this, l, zsize- k, i, j),
+                             aux);
+                    }
+
+        STARTINGZ(*this) = -FINISHINGZ(*this);
+    }
+
+    /** Extracts the 1D profile between two points in a 2D array
+     *
+     * Given two logical indexes, this function returns samples of the line that
+     * joins them. This is done by bilinear interpolation. The number of samples
+     * in the line is N.
+     */
+    void profile(long int x0, long int y0, long int xF, long int yF, long int N,
+                 MultidimArray< double >& profile) const
+    {
+        checkDimension(2);
+        profile.initZeros(N);
+        double tx_step = (double)(xF - x0) / (N - 1);
+        double ty_step = (double)(yF - y0) / (N - 1);
+        double tx = x0, ty = y0;
+
+        for (long int i = 0; i < N; i++)
+        {
+            profile(i) = interpolatedElement2D(tx, ty);
+            tx += tx_step;
+            ty += ty_step;
+        }
+    }
+
+    /** Show using gnuplot
+     *
+     * This function uses gnuplot to plot this vector. You must supply the
+     * xlabel, ylabel, and title.
+     */
+    void showWithGnuPlot(const std::string& xlabel, const std::string& title)
+    {
+        checkDimension(1);
+
+        FileName fn_tmp;
+        fn_tmp.initRandom(10);
+        MultidimArray<T>::write(static_cast<std::string>("PPP") +
+                                fn_tmp + ".txt");
+
+        std::ofstream fh_gplot;
+        fh_gplot.open((static_cast<std::string>("PPP") + fn_tmp +
+                       ".gpl").c_str());
+        if (!fh_gplot)
+            REPORT_ERROR( static_cast<std::string>("vector::showWithGnuPlot: Cannot open PPP")
+                         + fn_tmp + ".gpl for output");
+        fh_gplot << "set xlabel \"" + xlabel + "\"\n";
+        fh_gplot << "plot \"PPP" + fn_tmp + ".txt\" title \"" + title +
+        "\" w l\n";
+        fh_gplot << "pause 300 \"\"\n";
+        fh_gplot.close();
+        system((static_cast<std::string>("(gnuplot PPP") + fn_tmp +
+                ".gpl; rm PPP" + fn_tmp + ".txt PPP" + fn_tmp + ".gpl) &").c_str());
+    }
+
+    /** Edit with xmipp_editor.
+     *
+     * This function generates a random filename starting with PPP and
+     * edits it with xmipp_editor. After closing the editor the file is
+     * removed.
+     */
+    void edit()
+    {
+        FileName nam;
+        nam.initRandom(15);
+
+        nam = static_cast< std::string >("PPP" + nam + ".txt");
+        write(nam);
+
+        system((static_cast< std::string >("xmipp_edit -i " + nam +
+                                           " -remove &").c_str()));
+    }
+
+    /* Write to a binary file
+     */
+    void writeBinary(const FileName& fn) const
+    {
+        std::ofstream out;
+
+        out.open(fn.c_str(), std::ios::out | std::ios::binary);
+        if (!out)
+            REPORT_ERROR(static_cast< std::string >("MultidimArray::write: File " + fn + " cannot be opened for output"));
+
+        T* ptr;
+        unsigned long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this, n, ptr)
+            out.write(reinterpret_cast< char* >(ptr), sizeof(T));
+
+        out.close();
+    }
+
+    /** Read from a binary file.
+     * The array must be previously resized to the correct size.
+     */
+    void readBinary(const FileName& fn)
+    {
+        std::ifstream in;
+        in.open(fn.c_str(), std::ios::in | std::ios::binary);
+        if (!in)
+            REPORT_ERROR(static_cast< std::string>("MultidimArray::read: File " + fn + " not found"));
+
+        T* ptr;
+        unsigned long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this, n, ptr)
+            in.read(reinterpret_cast< char* >(ptr), sizeof(T));
+
+        in.close();
+    }
+
+    /** Read from a binary file, while summing to the existing array
+     * The array must be previously resized to the correct size.
+     */
+    void readBinaryAndSum(const FileName& fn)
+    {
+        std::ifstream in;
+        in.open(fn.c_str(), std::ios::in | std::ios::binary);
+        if (!in)
+            REPORT_ERROR(static_cast< std::string>("MultidimArray::read: File " + fn + " not found"));
+
+        T* ptr;
+        T val;
+        unsigned long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(*this, n, ptr)
+        {
+        	in.read(reinterpret_cast< char* >(&val), sizeof(T));
+        	*ptr += val;
+        }
+
+        in.close();
+    }
+
+    /** Write to an ASCII file.
+     */
+    void write(const FileName& fn) const
+    {
+        std::ofstream out;
+        out.open(fn.c_str(), std::ios::out);
+        if (!out)
+            REPORT_ERROR( static_cast< std::string >("MultidimArray::write: File " + fn + " cannot be opened for output"));
+
+        out << *this;
+        out.close();
+    }
+
+    /** Read from an ASCII file.
+      */
+     void read(const FileName& fn) const
+     {
+         std::ofstream in;
+         in.open(fn.c_str(), std::ios::in);
+         if (!in)
+             REPORT_ERROR( static_cast< std::string >("MultidimArray::read: Cannot read File " + fn));
+
+         in >> *this;
+         in.close();
+     }
+      //@}
+
+    /// @name Operators
+    /// @{
+
+    /** Assignment.
+     *
+     * You can build as complex assignment expressions as you like. Multiple
+     * assignment is allowed.
+     *
+     * @code
+     * v1 = v2 + v3;
+     * v1 = v2 = v3;
+     * @endcode
+     *
+     * This function is ported to Python as assign.
+     */
+    MultidimArray<T>& operator=(const MultidimArray<T>& op1)
+    {
+        if (&op1 != this)
+        {
+            if (data == NULL || !sameShape(op1))
+                resize(op1);
+            memcpy(data,op1.data,MULTIDIM_SIZE(op1)*sizeof(T));
+        }
+        return *this;
+    }
+
+    /** Unary minus.
+     *
+     * It is used to build arithmetic expressions. You can make a minus
+     * of anything as long as it is correct semantically.
+     *
+     * @code
+     * v1 = -v2;
+     * v1 = -v2.transpose();
+     * @endcode
+     */
+    MultidimArray<T> operator-() const
+    {
+        MultidimArray<T> tmp(*this);
+        T* ptr;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(tmp,n,ptr)
+        *ptr = -(*ptr);
+        return tmp;
+    }
+
+    /** Input from input stream.
+     *
+     * Actual size of the array is used to know how many values must be read.
+     *
+     * @code
+     * v.<3);
+     * std::cin >> v;
+     * @endcode
+     *
+     * This function is not ported to Python.
+     */
+    friend std::istream& operator>>(std::istream& in, MultidimArray<T>& v)
+    {
+        T* ptr;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(v,n,ptr)
+        in >> *ptr;
+        return in;
+    }
+
+    /** Equality.
+     *
+     * Returns true if this object has got the same shape (origin and size)
+     * than the argument and the same values (within accuracy).
+     */
+    bool equal(const MultidimArray<T>& op,
+               double accuracy = XMIPP_EQUAL_ACCURACY) const
+    {
+        if (!sameShape(op) || data==NULL || op.data == NULL)
+            return false;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(*this)
+        if (ABS(DIRECT_MULTIDIM_ELEM(*this,n) -
+                DIRECT_MULTIDIM_ELEM(op,n)) > accuracy)
+            return false;
+        return true;
+    }
+    //@}
+};
+
+/// @name Functions for all multidimensional arrays
+/// @{
+
+/** Conversion from one type to another.
+ *
+ * If we have an integer array and we need a double one, we can use this
+ * function. The conversion is done through a type casting of each element
+ * If n >= 0, only the nth volumes will be converted, otherwise all NSIZE volumes
+ */
+template<typename T1, typename T2>
+void typeCast(const MultidimArray<T1>& v1,  MultidimArray<T2>& v2, long n = -1)
+{
+    if (NZYXSIZE(v1) == 0)
+    {
+        v2.clear();
+        return;
+    }
+
+    if (n < 0)
+    {
+        v2.resize(v1);
+        T1* ptr1=NULL;
+        long int n;
+        FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(v1,n,ptr1)
+        DIRECT_MULTIDIM_ELEM(v2,n) = static_cast< T2 >(*ptr1);
+    }
+    else
+    {
+        v2.resize(ZSIZE(v1),YSIZE(v1),XSIZE(v1));
+        FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(v2)
+        DIRECT_A3D_ELEM(v2,k,i,j) = static_cast< T2 >DIRECT_NZYX_ELEM(v1,n,k,i,j);
+    }
+
+}
+
+/** Force positive.
+ *  A median filter is applied at those negative values. Positive values are untouched.
+ */
+void forcePositive(MultidimArray<double> &V);
+
+/** MultidimArray equality.*/
+template<typename T>
+bool operator==(const MultidimArray<T>& op1, const MultidimArray<T>& op2)
+{
+    return op1.equal(op2);
+}
+
+/** MultidimArray inequality.*/
+template<typename T>
+bool operator!=(const MultidimArray<T>& op1, const MultidimArray<T>& op2)
+{
+    return !(op1==op2);
+}
+
+/** Reduce both volumes to a common size.
+ *
+ * Search the range of logical indexes for which both volumes have got valid
+ * values, and cut both to that size, the corresponding origin is automatically
+ * computed.
+ *
+ * @code
+ * MultidimArray< double > V1(4, 5, 3);
+ * V1.startingX() = -2;
+ * V1.startingY() = -2;
+ * V1.startingZ() = -2;
+ *
+ * MultidimArray< double > V2(4, 2, 3);
+ * V2.startingX() = 0;
+ * V2.startingY() = 0;
+ * V2.startingZ() = 0;
+ *
+ * // V1 and V2 range from (0,0,0)=(z,y,x) to (1,1,0)
+ * cutToCommonSize(V1, V2);
+ * @endcode
+ */
+template<typename T>
+void cutToCommonSize(MultidimArray<T>& V1, MultidimArray<T>& V2)
+{
+    long int z0 = XMIPP_MAX(STARTINGZ(V1), STARTINGZ(V2));
+    long int zF = XMIPP_MIN(FINISHINGZ(V1), FINISHINGZ(V2));
+    long int y0 = XMIPP_MAX(STARTINGY(V1), STARTINGY(V2));
+    long int yF = XMIPP_MIN(FINISHINGY(V1), FINISHINGY(V2));
+    long int x0 = XMIPP_MAX(STARTINGX(V1), STARTINGX(V2));
+    long int xF = XMIPP_MIN(FINISHINGX(V1), FINISHINGX(V2));
+
+    V1.window(z0, y0, x0, zF, yF, xF);
+    V2.window(z0, y0, x0, zF, yF, xF);
+}
+
+/** Output to output stream.
+ * This function is not ported to Python.
+ */
+template <typename T>
+std::ostream& operator<< (std::ostream& ostrm, const MultidimArray<T>& v)
+{
+    if (v.xdim == 0)
+        ostrm << "NULL Array\n";
+    else
+        ostrm << std::endl;
+
+    double max_val = ABS(DIRECT_A3D_ELEM(v , 0, 0, 0));
+
+    T* ptr;
+    long int n;
+    FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY_ptr(v,n,ptr)
+    max_val = XMIPP_MAX(max_val, ABS(*ptr));
+
+    int prec = bestPrecision(max_val, 10);
+
+    if (YSIZE(v)==1 && ZSIZE(v)==1)
+    {
+        for (long int j = STARTINGX(v); j <= FINISHINGX(v); j++)
+            ostrm << floatToString((double) A3D_ELEM(v, 0, 0, j), 10, prec)
+            << std::endl;
+    }
+    else
+    {
+        for (long int l = 0; l < NSIZE(v); l++)
+        {
+            if (NSIZE(v)>1)
+                ostrm << "Image No. " << l << std::endl;
+            for (long int k = STARTINGZ(v); k <= FINISHINGZ(v); k++)
+            {
+                if (ZSIZE(v)>1)
+                    ostrm << "Slice No. " << k << std::endl;
+                for (long int i = STARTINGY(v); i <= FINISHINGY(v); i++)
+                {
+                    for (long int j = STARTINGX(v); j <= FINISHINGX(v); j++)
+                    {
+                        ostrm << floatToString((double) A3D_ELEM(v, k, i, j), 10, prec) << ' ';
+                    }
+                    ostrm << std::endl;
+                }
+            }
+        }
+    }
+
+    return ostrm;
+}
+
+//@}
+
+// Specializations cases for complex numbers
+template<>
+std::ostream& operator<<(std::ostream& ostrm, const MultidimArray< Complex >& v);
+//@}
+#endif
diff --git a/src/numerical_recipes.cpp b/src/numerical_recipes.cpp
new file mode 100644
index 0000000..495774f
--- /dev/null
+++ b/src/numerical_recipes.cpp
@@ -0,0 +1,1340 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+
+#include "src/numerical_recipes.h"
+
+/* NUMERICAL UTILITIES ----------------------------------------------------- */
+void nrerror(const char error_text[])
+{
+    fprintf(stderr, "Numerical Recipes run-time error...\n");
+    fprintf(stderr, "%s\n", error_text);
+    fprintf(stderr, "...now exiting to system...\n");
+    exit(1);
+}
+#define NRSIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a))
+
+/* RANDOM NUMBERS ---------------------------------------------------------- */
+#define M1 259200
+#define IA1 7141
+#define IC1 54773
+#define RM1 (1.0/M1)
+#define M2 134456
+#define IA2 8121
+#define IC2 28411
+#define RM2 (1.0/M2)
+#define M3 243000
+#define IA3 4561
+#define IC3 51349
+
+/* Chapter 7 Section 1: UNIFORM RANDOM NUMBERS */
+double ran1(int *idum)
+{
+    static long ix1, ix2, ix3;
+    static double r[98];
+    double temp;
+    static int iff = 0;
+    int j;
+
+    if (*idum < 0 || iff == 0)
+    {
+        iff = 1;
+        ix1 = (IC1 - (*idum)) % M1;
+        ix1 = (IA1 * ix1 + IC1) % M1;
+        ix2 = ix1 % M2;
+        ix1 = (IA1 * ix1 + IC1) % M1;
+        ix3 = ix1 % M3;
+        for (j = 1;j <= 97;j++)
+        {
+            ix1 = (IA1 * ix1 + IC1) % M1;
+            ix2 = (IA2 * ix2 + IC2) % M2;
+            r[j] = (ix1 + ix2 * RM2) * RM1;
+        }
+        *idum = 1;
+    }
+    ix1 = (IA1 * ix1 + IC1) % M1;
+    ix2 = (IA2 * ix2 + IC2) % M2;
+    ix3 = (IA3 * ix3 + IC3) % M3;
+    j = 1 + ((97 * ix3) / M3);
+    if (j > 97 || j < 1)
+        nrerror("RAN1: This cannot happen.");
+    temp = r[j];
+    r[j] = (ix1 + ix2 * RM2) * RM1;
+    return temp;
+}
+
+#undef M1
+#undef IA1
+#undef IC1
+#undef RM1
+#undef M2
+#undef IA2
+#undef IC2
+#undef RM2
+#undef M3
+#undef IA3
+#undef IC3
+
+/* Chapter 7 Section 3: GAUSSIAN RANDOM NUMBERS */
+double gasdev(int *idum)
+{
+    static int iset = 0;
+    static double gset;
+    double fac, r, v1, v2;
+
+    if (iset == 0)
+    {
+        do
+        {
+            v1 = 2.0 * ran1(idum) - 1.0;
+            v2 = 2.0 * ran1(idum) - 1.0;
+            r = v1 * v1 + v2 * v2;
+        }
+        while (r >= 1.0);
+        fac = sqrt(-2.0 * log(r) / r);
+        gset = v1 * fac;
+        iset = 1;
+        return v2*fac;
+    }
+    else
+    {
+        iset = 0;
+        return gset;
+    }
+}
+
+// t-distribution (nor Numerical Recipes, but Mathematics of Computation, vol. 62, 779-781.
+// I downloaded sem-code from http://ideas.repec.org/c/ega/comcod/200703.html
+// Sjors May 2008
+double tdev(double nu, int *idum)
+{
+    static int iset = 0;
+    static double gset;
+    double fac, r, v1, v2;
+
+    if (iset == 0)
+    {
+        do
+        {
+            v1 = 2.0 * ran1(idum) - 1.0;
+            v2 = 2.0 * ran1(idum) - 1.0;
+            r = v1 * v1 + v2 * v2;
+        }
+        while (r >= 1.0);
+        fac = sqrt(nu*(pow(r,-2.0/nu) -1.0)/r);
+        gset = v1 * fac;
+        iset = 1;
+        return v2*fac;
+    }
+    else
+    {
+        iset = 0;
+        return gset;
+    }
+}
+
+
+/* BESSEL FUNCTIONS -------------------------------------------------------- */
+/* CO: They may not come in the numerical recipes but it is not a bad
+   idea to put them here, in fact they come from Gabor's group in Feb'84     */
+double bessj0(double x)
+{
+    double ax, z;
+    double xx, y, ans, ans1, ans2;
+
+    if ((ax = fabs(x)) < 8.0)
+    {
+        y = x * x;
+        ans1 = 57568490574.0 + y * (-13362590354.0 +
+                                    y * (651619640.7
+                                         + y * (-11214424.18 +
+                                                y * (77392.33017 +
+                                                     y * (-184.9052456)))));
+        ans2 = 57568490411.0 + y * (1029532985.0 +
+                                    y * (9494680.718
+                                         + y * (59272.64853 +
+                                                y * (267.8532712 +
+                                                     y * 1.0))));
+        ans = ans1 / ans2;
+    }
+    else
+    {
+        z = 8.0 / ax;
+        y = z * z;
+        xx = ax - 0.785398164;
+        ans1 = 1.0 + y * (-0.1098628627e-2 + y * (0.2734510407e-4
+                          + y * (-0.2073370639e-5 + y * 0.2093887211e-6)));
+        ans2 = -0.1562499995e-1 + y * (0.1430488765e-3
+                                       + y * (-0.6911147651e-5 + y * (0.7621095161e-6
+                                                                      - y * 0.934935152e-7)));
+        ans = sqrt(0.636619772 / ax) * (cos(xx) * ans1 - z * sin(xx) * ans2);
+    }
+    return ans;
+}
+
+/*............................................................................*/
+double bessi0(double x)
+{
+    double y, ax, ans;
+    if ((ax = fabs(x)) < 3.75)
+    {
+        y = x / 3.75;
+        y *= y;
+        ans = 1.0 + y * (3.5156229 + y * (3.0899424 + y * (1.2067492
+                                          + y * (0.2659732 + y * (0.360768e-1 + y * 0.45813e-2)))));
+    }
+    else
+    {
+        y = 3.75 / ax;
+        ans = (exp(ax) / sqrt(ax)) * (0.39894228 + y * (0.1328592e-1
+                                      + y * (0.225319e-2 + y * (-0.157565e-2 + y * (0.916281e-2
+                                                                + y * (-0.2057706e-1 + y * (0.2635537e-1 + y * (-0.1647633e-1
+                                                                                            + y * 0.392377e-2))))))));
+    }
+    return ans;
+}
+
+/*............................................................................*/
+double bessi1(double x)
+{
+    double ax, ans;
+    double y;
+    if ((ax = fabs(x)) < 3.75)
+    {
+        y = x / 3.75;
+        y *= y;
+        ans = ax * (0.5 + y * (0.87890594 + y * (0.51498869 + y * (0.15084934
+                               + y * (0.2658733e-1 + y * (0.301532e-2 + y * 0.32411e-3))))));
+    }
+    else
+    {
+        y = 3.75 / ax;
+        ans = 0.2282967e-1 + y * (-0.2895312e-1 + y * (0.1787654e-1
+                                  - y * 0.420059e-2));
+        ans = 0.39894228 + y * (-0.3988024e-1 + y * (-0.362018e-2
+                                + y * (0.163801e-2 + y * (-0.1031555e-1 + y * ans))));
+        ans *= (exp(ax) / sqrt(ax));
+    }
+    return x < 0.0 ? -ans : ans;
+}
+
+/* General Bessel functions ------------------------------------------------ */
+double chebev(double a, double b, double c[], int m, double x)
+{
+    double d = 0.0, dd = 0.0, sv, y, y2;
+    int j;
+
+    if ((x - a)*(x - b) > 0.0)
+        nrerror("x not in range in routine chebev");
+    y2 = 2.0 * (y = (2.0 * x - a - b) / (b - a));
+    for (j = m - 1;j >= 1;j--)
+    {
+        sv = d;
+        d = y2 * d - dd + c[j];
+        dd = sv;
+    }
+    return y*d - dd + 0.5*c[0];
+}
+#define NUSE1 5
+#define NUSE2 5
+
+void beschb(double x, double *gam1, double *gam2, double *gampl, double *gammi)
+{
+    double xx;
+    static double c1[] =
+        {
+            -1.142022680371172e0, 6.516511267076e-3,
+            3.08709017308e-4, -3.470626964e-6, 6.943764e-9,
+            3.6780e-11, -1.36e-13
+        };
+    static double c2[] =
+        {
+            1.843740587300906e0, -0.076852840844786e0,
+            1.271927136655e-3, -4.971736704e-6, -3.3126120e-8,
+            2.42310e-10, -1.70e-13, -1.0e-15
+        };
+
+    xx = 8.0 * x * x - 1.0;
+    *gam1 = chebev(-1.0, 1.0, c1, NUSE1, xx);
+    *gam2 = chebev(-1.0, 1.0, c2, NUSE2, xx);
+    *gampl = *gam2 - x * (*gam1);
+    *gammi = *gam2 + x * (*gam1);
+}
+
+#undef NUSE1
+#undef NUSE2
+
+#define EPS 1.0e-16
+#define FPMIN 1.0e-30
+#define MAXIT 10000
+#define XMIN 2.0
+void bessjy(double x, double xnu, double *rj, double *ry, double *rjp, double *ryp)
+{
+    int i, isign, l, nl;
+    double a, b, br, bi, c, cr, ci, d, del, del1, den, di, dlr, dli, dr, e, f, fact, fact2,
+    fact3, ff, gam, gam1, gam2, gammi, gampl, h, p, pimu, pimu2, q, r, rjl,
+    rjl1, rjmu, rjp1, rjpl, rjtemp, ry1, rymu, rymup, rytemp, sum, sum1,
+    temp, w, x2, xi, xi2, xmu, xmu2;
+
+    if (x <= 0.0 || xnu < 0.0)
+        nrerror("bad arguments in bessjy");
+    nl = (x < XMIN ? (int)(xnu + 0.5) : XMIPP_MAX(0, (int)(xnu - x + 1.5)));
+    xmu = xnu - nl;
+    xmu2 = xmu * xmu;
+    xi = 1.0 / x;
+    xi2 = 2.0 * xi;
+    w = xi2 / PI;
+    isign = 1;
+    h = xnu * xi;
+    if (h < FPMIN)
+        h = FPMIN;
+    b = xi2 * xnu;
+    d = 0.0;
+    c = h;
+    for (i = 1;i <= MAXIT;i++)
+    {
+        b += xi2;
+        d = b - d;
+        if (fabs(d) < FPMIN)
+            d = FPMIN;
+        c = b - 1.0 / c;
+        if (fabs(c) < FPMIN)
+            c = FPMIN;
+        d = 1.0 / d;
+        del = c * d;
+        h = del * h;
+        if (d < 0.0)
+            isign = -isign;
+        if (fabs(del - 1.0) < EPS)
+            break;
+    }
+    if (i > MAXIT)
+        nrerror("x too large in bessjy; try asymptotic expansion");
+    rjl = isign * FPMIN;
+    rjpl = h * rjl;
+    rjl1 = rjl;
+    rjp1 = rjpl;
+    fact = xnu * xi;
+    for (l = nl;l >= 1;l--)
+    {
+        rjtemp = fact * rjl + rjpl;
+        fact -= xi;
+        rjpl = fact * rjtemp - rjl;
+        rjl = rjtemp;
+    }
+    if (rjl == 0.0)
+        rjl = EPS;
+    f = rjpl / rjl;
+    if (x < XMIN)
+    {
+        x2 = 0.5 * x;
+        pimu = PI * xmu;
+        fact = (fabs(pimu) < EPS ? 1.0 : pimu / sin(pimu));
+        d = -log(x2);
+        e = xmu * d;
+        fact2 = (fabs(e) < EPS ? 1.0 : sinh(e) / e);
+        beschb(xmu, &gam1, &gam2, &gampl, &gammi);
+        ff = 2.0 / PI * fact * (gam1 * cosh(e) + gam2 * fact2 * d);
+        e = exp(e);
+        p = e / (gampl * PI);
+        q = 1.0 / (e * PI * gammi);
+        pimu2 = 0.5 * pimu;
+        fact3 = (fabs(pimu2) < EPS ? 1.0 : sin(pimu2) / pimu2);
+        r = PI * pimu2 * fact3 * fact3;
+        c = 1.0;
+        d = -x2 * x2;
+        sum = ff + r * q;
+        sum1 = p;
+        for (i = 1;i <= MAXIT;i++)
+        {
+            ff = (i * ff + p + q) / (i * i - xmu2);
+            c *= (d / i);
+            p /= (i - xmu);
+            q /= (i + xmu);
+            del = c * (ff + r * q);
+            sum += del;
+            del1 = c * p - i * del;
+            sum1 += del1;
+            if (fabs(del) < (1.0 + fabs(sum))*EPS)
+                break;
+        }
+        if (i > MAXIT)
+            nrerror("bessy series failed to converge");
+        rymu = -sum;
+        ry1 = -sum1 * xi2;
+        rymup = xmu * xi * rymu - ry1;
+        rjmu = w / (rymup - f * rymu);
+    }
+    else
+    {
+        a = 0.25 - xmu2;
+        p = -0.5 * xi;
+        q = 1.0;
+        br = 2.0 * x;
+        bi = 2.0;
+        fact = a * xi / (p * p + q * q);
+        cr = br + q * fact;
+        ci = bi + p * fact;
+        den = br * br + bi * bi;
+        dr = br / den;
+        di = -bi / den;
+        dlr = cr * dr - ci * di;
+        dli = cr * di + ci * dr;
+        temp = p * dlr - q * dli;
+        q = p * dli + q * dlr;
+        p = temp;
+        for (i = 2;i <= MAXIT;i++)
+        {
+            a += 2 * (i - 1);
+            bi += 2.0;
+            dr = a * dr + br;
+            di = a * di + bi;
+            if (fabs(dr) + fabs(di) < FPMIN)
+                dr = FPMIN;
+            fact = a / (cr * cr + ci * ci);
+            cr = br + cr * fact;
+            ci = bi - ci * fact;
+            if (fabs(cr) + fabs(ci) < FPMIN)
+                cr = FPMIN;
+            den = dr * dr + di * di;
+            dr /= den;
+            di /= -den;
+            dlr = cr * dr - ci * di;
+            dli = cr * di + ci * dr;
+            temp = p * dlr - q * dli;
+            q = p * dli + q * dlr;
+            p = temp;
+            if (fabs(dlr - 1.0) + fabs(dli) < EPS)
+                break;
+        }
+        if (i > MAXIT)
+            nrerror("cf2 failed in bessjy");
+        gam = (p - f) / q;
+        rjmu = sqrt(w / ((p - f) * gam + q));
+        rjmu = NRSIGN(rjmu, rjl);
+        rymu = rjmu * gam;
+        rymup = rymu * (p + q / gam);
+        ry1 = xmu * xi * rymu - rymup;
+    }
+    fact = rjmu / rjl;
+    *rj = rjl1 * fact;
+    *rjp = rjp1 * fact;
+    for (i = 1;i <= nl;i++)
+    {
+        rytemp = (xmu + i) * xi2 * ry1 - rymu;
+        rymu = ry1;
+        ry1 = rytemp;
+    }
+    *ry = rymu;
+    *ryp = xnu * xi * rymu - ry1;
+}
+#undef EPS
+#undef FPMIN
+#undef MAXIT
+#undef XMIN
+
+/*............................................................................*/
+double bessi0_5(double x)
+{
+    return (x == 0) ? 0 : sqrt(2 / (PI*x))*sinh(x);
+}
+double bessi1_5(double x)
+{
+    return (x == 0) ? 0 : sqrt(2 / (PI*x))*(cosh(x) - sinh(x) / x);
+}
+double bessi2(double x)
+{
+    return (x == 0) ? 0 : bessi0(x) - ((2*1) / x) * bessi1(x);
+}
+double bessi2_5(double x)
+{
+    return (x == 0) ? 0 : bessi0_5(x) - ((2*1.5) / x) * bessi1_5(x);
+}
+double bessi3(double x)
+{
+    return (x == 0) ? 0 : bessi1(x) - ((2*2) / x) * bessi2(x);
+}
+double bessi3_5(double x)
+{
+    return (x == 0) ? 0 : bessi1_5(x) - ((2*2.5) / x) * bessi2_5(x);
+}
+double bessi4(double x)
+{
+    return (x == 0) ? 0 : bessi2(x) - ((2*3) / x) * bessi3(x);
+}
+double bessj1_5(double x)
+{
+    double rj, ry, rjp, ryp;
+    bessjy(x, 1.5, &rj, &ry, &rjp, &ryp);
+    return rj;
+}
+double bessj3_5(double x)
+{
+    double rj, ry, rjp, ryp;
+    bessjy(x, 3.5, &rj, &ry, &rjp, &ryp);
+    return rj;
+}
+
+/* Special functions ------------------------------------------------------- */
+double gammln(double xx)
+{
+    double x, tmp, ser;
+    static double cof[6] =
+        {
+            76.18009173, -86.50532033, 24.01409822,
+            -1.231739516, 0.120858003e-2, -0.536382e-5
+        };
+    int j;
+
+    x = xx - 1.0;
+    tmp = x + 5.5;
+    tmp -= (x + 0.5) * log(tmp);
+    ser = 1.0;
+    for (j = 0;j <= 5;j++)
+    {
+        x += 1.0;
+        ser += cof[j] / x;
+    }
+    return -tmp + log(2.50662827465*ser);
+}
+
+
+double betai(double a, double b, double x)
+{
+    double bt;
+    if (x < 0.0 || x > 1.0)
+        nrerror("Bad x in routine BETAI");
+    if (x == 0.0 || x == 1.0)
+        bt = 0.0;
+    else
+        bt = exp(gammln(a + b) - gammln(a) - gammln(b) + a * log(x) + b * log(1.0 - x));
+    if (x < (a + 1.0) / (a + b + 2.0))
+        return bt*betacf(a, b, x) / a;
+    else
+        return 1.0 -bt*betacf(b, a, 1.0 - x) / b;
+
+}
+
+#define ITMAX 100
+#define EPS 3.0e-7
+double betacf(double a, double b, double x)
+{
+    double qap, qam, qab, em, tem, d;
+    double bz, bm = 1.0, bp, bpp;
+    double az = 1.0, am = 1.0, ap, app, aold;
+    int m;
+
+    qab = a + b;
+    qap = a + 1.0;
+    qam = a - 1.0;
+    bz = 1.0 - qab * x / qap;
+    for (m = 1;m <= ITMAX;m++)
+    {
+        em = (double) m;
+        tem = em + em;
+        d = em * (b - em) * x / ((qam + tem) * (a + tem));
+        ap = az + d * am;
+        bp = bz + d * bm;
+        d = -(a + em) * (qab + em) * x / ((qap + tem) * (a + tem));
+        app = ap + d * az;
+        bpp = bp + d * bz;
+        aold = az;
+        am = ap / bpp;
+        bm = bp / bpp;
+        az = app / bpp;
+        bz = 1.0;
+        if (fabs(az - aold) < (EPS*fabs(az)))
+            return az;
+    }
+    nrerror("a or b too big, or ITMAX too small in BETACF");
+    return 0;
+}
+#undef ITMAX
+#undef EPS
+
+/* Powell optimization ------------------------------------------------------------ */
+#undef MAX
+#undef SIGN
+#define GOLD 1.618034
+#define GLIMIT 100.0
+#define TINY 1.0e-20
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#define SIGN(a,b) ((b) > 0.0 ? fabs(a) : -fabs(a))
+#define SHFT(a,b,c,d) (a)=(b);(b)=(c);(c)=(d);
+#define F1DIM(x,f) {\
+    for (int j = 1; j<=ncom; j++) \
+        xt[j] = pcom[j] + x * xicom[j]; \
+    f = (*func)(xt,prm);}
+
+void mnbrak(double *ax, double *bx, double *cx,
+            double *fa, double *fb, double *fc, double(*func)(double *, void*),
+            void *prm, int ncom, double *pcom, double *xicom)
+{
+    double ulim, u, r, q, fu, dum;
+    double *xt=NULL;
+    ask_Tvector(xt, 1, ncom);
+
+    F1DIM(*ax,*fa);
+    F1DIM(*bx,*fb);
+    if (*fb > *fa)
+    {
+        SHFT(dum, *ax, *bx, dum)
+        SHFT(dum, *fb, *fa, dum)
+    }
+    *cx = (*bx) + GOLD * (*bx - *ax);
+    F1DIM(*cx,*fc);
+    while (*fb > *fc)
+    {
+        r = (*bx - *ax) * (*fb - *fc);
+        q = (*bx - *cx) * (*fb - *fa);
+        u = (*bx) - ((*bx - *cx) * q - (*bx - *ax) * r) /
+            (2.0 * SIGN(MAX(fabs(q - r), TINY), q - r));
+        ulim = (*bx) + GLIMIT * (*cx - *bx);
+        if ((*bx - u)*(u - *cx) > 0.0)
+        {
+            F1DIM(u,fu);
+            if (fu < *fc)
+            {
+                *ax = (*bx);
+                *bx = u;
+                *fa = (*fb);
+                *fb = fu;
+                return;
+            }
+            else if (fu > *fb)
+            {
+                *cx = u;
+                *fc = fu;
+                return;
+            }
+            u = (*cx) + GOLD * (*cx - *bx);
+            F1DIM(u,fu);
+        }
+        else if ((*cx - u)*(u - ulim) > 0.0)
+        {
+            F1DIM(u,fu);
+            if (fu < *fc)
+            {
+                SHFT(*bx, *cx, u, *cx + GOLD*(*cx - *bx))
+                double aux; F1DIM(u,aux);
+                SHFT(*fb, *fc, fu, aux)
+            }
+        }
+        else if ((u - ulim)*(ulim - *cx) >= 0.0)
+        {
+            u = ulim;
+            F1DIM(u,fu);
+        }
+        else
+        {
+            u = (*cx) + GOLD * (*cx - *bx);
+            F1DIM(u,fu);
+        }
+        SHFT(*ax, *bx, *cx, u)
+        SHFT(*fa, *fb, *fc, fu)
+    }
+    free_Tvector(xt, 1, ncom);
+}
+
+#undef GOLD
+#undef GLIMIT
+#undef TINY
+#undef MAX
+
+#define ITMAX 100
+#define CGOLD 0.3819660
+#define ZEPS 1.0e-10
+double brent(double ax, double bx, double cx, double(*func)(double *,void*),
+             void *prm, double tol, double *xmin,
+             int ncom, double *pcom, double *xicom)
+{
+    int iter;
+    double a, b, d, etemp, fu, fv, fw, fx, p, q, r, tol1, tol2, u, v, w, x, xm;
+    double e = 0.0;
+    double *xt=NULL;
+    ask_Tvector(xt, 1, ncom);
+
+    a = (ax < cx ? ax : cx);
+    b = (ax > cx ? ax : cx);
+    x = w = v = bx;
+    F1DIM(x,fx);
+    fw = fv = fx;
+    for (iter = 1;iter <= ITMAX;iter++)
+    {
+        xm = 0.5 * (a + b);
+        tol2 = 2.0 * (tol1 = tol * fabs(x) + ZEPS);
+        if (fabs(x - xm) <= (tol2 - 0.5*(b - a)))
+        {
+            *xmin = x;
+            free_Tvector(xt, 1, ncom);
+            return fx;
+        }
+        if (fabs(e) > tol1)
+        {
+            r = (x - w) * (fx - fv);
+            q = (x - v) * (fx - fw);
+            p = (x - v) * q - (x - w) * r;
+            q = 2.0 * (q - r);
+            if (q > 0.0)
+                p = -p;
+            q = fabs(q);
+            etemp = e;
+            e = d;
+            if (fabs(p) >= fabs(0.5*q*etemp) || p <= q*(a - x) || p >= q*(b - x))
+                d = CGOLD * (e = (x >= xm ? a - x : b - x));
+            else
+            {
+                d = p / q;
+                u = x + d;
+                if (u - a < tol2 || b - u < tol2)
+                    d = SIGN(tol1, xm - x);
+            }
+        }
+        else
+        {
+            d = CGOLD * (e = (x >= xm ? a - x : b - x));
+        }
+        u = (fabs(d) >= tol1 ? x + d : x + SIGN(tol1, d));
+        F1DIM(u,fu);
+        if (fu <= fx)
+        {
+            if (u >= x)
+                a = x;
+            else
+                b = x;
+            SHFT(v, w, x, u)
+            SHFT(fv, fw, fx, fu)
+        }
+        else
+        {
+            if (u < x)
+                a = u;
+            else
+                b = u;
+            if (fu <= fw || w == x)
+            {
+                v = w;
+                w = u;
+                fv = fw;
+                fw = fu;
+            }
+            else if (fu <= fv || v == x || v == w)
+            {
+                v = u;
+                fv = fu;
+            }
+        }
+    }
+    nrerror("Too many iterations in brent");
+    *xmin = x;
+    free_Tvector(xt, 1, ncom);
+    return fx;
+}
+#undef ITMAX
+#undef CGOLD
+#undef ZEPS
+#undef SHFT
+#undef F1DIM
+
+#define TOL 2.0e-4
+void linmin(double *p, double *xi, int n, double &fret,
+            double(*func)(double *, void*), void *prm)
+{
+    int j;
+    double xx, xmin, fx, fb, fa, bx, ax;
+
+    int ncom = n;
+    double *pcom=NULL;
+    double *xicom=NULL;
+    ask_Tvector(pcom, 1, n);
+    ask_Tvector(xicom, 1, n);
+    for (j = 1;j <= n;j++)
+    {
+        pcom[j] = p[j];
+        xicom[j] = xi[j];
+    }
+    ax = 0.0;
+    xx = 1.0;
+    bx = 2.0;
+    mnbrak(&ax, &xx, &bx, &fa, &fx, &fb, func, prm, ncom, pcom, xicom);
+    fret = brent(ax, xx, bx, func, prm, TOL, &xmin, ncom, pcom, xicom);
+    for (j = 1;j <= n;j++)
+    {
+        xi[j] *= xmin;
+        p[j] += xi[j];
+    }
+    free_Tvector(xicom, 1, n);
+    free_Tvector(pcom, 1, n);
+}
+#undef TOL
+
+#define ITMAX 200
+void powell(double *p, double *xi, int n, double ftol, int &iter,
+            double &fret, double(*func)(double *, void *), void *prm,
+            bool show)
+{
+    int i, ibig, j;
+    double t, fptt, fp, del;
+    double *pt, *ptt, *xit;
+    bool   different_from_0;
+
+    ask_Tvector(pt, 1, n);
+    ask_Tvector(ptt, 1, n);
+    ask_Tvector(xit, 1, n);
+    fret = (*func)(p,prm);
+    for (j = 1;j <= n;j++)
+        pt[j] = p[j];
+
+    for (iter = 1;;(iter)++)
+    {
+        /* By coss ----- */
+        if (show)
+        {
+            std::cout << iter << " (" << p[1];
+            for (int co = 2; co <= n; co++)
+                std::cout << "," << p[co];
+            std::cout << ")--->" << fret << std::endl;
+        }
+        /* ------------- */
+
+        fp = fret;
+        ibig = 0;
+        del = 0.0;
+        for (i = 1;i <= n;i++)
+        {
+            different_from_0 = false; // CO
+            for (j = 1;j <= n;j++)
+            {
+                xit[j] = xi[j*n+i];
+                if (xit[j] != 0)
+                    different_from_0 = true;
+            }
+            if (different_from_0)
+            {
+                fptt = fret;
+                linmin(p, xit, n, fret, func, prm);
+                if (fabs(fptt - fret) > del)
+                {
+                    del = fabs(fptt - fret);
+                    ibig = i;
+                }
+                /* By coss ----- */
+                if (show)
+                {
+                    std::cout << "   (";
+                    if (i == 1)
+                        std::cout << "***";
+                    std::cout << p[1];
+                    for (int co = 2; co <= n; co++)
+                    {
+                        std::cout << ",";
+                        if (co == i)
+                            std::cout << "***";
+                        std::cout << p[co];
+                    }
+                    std::cout << ")--->" << fret << std::endl;
+                }
+                /* ------------- */
+            }
+        }
+        if (2.0*fabs(fp - fret) <= ftol*(fabs(fp) + fabs(fret)))
+        {
+            free_Tvector(xit, 1, n);
+            free_Tvector(ptt, 1, n);
+            free_Tvector(pt, 1, n);
+            return;
+        }
+        if (iter == ITMAX)
+            nrerror("Too many iterations in routine POWELL");
+        for (j = 1;j <= n;j++)
+        {
+            ptt[j] = 2.0 * p[j] - pt[j];
+            xit[j] = p[j] - pt[j];
+            pt[j] = p[j];
+        }
+        fptt = (*func)(ptt,prm);
+        if (fptt < fp)
+        {
+            #define SQR(a) ((a)*(a))
+            t = 2.0 * (fp - 2.0 * fret + fptt) * SQR(fp - fret - del) - del * SQR(fp - fptt);
+            if (t < 0.0)
+            {
+                linmin(p, xit, n, fret, func, prm);
+                for (j = 1;j <= n;j++)
+                    xi[j*n+ibig] = xit[j];
+            }
+        }
+    }
+}
+#undef ITMAX
+#undef SQR
+
+/* Singular value descomposition ------------------------------------------- */
+/* Copied from Bilib library (linearalgebra.h) */
+double Pythag(double a, double b)
+{
+    double absa, absb;
+    absa = fabs(a);
+    absb = fabs(b);
+    if (absb < absa)
+        return(absa * sqrt(1.0 + absb * absb / (absa * absa)));
+    else
+        return((absb == 0.0) ? (0.0) : (absb * sqrt(1.0 + absa * absa / (absb * absb))));
+}
+
+#define SVDMAXITER 1000
+void svdcmp(double *U, int Lines, int Columns, double *W, double *V)
+{
+    double *rv1 = (double *)NULL;
+    double Norm, Scale;
+    double c, f, g, h, s;
+    double x, y, z;
+    long i, its, j, jj, k, l = 0L, nm = 0L;
+    bool    Flag;
+    int     MaxIterations = SVDMAXITER;
+
+    ask_Tvector(rv1, 0, Columns*Columns - 1);
+    g = Scale = Norm = 0.0;
+    for (i = 0L; (i < Columns); i++)
+    {
+        l = i + 1L;
+        rv1[i] = Scale * g;
+        g = s = Scale = 0.0;
+        if (i < Lines)
+        {
+            for (k = i; (k < Lines); k++)
+            {
+                Scale += fabs(U[k * Columns + i]);
+            }
+            if (Scale != 0.0)
+            {
+                for (k = i; (k < Lines); k++)
+                {
+                    U[k * Columns + i] /= Scale;
+                    s += U[k * Columns + i] * U[k * Columns + i];
+                }
+                f = U[i * Columns + i];
+                g = (0.0 <= f) ? (-sqrt(s)) : (sqrt(s));
+                h = f * g - s;
+                U[i * Columns + i] = f - g;
+                for (j = l; (j < Columns); j++)
+                {
+                    for (s = 0.0, k = i; (k < Lines); k++)
+                    {
+                        s += U[k * Columns + i] * U[k * Columns + j];
+                    }
+                    f = s / h;
+                    for (k = i; (k < Lines); k++)
+                    {
+                        U[k * Columns + j] += f * U[k * Columns + i];
+                    }
+                }
+                for (k = i; (k < Lines); k++)
+                {
+                    U[k * Columns + i] *= Scale;
+                }
+            }
+        }
+        W[i] = Scale * g;
+        g = s = Scale = 0.0;
+        if ((i < Lines) && (i != (Columns - 1L)))
+        {
+            for (k = l; (k < Columns); k++)
+            {
+                Scale += fabs(U[i * Columns + k]);
+            }
+            if (Scale != 0.0)
+            {
+                for (k = l; (k < Columns); k++)
+                {
+                    U[i * Columns + k] /= Scale;
+                    s += U[i * Columns + k] * U[i * Columns + k];
+                }
+                f = U[i * Columns + l];
+                g = (0.0 <= f) ? (-sqrt(s)) : (sqrt(s));
+                h = f * g - s;
+                U[i * Columns + l] = f - g;
+                for (k = l; (k < Columns); k++)
+                {
+                    rv1[k] = U[i * Columns + k] / h;
+                }
+                for (j = l; (j < Lines); j++)
+                {
+                    for (s = 0.0, k = l; (k < Columns); k++)
+                    {
+                        s += U[j * Columns + k] * U[i * Columns + k];
+                    }
+                    for (k = l; (k < Columns); k++)
+                    {
+                        U[j * Columns + k] += s * rv1[k];
+                    }
+                }
+                for (k = l; (k < Columns); k++)
+                {
+                    U[i * Columns + k] *= Scale;
+                }
+            }
+        }
+        Norm = ((fabs(W[i]) + fabs(rv1[i])) < Norm) ? (Norm) : (fabs(W[i]) + fabs(rv1[i]));
+    }
+    for (i = Columns - 1L; (0L <= i); i--)
+    {
+        if (i < (Columns - 1L))
+        {
+            if (g != 0.0)
+            {
+                for (j = l; (j < Columns); j++)
+                {
+                    V[j * Columns + i] = U[i * Columns + j] / (U[i * Columns + l] * g);
+                }
+                for (j = l; (j < Columns); j++)
+                {
+                    for (s = 0.0, k = l; (k < Columns); k++)
+                    {
+                        s += U[i * Columns + k] * V[k * Columns + j];
+                    }
+                    for (k = l; (k < Columns); k++)
+                    {
+                        if (s != 0.0)
+                        {
+                            V[k * Columns + j] += s * V[k * Columns + i];
+                        }
+                    }
+                }
+            }
+            for (j = l; (j < Columns); j++)
+            {
+                V[i * Columns + j] = V[j * Columns + i] = 0.0;
+            }
+        }
+        V[i * Columns + i] = 1.0;
+        g = rv1[i];
+        l = i;
+    }
+    for (i = (Lines < Columns) ? (Lines - 1L) : (Columns - 1L); (0L <= i); i--)
+    {
+        l = i + 1L;
+        g = W[i];
+        for (j = l; (j < Columns); j++)
+        {
+            U[i * Columns + j] = 0.0;
+        }
+        if (g != 0.0)
+        {
+            g = 1.0 / g;
+            for (j = l; (j < Columns); j++)
+            {
+                for (s = 0.0, k = l; (k < Lines); k++)
+                {
+                    s += U[k * Columns + i] * U[k * Columns + j];
+                }
+                f = s * g / U[i * Columns + i];
+                for (k = i; (k < Lines); k++)
+                {
+                    if (f != 0.0)
+                    {
+                        U[k * Columns + j] += f * U[k * Columns + i];
+                    }
+                }
+            }
+            for (j = i; (j < Lines); j++)
+            {
+                U[j * Columns + i] *= g;
+            }
+        }
+        else
+        {
+            for (j = i; (j < Lines); j++)
+            {
+                U[j * Columns + i] = 0.0;
+            }
+        }
+        U[i * Columns + i] += 1.0;
+    }
+    for (k = Columns - 1L; (0L <= k); k--)
+    {
+        for (its = 1L; (its <= MaxIterations); its++)
+        {
+            Flag = true;
+            for (l = k; (0L <= l); l--)
+            {
+                nm = l - 1L;
+                if ((fabs(rv1[l]) + Norm) == Norm)
+                {
+                    Flag = false;
+                    break;
+                }
+                if ((fabs(W[nm]) + Norm) == Norm)
+                {
+                    break;
+                }
+            }
+            if (Flag)
+            {
+                c = 0.0;
+                s = 1.0;
+                for (i = l; (i <= k); i++)
+                {
+                    f = s * rv1[i];
+                    rv1[i] *= c;
+                    if ((fabs(f) + Norm) == Norm)
+                    {
+                        break;
+                    }
+                    g = W[i];
+                    h = Pythag(f, g);
+                    W[i] = h;
+                    h = 1.0 / h;
+                    c = g * h;
+                    s = -f * h;
+                    for (j = 0L; (j < Lines); j++)
+                    {
+                        y = U[j * Columns + nm];
+                        z = U[j * Columns + i];
+                        U[j * Columns + nm] = y * c + z * s;
+                        U[j * Columns + i] = z * c - y * s;
+                    }
+                }
+            }
+            z = W[k];
+            if (l == k)
+            {
+                if (z < 0.0)
+                {
+                    W[k] = -z;
+                    for (j = 0L; (j < Columns); j++)
+                    {
+                        V[j * Columns + k] = -V[j * Columns + k];
+                    }
+                }
+                break;
+            }
+            if (its == MaxIterations)
+            {
+                free_Tvector(rv1, 0, Columns*Columns - 1);
+                return;
+            }
+            x = W[l];
+            nm = k - 1L;
+            y = W[nm];
+            g = rv1[nm];
+            h = rv1[k];
+            f = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0 * h * y);
+            g = Pythag(f, 1.0);
+            f = ((x - z) * (x + z) + h * ((y / (f + ((0.0 <= f) ? (fabs(g))
+                                                : (-fabs(g))))) - h)) / x;
+            c = s = 1.0;
+            for (j = l; (j <= nm); j++)
+            {
+                i = j + 1L;
+                g = rv1[i];
+                y = W[i];
+                h = s * g;
+                g = c * g;
+                z = Pythag(f, h);
+                rv1[j] = z;
+                c = f / z;
+                s = h / z;
+                f = x * c + g * s;
+                g = g * c - x * s;
+                h = y * s;
+                y *= c;
+                for (jj = 0L; (jj < Columns); jj++)
+                {
+                    x = V[jj * Columns + j];
+                    z = V[jj * Columns + i];
+                    V[jj * Columns + j] = x * c + z * s;
+                    V[jj * Columns + i] = z * c - x * s;
+                }
+                z = Pythag(f, h);
+                W[j] = z;
+                if (z != 0.0)
+                {
+                    z = 1.0 / z;
+                    c = f * z;
+                    s = h * z;
+                }
+                f = c * g + s * y;
+                x = c * y - s * g;
+                for (jj = 0L; (jj < Lines); jj++)
+                {
+                    y = U[jj * Columns + j];
+                    z = U[jj * Columns + i];
+                    U[jj * Columns + j] = y * c + z * s;
+                    U[jj * Columns + i] = z * c - y * s;
+                }
+            }
+            rv1[l] = 0.0;
+            rv1[k] = f;
+            W[k] = x;
+        }
+    }
+    free_Tvector(rv1, 0, Columns*Columns - 1);
+}
+
+void svbksb(double *u, double *w, double *v, int m, int n, double *b, double *x)
+{
+    int jj, j, i;
+    double s, *tmp;
+
+    ask_Tvector(tmp, 1, n);
+    for (j = 1;j <= n;j++)
+    {
+        s = 0.0;
+        if (w[j])
+        {
+            for (i = 1;i <= m;i++)
+                s += u[i*n+j] * b[i];
+            s /= w[j];
+        }
+        tmp[j] = s;
+    }
+    for (j = 1;j <= n;j++)
+    {
+        s = 0.0;
+        for (jj = 1;jj <= n;jj++)
+            s += v[j*n+jj] * tmp[jj];
+        x[j] = s;
+    }
+    free_Tvector(tmp, 1, n);
+}
+
+
+/* Gamma function ---------------------------------------------------------- */
+#define ITMAX 100
+#define EPS 3.0e-7
+
+void gser(double *gamser, double a, double x, double *gln)
+{
+    int n;
+    double sum, del, ap;
+
+    *gln = gammln(a);
+    if (x <= 0.0)
+    {
+        if (x < 0.0)
+            nrerror("x less than 0 in routine gser");
+        *gamser = 0.0;
+        return;
+    }
+    else
+    {
+        ap = a;
+        del = sum = 1.0 / a;
+        for (n = 1;n <= ITMAX;n++)
+        {
+            ++ap;
+            del *= x / ap;
+            sum += del;
+            if (fabs(del) < fabs(sum)*EPS)
+            {
+                *gamser = sum * exp(-x + a * log(x) - (*gln));
+                return;
+            }
+        }
+        nrerror("a too large, ITMAX too small in routine gser");
+        return;
+    }
+}
+#undef ITMAX
+#undef EPS
+
+#define ITMAX 100
+#define EPS 3.0e-7
+#define FPMIN 1.0e-30
+
+void gcf(double *gammcf, double a, double x, double *gln)
+{
+    int i;
+    double an, b, c, d, del, h;
+
+    *gln = gammln(a);
+    b = x + 1.0 - a;
+    c = 1.0 / FPMIN;
+    d = 1.0 / b;
+    h = d;
+    for (i = 1;i <= ITMAX;i++)
+    {
+        an = -i * (i - a);
+        b += 2.0;
+        d = an * d + b;
+        if (fabs(d) < FPMIN)
+            d = FPMIN;
+        c = b + an / c;
+        if (fabs(c) < FPMIN)
+            c = FPMIN;
+        d = 1.0 / d;
+        del = d * c;
+        h *= del;
+        if (fabs(del - 1.0) < EPS)
+            break;
+    }
+    if (i > ITMAX)
+        nrerror("a too large, ITMAX too small in gcf");
+    *gammcf = exp(-x + a * log(x) - (*gln)) * h;
+}
+#undef ITMAX
+#undef EPS
+#undef FPMIN
+
+double gammp(double a, double x)
+{
+    double gamser, gammcf, gln;
+
+    if (x < 0.0 || a <= 0.0)
+        nrerror("Invalid arguments in routine gammp");
+    if (x < (a + 1.0))
+    {
+        gser(&gamser, a, x, &gln);
+        return gamser;
+    }
+    else
+    {
+        gcf(&gammcf, a, x, &gln);
+        return 1.0 -gammcf;
+    }
+}
diff --git a/src/numerical_recipes.h b/src/numerical_recipes.h
new file mode 100644
index 0000000..21b3f40
--- /dev/null
+++ b/src/numerical_recipes.h
@@ -0,0 +1,273 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+#ifndef _NUMERICAL_HH
+#   define _NUMERICAL_HH
+
+#include <math.h>
+#include "src/memory.h"
+#include "src/macros.h"
+#include "src/error.h"
+
+/*****************************************************************************/
+/* Variable and prototype definitions for the Numerical Core                 */
+/*****************************************************************************/
+
+//@defgroup NumericalRecipes Functions from the Numerical Recipes
+//@ingroup DataLibrary
+//@{
+
+// Utilities --------------------------------------------------------------
+void nrerror(const char error_text[]);
+
+// Random numbers ---------------------------------------------------------
+double ran1(int *idum);                                 // Uniform random
+double gasdev(int *idum);                               // Gaussian random
+double tdev(double nu, int *idum);                      // t-student random
+
+// Bessel functions --------------------------------------------------------
+double bessj0(double x);
+double bessj3_5(double x);
+double bessj1_5(double x);
+
+double bessi0(double x);
+double bessi1(double x);
+double bessi0_5(double x);
+double bessi1_5(double x);
+double bessi2(double x);
+double bessi3(double x);
+double bessi2_5(double x);
+double bessi3_5(double x);
+double bessi4(double x);
+
+// Special functions -------------------------------------------------------
+double gammln(double xx);
+double gammp(double a, double x);
+double betacf(double a, double b, double x);
+double betai(double a, double b, double x);
+
+// Singular value descomposition of matrix a (numerical recipes, chapter 2-6 for details)
+void svdcmp(double *a, int m, int n, double *w, double *v);
+void svbksb(double *u, double *w, double *v, int m, int n, double *b, double *x);
+
+// Optimization ------------------------------------------------------------
+void powell(double *p, double *xi, int n, double ftol, int &iter,
+            double &fret, double(*func)(double *, void *), void *prm,
+            bool show);
+
+// Working with matrices ---------------------------------------------------
+// LU decomposition
+#define TINY 1.0e-20;
+/* Chapter 2 Section 3: LU DECOMPOSITION */
+template <class T>
+void ludcmp(T *a, int n, int *indx, T *d)
+{
+    int i, imax, j, k;
+    T big, dum, sum, temp;
+    T *vv;
+
+    ask_Tvector(vv, 1, n);
+    *d = (T)1.0;
+    for (i = 1;i <= n;i++)
+    {
+        big = (T)0.0;
+        for (j = 1;j <= n;j++)
+            if ((temp = (T)fabs((double)a[i*n+j])) > big)
+                big = temp;
+        if (big == (T)0.0)
+            nrerror("Singular matrix in routine LUDCMP");
+        vv[i] = (T)1.0 / big;
+    }
+    for (j = 1;j <= n;j++)
+    {
+        for (i = 1;i < j;i++)
+        {
+            sum = a[i*n+j];
+            for (k = 1;k < i;k++)
+                sum -= a[i*n+k] * a[k*n+j];
+            a[i*n+j] = sum;
+        }
+        big = (T)0.0;
+        for (i = j;i <= n;i++)
+        {
+            sum = a[i*n+j];
+            for (k = 1;k < j;k++)
+                sum -= a[i*n+k] * a[k*n+j];
+            a[i*n+j] = sum;
+            if ((dum = vv[i] * (T)fabs((double)sum)) >= big)
+            {
+                big = dum;
+                imax = i;
+            }
+        }
+        if (j != imax)
+        {
+            for (k = 1;k <= n;k++)
+            {
+                dum = a[imax*n+k];
+                a[imax*n+k] = a[j*n+k];
+                a[j*n+k] = dum;
+            }
+            *d = -(*d);
+            vv[imax] = vv[j];
+        }
+        indx[j] = imax;
+        if (a[j*n+j] == 0.0)
+            a[j*n+j] = (T) TINY;
+        if (j != n)
+        {
+            dum = (T)1.0 / (a[j*n+j]);
+            for (i = j + 1;i <= n;i++)
+                a[i*n+j] *= dum;
+        }
+    }
+    free_Tvector(vv, 1, n);
+}
+#undef TINY
+
+// Solve Ax=b
+/* Chapter 2 Section 3: LU BACKWARD-FORWARD SUBSTITUTION */
+template <class T>
+void lubksb(T *a, int n, int *indx, T b[])
+{
+    int i, ii = 0, ip, j;
+    T sum;
+
+    for (i = 1;i <= n;i++)
+    {
+        ip = indx[i];
+        sum = b[ip];
+        b[ip] = b[i];
+        if (ii)
+            for (j = ii;j <= i - 1;j++)
+                sum -= a[i*n+j] * b[j];
+        else if (sum)
+            ii = i;
+        b[i] = sum;
+    }
+    for (i = n;i >= 1;i--)
+    {
+        sum = b[i];
+        for (j = i + 1;j <= n;j++)
+            sum -= a[i*n+j] * b[j];
+        b[i] = sum / a[i*n+i];
+    }
+}
+
+/* Chapter 2, Section 1. Gauss-Jordan equation system resolution ----------- */
+// Solve Ax=b (b=matrix)
+template <class T>
+void gaussj(T *a, int n, T *b, int m)
+{
+    T temp;
+    int *indxc, *indxr, *ipiv;
+    int i, icol, irow, j, k, l, ll;
+    T big, dum;
+    double pivinv;
+
+    ask_Tvector(indxc, 1, n);
+    ask_Tvector(indxr, 1, n);
+    ask_Tvector(ipiv, 1, n);
+    for (j = 1;j <= n;j++)
+        ipiv[j] = 0;
+    for (i = 1;i <= n;i++)
+    {
+        big = (T)0;
+        for (j = 1;j <= n;j++)
+            if (ipiv[j] != 1)
+                for (k = 1;k <= n;k++)
+                {
+                    if (ipiv[k] == 0)
+                    {
+                        if (fabs((double)a[j*n+k]) >= (double) big)
+                        {
+                            big = ABS(a[j*n+k]);
+                            irow = j;
+                            icol = k;
+                        }
+                    }
+                    else if (ipiv[k] > 1)
+                        nrerror("GAUSSJ: Singular Matrix-1");
+                }
+        ++(ipiv[icol]);
+        if (irow != icol)
+        {
+            for (l = 1;l <= n;l++)
+                SWAP(a[irow*n+l], a[icol*n+l], temp)
+                for (l = 1;l <= m;l++)
+                    SWAP(b[irow*n+l], b[icol*n+l], temp)
+                }
+        indxr[i] = irow;
+        indxc[i] = icol;
+        if (a[icol*n+icol] == 0.0)
+            nrerror("GAUSSJ: Singular Matrix-2");
+        pivinv = 1.0f / a[icol*n+icol];
+        a[icol*n+icol] = (T)1;
+        for (l = 1;l <= n;l++)
+            a[icol*n+l] = (T)(pivinv * a[icol*n+l]);
+        for (l = 1;l <= m;l++)
+            b[icol*n+l] = (T)(pivinv * b[icol*n+l]);
+        for (ll = 1;ll <= n;ll++)
+            if (ll != icol)
+            {
+                dum = a[ll*n+icol];
+                a[ll*n+icol] = (T)0;
+                for (l = 1;l <= n;l++)
+                    a[ll*n+l] -= a[icol*n+l] * dum;
+                for (l = 1;l <= m;l++)
+                    b[ll*n+l] -= b[icol*n+l] * dum;
+            }
+    }
+    for (l = n;l >= 1;l--)
+    {
+        if (indxr[l] != indxc[l])
+            for (k = 1;k <= n;k++)
+                SWAP(a[k*n+indxr[l]], a[k*n+indxc[l]], temp);
+    }
+    free_Tvector(ipiv, 1, n);
+    free_Tvector(indxr, 1, n);
+    free_Tvector(indxc, 1, n);
+}
+
+
+#endif
diff --git a/src/parallel.cpp b/src/parallel.cpp
new file mode 100644
index 0000000..62ce9a9
--- /dev/null
+++ b/src/parallel.cpp
@@ -0,0 +1,339 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     J.M. De la Rosa Trevin (jmdelarosa at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+#include "src/parallel.h"
+
+
+// ================= MUTEX ==========================
+Mutex::Mutex()
+{
+    pthread_mutex_init(&mutex, NULL);
+}
+
+void Mutex::lock()
+{
+    pthread_mutex_lock(&mutex);
+}
+
+Mutex::~Mutex()
+{
+    pthread_mutex_destroy(&mutex);
+}
+
+void Mutex::unlock()
+{
+    pthread_mutex_unlock(&mutex);
+}
+
+// ================= BARRIER ==========================
+Barrier::Barrier(int numberOfThreads)
+{
+    needed = numberOfThreads + 1;
+    called = 0;
+    pthread_mutex_init(&mutex, NULL);
+    pthread_cond_init(&cond, NULL);
+}
+
+Barrier::~Barrier()
+{
+    pthread_mutex_destroy(&mutex);
+    pthread_cond_destroy(&cond);
+}
+
+void Barrier::wait()
+{
+    pthread_mutex_lock(&mutex);
+    ++called;
+    if (called == needed)
+    {
+        called = 0;
+        pthread_cond_broadcast(&cond);
+    }
+    else
+    {
+        pthread_cond_wait(&cond, &mutex);
+    }
+    pthread_mutex_unlock(&mutex);
+}
+
+// ================= THREAD MANAGER =======================
+
+ThreadArgument::ThreadArgument()
+{
+    thread_id = -1;
+    manager = NULL;
+    data = NULL;
+}
+
+ThreadArgument::ThreadArgument(int id, ThreadManager * manager, void * data)
+{
+    this->thread_id = id;
+    this->manager = manager;
+    this->data = data;
+}
+
+void * _threadMain(void * data)
+{
+    ThreadArgument * thArg = (ThreadArgument*) data;
+    ThreadManager * thMgr = thArg->manager;
+
+    while (true)
+    {
+        //Wait for start working or leave
+        thMgr->wait();
+        //After awaked check what to do
+        if (thMgr->workFunction != NULL)
+        {
+        	try
+        	{
+        		thMgr->workFunction(*thArg);
+        		thMgr->wait(); //wait for finish together
+        	}
+        	catch (RelionError XE)
+        	{
+        		std::cerr << XE << std::endl
+        		          << "In thread " << thArg->thread_id << std::endl;
+        		pthread_exit(NULL);
+        	}
+        }
+        else //exit thread
+        {
+            pthread_exit(NULL);
+        }
+    }
+}
+
+ThreadManager::ThreadManager(int numberOfThreads, void * workClass)
+{
+    threads = numberOfThreads;
+    barrier = new Barrier(threads);
+    workFunction = NULL;
+    ids = new pthread_t[threads];
+    arguments = new ThreadArgument[threads];
+    started = false;
+    this->workClass = workClass;
+
+}
+
+void ThreadManager::startThreads()
+{
+    //Create threads
+    int result;
+
+    for (int i = 0; i < threads; ++i)
+    {
+        arguments[i].thread_id = i;
+        arguments[i].manager = this;
+        arguments[i].data = NULL;
+        arguments[i].workClass = workClass;
+
+#ifdef DEBUG_THREADS
+        std::cerr << " startThreads: i= " << i << std::endl;
+#endif
+        result = pthread_create(ids + i, NULL, _threadMain, (void*) (arguments + i));
+
+        if (result != 0)
+        {
+            std::cerr << "ThreadManager: can't create threads." << std::endl;
+            exit(1);
+        }
+    }
+    started = true;
+}
+
+ThreadManager::~ThreadManager()
+{
+    //Destroy the threads
+    workFunction = NULL;
+    if (started)
+    {
+        wait();
+        for (int i = 0; i < threads; ++i)
+        	pthread_join(ids[i], NULL);
+    }
+
+    delete barrier;
+    delete[] ids;
+    delete[] arguments;
+}
+
+void ThreadManager::run(ThreadFunction function)
+{
+	runAsync(function);
+    //Wait on barrier to wait for threads finish
+    wait();
+}
+
+void ThreadManager::runAsync(ThreadFunction function)
+{
+    workFunction = function;
+    if (!started)
+        startThreads();
+    //Wait on barrier to threads starts working
+    wait();
+}
+
+void ThreadManager::wait()
+{
+    barrier->wait();
+}
+
+// =================== TASK_DISTRIBUTOR ============================
+
+ParallelTaskDistributor::ParallelTaskDistributor(size_t nTasks, size_t bSize)
+{
+
+	resize(nTasks, bSize);
+}
+
+void ParallelTaskDistributor::resize(size_t nTasks, size_t bSize)
+{
+	if (!(nTasks && bSize && bSize <= nTasks))
+	{
+		std::cerr << " nTasks= " << nTasks << " bSize= " << bSize << std::endl;
+		REPORT_ERROR("nTasks and bSize should be > 0, also bSize <= nTasks");
+	}
+
+	numberOfTasks = nTasks;
+	blockSize = bSize;
+	assignedTasks = 0;
+}
+
+void ParallelTaskDistributor::reset()
+{
+    lock();
+    assignedTasks = 0;
+    unlock();
+}
+
+void ParallelTaskDistributor::setBlockSize(size_t bSize)
+{
+    lock();
+    blockSize = bSize;
+    unlock();
+}
+
+int ParallelTaskDistributor::getBlockSize() const
+{
+    return blockSize;
+}
+
+bool ParallelTaskDistributor::getTasks(size_t &first, size_t &last)
+{
+    lock();
+    bool result = distribute(first, last);
+    unlock();
+    return result;
+}
+
+bool ParallelTaskDistributor::setAssignedTasks(size_t tasks)
+{
+    if (tasks < 0 || tasks >= numberOfTasks)
+        return false;
+    lock();
+    assignedTasks = tasks;
+    unlock();
+    return true;
+}
+
+void ThreadTaskDistributor::lock()
+{
+    mutex.lock();
+}
+
+void ThreadTaskDistributor::unlock()
+{
+    mutex.unlock();
+}
+
+bool ThreadTaskDistributor::distribute(size_t &first, size_t &last)
+{
+    bool result = true;
+    first = last = 0;
+    if (assignedTasks >= numberOfTasks)
+    {
+        result = false;
+    }
+    else
+    {
+        first = assignedTasks;
+        assignedTasks
+        = (assignedTasks + blockSize < numberOfTasks) ? (assignedTasks
+                + blockSize) : numberOfTasks;
+        last = assignedTasks - 1;
+    }
+    return result;
+}
+
+
+/** Divides a number into most equally groups */
+long int divide_equally(long int N, int size, int rank, long int &first, long int &last)
+{
+    long int jobs_per_worker = N / size;
+    long int jobs_resting = N % size;
+    if (rank < jobs_resting)
+    {
+        first = rank * (jobs_per_worker + 1);
+        last = first + jobs_per_worker;
+    }
+    else
+    {
+        first = rank * jobs_per_worker + jobs_resting;
+        last = first + jobs_per_worker - 1;
+    }
+    return last - first + 1;
+}
+
+/** In which group from divide_equally is myself? */
+int divide_equally_which_group(long int N, int size, long int myself)
+{
+    long int first, last;
+    for (int rank = 0; rank < size; rank++)
+    {
+        divide_equally(N, size, rank, first, last);
+        if (myself >= first && myself <= last)
+            return rank;
+    }
+    return -1;
+}
+
diff --git a/src/parallel.h b/src/parallel.h
new file mode 100644
index 0000000..fadfb0e
--- /dev/null
+++ b/src/parallel.h
@@ -0,0 +1,401 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     J.M. De la Rosa Trevin (jmdelarosa at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+#ifndef __PARALLEL_H
+#define __PARALLEL_H
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "src/error.h"
+
+// This code was copied from a developmental version of Xmipp-3.0
+// which is developed at the Biocomputing Unit of the National Center for Biotechnology - CSIC
+// in Madrid , Spain
+
+
+class ThreadManager;
+class ThreadArgument;
+
+/* Prototype of functions for threads works. */
+typedef void (*ThreadFunction) (ThreadArgument &arg);
+
+/** Class wrapping around the pthreads mutex.
+ * This class will provide a more object oriented implementation
+ * of a mutex, to ensure the unique access to critical regions of
+ * code and other syncronization problems.
+ */
+class Mutex
+{
+private:
+    pthread_mutex_t mutex; //our pthread mutex
+
+public:
+    /** Default constructor.
+     * This constructor just initialize the pthread_mutex_t structure
+     * with its defaults values, just like static initialization with PTHREAD_MUTEX_INITIALIZER
+     */
+    Mutex();
+
+    /** Destructor. */
+    virtual ~Mutex();
+
+    /** Function to get the access to the mutex.
+     * If some thread has the mutex and an other one
+     * asks to lock it, it will be waiting until the first one
+     * releases the mutex
+     */
+    virtual void lock();
+
+    /** Function to release the mutex.
+     * This allows access to the mutex to other
+     * threads that are waiting for it.
+     */
+    virtual void unlock();
+};//end of class Mutex
+
+/** Class to synchronize several threads in some point of execution.
+ * Threads is a way of distributing workload across
+ * different workers to solve a problem faster. Nevertheless, sometimes
+ * we need synchronization between threads to avoid undesired race
+ * conditions and other problems. Here we are an implementation of a barrier
+ * that allows putting all threads to wait at a given point until all of them
+ * have reached such point and can continue working. Barriers are usually
+ * available through pthreads system library. Nonetheless, sometimes it is not
+ * so we have to implement it here.
+ * @code
+ * Mutex mutex;
+ *
+ * //Then in each thread to access the critical section:
+ *  mutex.lock();
+ *  //...Do critical section stuff
+ *  mutex.unlock();
+ *
+   @endcode
+ */
+class Barrier
+{
+
+private:
+    int needed; ///< How many threads should arrive to meet point
+    int called; ///< How many threads already arrived
+    pthread_mutex_t mutex; ///< Mutex to update structure
+    pthread_cond_t cond; ///< Condition on which the threads are waiting
+
+public:
+    /** Constructor of the barrier to initialize the object.
+     * You should pass the number of working threads that
+     * you want to wait on the barrier. The internal counter
+     * of the barrier will be initialized with numberOfThreads + 1
+     * taking into account the main thread, so it need to wait
+     * also in the barrier with the worker threads to all
+     * can move on.
+     * @code
+     *  //For syncronize 10 threads created by a main thread
+     *  //you can create the barrier from the main thread
+     *  Barrier * barrier = new Barrier(10);
+     *  //...
+     *  //In the syncronization point
+     *  barrier->wait();
+     * @endcode
+     * */
+    Barrier(int numberOfThreads);
+
+    /** Destructor to free all memory used */
+    ~Barrier();
+
+    /** Request to wait in this meet point.
+     * For each thread calling this function the execution will
+     * be paused untill all threads arrive this point.
+     */
+    void wait();
+
+};//end of class Barrier
+
+/** Class to pass arguments to threads functions.
+ * The argument passed can be obtained casting
+ * the void * data received in the function.
+ * @see ThreadManager
+ */
+class ThreadArgument
+{
+private:
+    ThreadManager * manager;
+public:
+    int thread_id; ///< The thread id
+    void * workClass; ///< The class in which threads will be working
+    void * data;
+
+    ThreadArgument();
+    ThreadArgument(int id, ThreadManager * manager = NULL, void * data = NULL);
+
+    friend class ThreadManager;
+    friend void * _threadMain(void * data);
+};
+
+void * _threadMain(void * data);
+
+/** Class for manage a group of threads performing one or several tasks.
+ * This class is very useful when we have some function that can be executed
+ * in parrallel by threads. The threads are created in the contructor of the object
+ * and released in destructor. This way threads can execute different
+ * functions at diffent moments and exit at the end of manager life. Also, the
+ * wait() function allow in the main thread to wait until all threads have
+ * finish working on a task and maybe then execute another one.
+ * This class is supposed to be used only in the main thread.
+ */
+class ThreadManager
+{
+private:
+    int threads; ///< number of working threads.
+    pthread_t * ids; ///< pthreads identifiers
+    ThreadArgument * arguments; ///< Arguments passed to threads
+    Barrier * barrier; ///< barrier for syncronized between tasks.
+    /// Pointer to the function to work on,
+    /// if null threads should exit
+    ThreadFunction workFunction;
+    bool started;
+    void * workClass;
+
+    void startThreads();
+
+public:
+    /** Constructor, number of working threads should be supplied */
+    ThreadManager(int numberOfThreads, void * workClass = NULL);
+
+    /** Destructor, free memory and exit threads */
+    ~ThreadManager();
+
+    /** Function to start working in a task.
+     * The function that want to be executed in parallel
+     * by the working threads should be passed as argument.
+     * Functions that can be executed by thread should by of the
+     * type ThreadFunction, i.e., return void * and only
+     * one argument of type ThreadArgument.
+     * The call of this function will block the main thread
+     * until all workers finish their job, if you dont want to block
+     * use runAsync instead, and later can call wait for waiting
+     * until threads are done.
+     * @code
+     *
+     *  //Global variables, so it are visible in 'processSeveralImages()'
+     *  ParallelTaskDistributor * td;
+     *  //function to perform some operation
+     *  //to N images executed in parellel
+     *  void * processImages(ThreadArgument & data)
+     *  {
+     *      int thread_id = arg.thread_id;
+     *
+     *      size_t firstImage, lastImage;
+     *      while (td->getTasks(firstImage, lastImage))
+     *          for (int image = firstImage; image <= lastImage; ++image)
+     *          {
+     *              //...
+     *              processOneImage(image);
+     *              //...
+     *          }
+     *  }
+     *
+     *  int main()
+     *  {
+     *  //...
+     *  //Distribute 1000 tasks in blocks of 100.
+     *  td = new ThreadTaskDistributor(1000, 100);
+     *  //Start 2 threads to work on it
+     *  ThreadManager * tm = new ThreadManager(2);
+     *  tm.run(processImages);
+     *  //...
+     *  //Same threads can work in other function
+     *  tm.run(processVolumes);
+     *  }
+     * @endcode
+     */
+    void run(ThreadFunction function);
+
+    /** Same as run but without blocking. */
+    void runAsync(ThreadFunction function);
+
+    /** Function that should be called to wait until all threads finished work */
+    void wait();
+
+    /** function to start running the threads.
+     * Should be external and declared as friend */
+    friend void * _threadMain(void * data);
+
+
+}
+;//end of class ThreadManager
+
+/** This class distributes dynamically N tasks between parallel workers.
+ * @ingroup ParallelLibrary
+ * This class is a generalization of a common task in a parallel
+ * environment of dynamically distribute N tasks between workers(threads or mpi proccess).
+ * Each worker will ask for a group of tasks, proccess it and ask for more tasks
+ * until there is not more task to process.
+ *
+ * This class is abstract and only serves as base for
+ * concrete implementations, which will provides the
+ * specific lock mechanisms and the way of distribution.
+ */
+class ParallelTaskDistributor
+{
+//protected:
+public:
+    //How many tasks give in each request
+    size_t blockSize;
+    //The number of tasks that have been assigned
+    size_t assignedTasks;
+
+public:
+    //The total number of tasks to be distributed
+    size_t numberOfTasks;
+    /** Constructor.
+     * The number of jobs and block size should be provided.
+     */
+    ParallelTaskDistributor(size_t nTasks, size_t bSize);
+
+    /* Resets the size of the task distributor
+     */
+    virtual void resize(size_t nTasks, size_t bSize);
+
+    /** Destructor.
+     */
+    virtual ~ParallelTaskDistributor()
+    {}
+    ;
+
+    /** Restart the number of assigned tasks and distribution again. (Resets assignedTasks = 0)
+     * This method should only be called in the main thread
+     * before start distributing the tasks between the workers
+     * threads.
+     */
+    void reset();
+
+    /** Set the number of tasks assigned in each request */
+    void setBlockSize(size_t bSize);
+
+    /** Return the number of tasks assigned in each request */
+    int getBlockSize() const;
+
+    /** Gets parallel tasks.
+     *  @ingroup ParallelJobHandler
+     *  This function will be called by workers for asking tasks
+     *  until there are not more tasks to process.
+     *  Example:
+     *  @code
+     *  //...
+     *  ParallelTaskDistributor * td = new ThreadTaskDistributor(1000, 100);
+     *  //...
+     *  //function to perform some operation
+     *  //to N images executed in parellel
+     *  void processSeveralImages()
+     *  {
+     *      size_t firstImage, lastImage;
+     *      while (td->getTasks(firstImage, lastImage))
+     *          for (size_t image = firstImage; image <= lastImage; ++image)
+     *          {
+     *              //...
+     *              processOneImage(image);
+     *              //...
+     *          }
+     *  }
+     *  @endcode
+     */
+    bool getTasks(size_t &first, size_t &last); // False = no more jobs, true = more jobs
+    /* This function set the number of completed tasks.
+     * Usually this not need to be called. Its more useful
+     * for restarting work, when usually the master detect
+     * the number of tasks already done.
+     */
+    bool setAssignedTasks(size_t tasks);
+
+
+protected:
+    //Virtual functions that should be implemented in
+    //subclasses, providing a mechanism of lock and
+    //the specific way of distribute tasks.
+    virtual void lock() = 0;
+    virtual void unlock() = 0;
+    virtual bool distribute(size_t &first, size_t &last) = 0;
+
+};//class ParallelTaskDistributor
+
+/** This class is a concrete implementation of ParallelTaskDistributor for POSIX threads.
+ * It uses mutex as the locking mechanism
+ * and distributes tasks from 0 to numberOfTasks.
+ */
+class ThreadTaskDistributor: public ParallelTaskDistributor
+{
+
+public:
+
+	ThreadTaskDistributor(size_t nTasks, size_t bSize):ParallelTaskDistributor(nTasks, bSize) {}
+    virtual ~ThreadTaskDistributor(){};
+
+protected:
+    Mutex mutex; ///< Mutex to syncronize access to critical region
+    virtual void lock();
+    virtual void unlock();
+    virtual bool distribute(size_t &first, size_t &last);
+};//end of class ThreadTaskDistributor
+
+
+/// @name Miscellaneous functions
+//@{
+/** Divides a number into most equally groups
+ *
+ * For example you want to distribute N jobs between M workers
+ * so each worker will have N/M jobs and some of them(N % M first)
+ * will have N/M + 1 jobs
+ * So for the worker 'rank' will be computed the first and last job to do
+ * Return the number of jobs assigned, that could be N/M + 1 or N/M
+ *
+ */
+long int divide_equally(long int N, int size, int rank, long int &first, long int &last);
+
+/** In which group (of divide_equally) is myself situated?
+ */
+int divide_equally_which_group(long int N, int size, long int myself);
+
+
+#endif
diff --git a/src/particle_polisher.cpp b/src/particle_polisher.cpp
new file mode 100644
index 0000000..0a97a71
--- /dev/null
+++ b/src/particle_polisher.cpp
@@ -0,0 +1,1616 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include "src/particle_polisher.h"
+//#define DEBUG_TILT
+
+void ParticlePolisher::read(int argc, char **argv)
+{
+
+	parser.setCommandLine(argc, argv);
+	int gen_section = parser.addSection("General options");
+	fn_in = parser.getOption("--i", "STAR file with the aligned movie frames, e.g. run1_ct25_data.star");
+	fn_out = parser.getOption("--o", "Output rootname", "shiny");
+	angpix = textToFloat(parser.getOption("--angpix", "Pixel size (in Angstroms)", "1"));
+	running_average_width = textToInteger(parser.getOption("--movie_frames_running_avg", "Number of movie frames in each running average", "5"));
+	do_start_all_over = parser.checkOption("--dont_read_old_files", "Do not read intermediate results from disc, but re-do all calculations from scratch");
+
+	int fit_section = parser.addSection("Beam-induced movement fitting options");
+	sigma_neighbour_distance = textToFloat(parser.getOption("--sigma_nb", "Standard deviation for a Gaussian weight on the particle distance", "100."));
+	if (parser.checkOption("--log_fit",       "Fit line on a logarithmic time-scale      (default=linear fit)"))
+		fitting_mode = LOGARITHMIC_FIT;
+	else if (parser.checkOption("--sqrt_fit", "Fit line on a square-root time-scale      (default=linear fit)"))
+		fitting_mode = SQRT_FIT;
+	else if (parser.checkOption("--no_fit",   "Do not fit any function through movements (default=linear fit)"))
+		fitting_mode = NO_FIT;
+	else
+		fitting_mode = LINEAR_FIT;
+
+	int post_section = parser.addSection("Per-frame B-factor estimation options");
+	do_weighting = !parser.checkOption("--skip_bfactor_weighting", "Don't perform B-factor weighting");
+	frame_running_average = textToInteger(parser.getOption("--bfactor_running_avg", "Number of movie frames to join in B-factor determination", "1"));
+	perframe_highres = textToFloat(parser.getOption("--perframe_highres", "Highest resolution (in A) to include in the per-frame reconstructions", "-1."));
+	fit_minres = textToFloat(parser.getOption("--autob_lowres", "Lowest resolution (in A) to include in fitting of the B-factor", "20."));
+	fn_sym = parser.getOption("--sym", "Symmetry group", "c1");
+	fn_mask = parser.getOption("--mask", "Postprocessing mask for B-factor determination of per-frame reconstructions (1=protein, 0=solvent, all values in range [0,1])", "");
+
+	int ctf_section = parser.addSection("CTF options");
+   	do_ctf = !parser.checkOption("--no_ctf", "Don't apply CTF correction");
+	intact_ctf_first_peak = parser.checkOption("--ctf_intact_first_peak", "Leave CTFs intact until first peak");
+	ctf_phase_flipped = parser.checkOption("--ctf_phase_flipped", "Images have been phase flipped");
+	only_flip_phases = parser.checkOption("--only_flip_phases", "Do not correct CTF-amplitudes, only flip phases");
+	defocus_shift_max = textToFloat(parser.getOption("--defocus_shift_max", "Maximum shift in defocus (in A) to search for each particle", "0"));
+	defocus_shift_step = textToFloat(parser.getOption("--defocus_shift_step", "Maximum shift in defocus (in A) to search for each particle", "100"));
+
+	int norm_section = parser.addSection("Normalisation options");
+	do_normalise = !parser.checkOption("--skip_normalise", "Do not normalise the polsihed particles?");
+	bg_radius =  textToInteger(parser.getOption("--bg_radius", "Radius of the circular mask that will be used to define the background area (in pixels)", "-1"));
+	white_dust_stddev = textToFloat(parser.getOption("--white_dust", "Sigma-values above which white dust will be removed (negative value means no dust removal)","-1"));
+	black_dust_stddev = textToFloat(parser.getOption("--black_dust", "Sigma-values above which black dust will be removed (negative value means no dust removal)","-1"));
+
+	int beamtilt_section = parser.addSection("Beamtilt refinement options");
+	beamtilt_max = textToFloat(parser.getOption("--beamtilt_max", "Maximum beamtilt (in mrad) to search", "0."));
+	beamtilt_step = textToFloat(parser.getOption("--beamtilt_step", "Step-size for beamtilt searches (in mrad)", "0.2"));
+	minres_beamtilt = textToFloat(parser.getOption("--minres_beamtilt", "Lowest resolution to include in beam-tilt correction (in A)", "6"));
+
+	int out_section = parser.addSection("Polished particles output options");
+	first_frame = textToInteger(parser.getOption("--first_frame", "First frame to include in the polished particles", "1"));
+	last_frame = textToInteger(parser.getOption("--last_frame", "First frame to include in the polished particles (default is all)", "-1"));
+
+	verb = textToInteger(parser.getOption("--verb", "Verbosity", "1"));
+
+	// Check for errors in the command-line option
+	if (parser.checkForErrors())
+		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+}
+
+void ParticlePolisher::usage()
+{
+	parser.writeUsage(std::cerr);
+}
+
+void ParticlePolisher::initialise()
+{
+    // Fill tabulated sine and cosine tables
+    tab_sin.initialise(5000);
+    tab_cos.initialise(5000);
+
+#ifndef DEBUG_TILT
+    if (verb > 0)
+    	std::cout << " + Reading the input STAR file ... " << std::endl;
+    exp_model.read(fn_in, true); // true means do_ignore_particle_name!!
+
+	// Find out which OriginalParticles come from the same micrograph
+    if (verb > 0)
+    	std::cout << " + Grouping all particles from the same micrographs ... " << std::endl;
+	exp_model.getAverageMicrographs();
+
+	// Pre-size the fitted_movements array (for parallelised output...)
+	int total_nr_images = exp_model.numberOfParticles();
+	fitted_movements.resize(total_nr_images, 2);
+
+	last_frame = (last_frame < 0) ? exp_model.ori_particles[0].particles_id.size() : last_frame;
+	perframe_bfactors.initZeros( 3 * (last_frame - first_frame + 1)); // now store bfactor, offset and corr_coeff
+#endif
+
+	// Get the pixel size from the input STAR file
+	if (exp_model.MDimg.containsLabel(EMDL_CTF_MAGNIFICATION) && exp_model.MDimg.containsLabel(EMDL_CTF_DETECTOR_PIXEL_SIZE))
+	{
+		double mag, dstep;
+		exp_model.MDimg.getValue(EMDL_CTF_MAGNIFICATION, mag);
+		exp_model.MDimg.getValue(EMDL_CTF_DETECTOR_PIXEL_SIZE, dstep);
+		angpix = 10000. * dstep / mag;
+		if (verb > 0)
+			std::cout << " + Using pixel size calculated from magnification and detector pixel size in the input STAR file: " << angpix << std::endl;
+	}
+
+    if (do_weighting)
+    {
+    	// Read in the Imask
+    	Imask.read(fn_mask);
+    	ori_size = XSIZE(Imask());
+    }
+
+	if (do_normalise && bg_radius < 0)
+		REPORT_ERROR("ERROR: please provide a radius for a circle that defines the background area when normalising...");
+
+
+}
+
+// Fit the beam-induced translations for all average micrographs
+void ParticlePolisher::fitMovementsAllMicrographs()
+{
+
+	// Loop over all average micrographs
+	int barstep;
+	int my_nr_micrographs = exp_model.average_micrographs.size();
+	if (verb > 0)
+	{
+		std::cout << " + Fitting straight paths for beam-induced movements in all micrographs ... " << std::endl;
+		init_progress_bar(my_nr_micrographs);
+		barstep = XMIPP_MAX(1, my_nr_micrographs/ 60);
+	}
+
+    for (long int i = 0; i < my_nr_micrographs; i++)
+	{
+    	if (verb > 0 && i % barstep == 0)
+			progress_bar(i);
+
+		fitMovementsOneMicrograph(i);
+	}
+
+    // Set the fitted movements in the xoff and yoff columns of the exp_model.MDimg
+    for (int ipart = 0; ipart < exp_model.numberOfParticles(); ipart++)
+	{
+		long int part_id = exp_model.particles[ipart].id;
+		long int img_id = exp_model.getImageId(part_id, 0);
+		double xoff = DIRECT_A2D_ELEM(fitted_movements, img_id, 0);
+		double yoff = DIRECT_A2D_ELEM(fitted_movements, img_id, 1);
+		exp_model.MDimg.setValue(EMDL_ORIENT_ORIGIN_X, xoff, img_id);
+		exp_model.MDimg.setValue(EMDL_ORIENT_ORIGIN_Y, yoff, img_id);
+	}
+
+    if (verb > 0)
+	{
+		progress_bar(my_nr_micrographs);
+	}
+
+	// Write out the STAR file with all the fitted movements
+	FileName fn_tmp = fn_in.withoutExtension() + "_" + fn_out + ".star";
+	exp_model.MDimg.write(fn_tmp);
+	std::cout << " + Written out all fitted movements in STAR file: " << fn_tmp << std::endl;
+
+
+}
+
+
+
+void ParticlePolisher::fitMovementsOneMicrograph(long int imic)
+{
+
+	std::vector<double> x_pick, y_pick, x_off_prior, y_off_prior, x_start, x_end, dummy; // X and Y-coordinates for the average particles in the micrograph
+	std::vector< std::vector<double> > x_off, y_off; // X and Y shifts w.r.t. the average for each movie frame
+	double x_pick_p, y_pick_p, x_off_p, y_off_p, x_off_prior_p, y_off_prior_p;
+
+
+	// Loop over all original_particles in this average_micrograph
+	// And fill the x_pick, y_;pick, x_off and y_off vectors
+	for (long int ipar = 0; ipar < (exp_model.average_micrographs[imic]).ori_particles_id.size(); ipar++)
+	{
+		long int ori_part_id = exp_model.average_micrographs[imic].ori_particles_id[ipar];
+
+		x_off.push_back(dummy);
+		y_off.push_back(dummy);
+		bool is_first = true;
+		for (long int i_frame = 0; i_frame < exp_model.ori_particles[ori_part_id].particles_id.size(); i_frame++ )
+		{
+			long int part_id = exp_model.ori_particles[ori_part_id].particles_id[i_frame];
+			long int img_id = exp_model.getImageId(part_id, 0);
+
+			exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_X, x_off_p, img_id);
+			exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_Y, y_off_p, img_id);
+			exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_X_PRIOR, x_off_prior_p, img_id);
+			exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_Y_PRIOR, y_off_prior_p, img_id);
+
+			// Store the value of the picked coordinates for the first movie frame
+			if (is_first)
+			{
+				is_first = false;
+				exp_model.MDimg.getValue(EMDL_IMAGE_COORD_X, x_pick_p, img_id);
+				exp_model.MDimg.getValue(EMDL_IMAGE_COORD_X, y_pick_p, img_id);
+				x_pick.push_back(x_pick_p);
+				y_pick.push_back(y_pick_p);
+				x_off_prior.push_back(x_off_prior_p);
+				y_off_prior.push_back(y_off_prior_p);
+			}
+			else
+			{
+				if (ABS(x_off_prior_p - x_off_prior[ipar]) > 0.01 || ABS(y_off_prior_p - y_off_prior[ipar]) > 0.01)
+					REPORT_ERROR("ParticlePolisher::processFramesOneMicrograph ERROR: unequal priors on x and y for different movie frames!");
+			}
+
+			// Store the offsets for all movie frames, relative to the prior (to get the movements of the frames)
+			x_off[ipar].push_back(x_off_p);
+			y_off[ipar].push_back(y_off_p);
+		}
+	}
+
+	// Now do the actual fitting
+	double gauss_const = 1. / sqrt(2 * PI * sigma_neighbour_distance * sigma_neighbour_distance);
+	double min2sigma2 = - 2. * sigma_neighbour_distance * sigma_neighbour_distance;
+	// Loop over all ori_particles
+	for (long int ipar = 0; ipar < (exp_model.average_micrographs[imic]).ori_particles_id.size(); ipar++)
+	{
+		long int ori_part_id = exp_model.average_micrographs[imic].ori_particles_id[ipar];
+
+		double my_pick_x = x_pick[ipar] + x_off_prior[ipar];
+		double my_pick_y = y_pick[ipar] + y_off_prior[ipar];
+
+		fit_point2D      onepoint;
+		std::vector<fit_point2D> points_x, points_y;
+
+		// Loop over all other ori_particles on this micrograph and determine weight for contribution to this ori_particle
+		for (long int ii = 0; ii < x_pick.size(); ii++)
+		{
+
+			double nb_pick_x = x_pick[ii] + x_off_prior[ii]; // add prior to center at average position
+			double nb_pick_y = y_pick[ii] + y_off_prior[ii]; // add prior to center at average position
+			double dist2 = (nb_pick_x - my_pick_x) * (nb_pick_x - my_pick_x) + (nb_pick_y - my_pick_y) * (nb_pick_y - my_pick_y);
+			double weight;
+			if (ABS(min2sigma2) < 0.01)
+				weight = (dist2 < 0.01) ? 1. : 0.;
+			else
+				weight = gauss_const * exp(dist2 / min2sigma2);
+
+			if (weight > 0.00001) // ignore very small weights
+			{
+				int first_frame_fit = running_average_width / 2;
+				int last_frame_fit = x_off[ii].size() - (running_average_width / 2);
+				// only fit using those frames that contribute fully to the running average, i.e. exclude the first and last few frames...
+				for (long int i_frame = first_frame_fit; i_frame < last_frame_fit; i_frame++)
+				{
+					if (fitting_mode == LINEAR_FIT)
+						onepoint.x = i_frame + 1; // linear movement with time.... that may not be true!
+					else if (fitting_mode == LOGARITHMIC_FIT)
+						onepoint.x = log(i_frame + 1); // logarithmic movement with time: better?!
+					else if (fitting_mode == SQRT_FIT)
+						onepoint.x = sqrt(i_frame + 1); // logarithmic movement with time: better?!
+					onepoint.w = weight;
+					onepoint.y = x_off[ii][i_frame] - x_off_prior[ii]; // subtract prior to center movement of average position
+					points_x.push_back(onepoint);
+					onepoint.y = y_off[ii][i_frame] - y_off_prior[ii]; // subtract prior to center movement of average position
+					points_y.push_back(onepoint);
+				}
+			}
+		}
+
+		double slope_x, intercept_x, ccf_x;
+		double slope_y, intercept_y, ccf_y;
+		fitStraightLine(points_x, slope_x, intercept_x, ccf_x);
+		fitStraightLine(points_y, slope_y, intercept_y, ccf_y);
+
+		// Now set the interpolated values
+		// Do this for all frames! (whereas fitting was done with excluding the running_average_width halves from both ends)
+		// Rather than setting them straight back into the exp_model.MDimg, use the fitted_movements array
+		// In the parallel version, this will be required for gathering the results from all nodes
+		for (long int i_frame = 0; i_frame < x_off[ipar].size(); i_frame++)
+		{
+			if (fitting_mode == LINEAR_FIT)
+			{
+				x_off_p = slope_x * (i_frame + 1) + intercept_x;
+				y_off_p = slope_y * (i_frame + 1) + intercept_y;
+			}
+			else if (fitting_mode == LOGARITHMIC_FIT)
+			{
+				x_off_p = slope_x * log(i_frame + 1) + intercept_x;
+				y_off_p = slope_y * log(i_frame + 1) + intercept_y;
+			}
+			else if (fitting_mode == SQRT_FIT)
+			{
+				x_off_p = slope_x * sqrt(i_frame + 1) + intercept_x;
+				y_off_p = slope_y * sqrt(i_frame + 1) + intercept_y;
+			}
+
+			long int part_id = exp_model.ori_particles[ori_part_id].particles_id[i_frame];
+			long int img_id = exp_model.getImageId(part_id, 0);
+			A2D_ELEM(fitted_movements, img_id, 0) = x_off_p + x_off_prior[ipar];
+			A2D_ELEM(fitted_movements, img_id, 1) = y_off_p + y_off_prior[ipar];
+		}
+	}
+
+}
+
+void ParticlePolisher::calculateAllSingleFrameReconstructionsAndBfactors()
+{
+
+	FileName fn_star = fn_in.withoutExtension() + "_" + fn_out + "_bfactors.star";
+	if (!do_start_all_over && readStarFileBfactors(fn_star))
+	{
+		if (verb > 0)
+			std::cout << " + " << fn_star << " already exists: skipping calculation of per-frame B-factors." <<std::endl;
+		return;
+	}
+
+	double bfactor, offset, corr_coeff;
+
+	// Loop over all frames to be included in the reconstruction
+	int my_nr_frames = last_frame - first_frame + 1;
+	int barstep;
+	if (verb > 0)
+	{
+		std::cout << " + Calculating per-frame reconstructions ... " << std::endl;
+		init_progress_bar(my_nr_frames);
+		barstep = XMIPP_MAX(1, my_nr_frames/ 60);
+	}
+
+    for (long int i = first_frame; i <= last_frame; i++)
+	{
+
+    	calculateSingleFrameReconstruction(i, 1);
+    	calculateSingleFrameReconstruction(i, 2);
+
+    	if (verb > 0 && i % barstep == 0)
+    		progress_bar(i);
+
+	}
+
+    // Also calculate the average of all single-frames for both halves
+    calculateAverageAllSingleFrameReconstructions(1);
+    calculateAverageAllSingleFrameReconstructions(2);
+
+    // Now calculate the FSC between the average of all single-frame reconstructions
+    calculateBfactorSingleFrameReconstruction(-1, bfactor, offset, corr_coeff);
+
+	if (verb > 0)
+	{
+		std::cout << " + Calculating per-frame B-factors and offsets ... " << std::endl;
+		init_progress_bar(my_nr_frames);
+		barstep = XMIPP_MAX(1, my_nr_frames/ 60);
+	}
+    for (long int i = first_frame; i <= last_frame; i++)
+	{
+
+       	calculateBfactorSingleFrameReconstruction(i, bfactor, offset, corr_coeff);
+       	int iframe = i - first_frame;
+       	DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 0) = bfactor;
+       	DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 1) = offset;
+       	DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 2) = corr_coeff;
+
+       	if (verb > 0 && i % barstep == 0)
+    		progress_bar(i);
+	}
+
+
+    if (verb > 0)
+	{
+		progress_bar(my_nr_frames);
+	}
+
+    // Write STAR file
+    writeStarFileBfactors(fn_star);
+
+
+    // Also write a STAR file with the relative contributions of each frame to all frequencies
+    fn_star = fn_in.withoutExtension() + "_" + fn_out + "_relweights.star";
+    writeStarFileRelativeWeights(fn_star);
+
+
+}
+
+bool ParticlePolisher::readStarFileBfactors(FileName fn_star)
+{
+	if (exists(fn_star))
+	{
+		MetaDataTable MD;
+		MD.read(fn_star);
+		int i = 0;
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MD)
+		{
+			MD.getValue(EMDL_POSTPROCESS_BFACTOR, DIRECT_A1D_ELEM(perframe_bfactors, i * 3 + 0) );
+			MD.getValue(EMDL_POSTPROCESS_GUINIER_FIT_INTERCEPT, DIRECT_A1D_ELEM(perframe_bfactors, i * 3 + 1) );
+			i++;
+		}
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+
+}
+
+void ParticlePolisher::writeStarFileBfactors(FileName fn_star)
+{
+	MetaDataTable MDout;
+	MDout.setName("perframe_bfactors");
+
+	for (int i = 0; i < XSIZE(perframe_bfactors)/3; i++ )
+	{
+		MDout.addObject();
+		MDout.setValue(EMDL_IMAGE_FRAME_NR, first_frame + i);
+		MDout.setValue(EMDL_POSTPROCESS_BFACTOR, DIRECT_A1D_ELEM(perframe_bfactors, i * 3 + 0) );
+		MDout.setValue(EMDL_POSTPROCESS_GUINIER_FIT_INTERCEPT, DIRECT_A1D_ELEM(perframe_bfactors, i * 3 + 1) );
+	}
+
+	MDout.write(fn_star);
+}
+
+void ParticlePolisher::writeStarFileRelativeWeights(FileName fn_star)
+{
+	std::ofstream  fh;
+    fh.open((fn_star).c_str(), std::ios::out);
+    if (!fh)
+        REPORT_ERROR( (std::string)"ParticlePolisher::writeStarFileRelativeWeights: Cannot write file: " + fn_star);
+
+    // First pre-calculate the sum of all weights at every frequency
+    MultidimArray<double> sumweight_per_shell(ori_size/2), cumulative_relweight_per_shell(ori_size/2);
+    sumweight_per_shell.initZeros();
+    for (int iframe = 0; iframe < XSIZE(perframe_bfactors)/3; iframe++ )
+   	{
+    	double bfactor = DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 0);
+    	double offset = DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 1);
+		for (int i = 1; i < ori_size/2; i++) // ignore origin
+		{
+			double res = (double)i / (ori_size * angpix); // resolution in 1/A
+			double w = exp( (bfactor / 4.)  * res * res  + offset);
+
+			DIRECT_A1D_ELEM(sumweight_per_shell, i) += w;
+		}
+   	}
+
+    // Now calculate the relative weights and their cumulative curves
+    cumulative_relweight_per_shell.initZeros();
+    for (int iframe = 0; iframe < XSIZE(perframe_bfactors)/3; iframe++ )
+    {
+
+    	double bfactor = DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 0);
+    	double offset = DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 1);
+
+    	MetaDataTable MDout;
+		std::string fn_table = "relative_weights_frame_" + integerToString(first_frame + iframe);
+		MDout.setName(fn_table);
+
+		for (int i = 1; i < ori_size/2; i++) // ignore origin
+		{
+			double res = (double)i / (ori_size * angpix); // resolution in 1/A
+			double w = exp( (bfactor / 4.)  * res * res  + offset);
+
+			w /= DIRECT_A1D_ELEM(sumweight_per_shell, i); // from absolute to relative weight
+			DIRECT_A1D_ELEM(cumulative_relweight_per_shell, i) += w;
+
+			MDout.addObject();
+			MDout.setValue(EMDL_RESOLUTION, res); //res in 1/A
+			MDout.setValue(EMDL_PERFRAME_RELATIVE_WEIGHT, w);
+			MDout.setValue(EMDL_PERFRAME_CUMULATIVE_WEIGHT, DIRECT_A1D_ELEM(cumulative_relweight_per_shell, i));
+
+		}
+		MDout.write(fh);
+
+	}
+
+    fh.close();
+}
+
+void ParticlePolisher::calculateAverageAllSingleFrameReconstructions(int this_half)
+{
+
+	FileName fn_sum;
+	fn_sum = fn_in.withoutExtension() + "_" + fn_out + "_avgframes_half" + integerToString(this_half) + "_class001_unfil.mrc";
+
+	if (!do_start_all_over && exists(fn_sum))
+	{
+		if (verb > 0)
+			std::cout << std::endl << " + " << fn_sum << " already exists: skipping calculation average of all frames." << std::endl;
+		return;
+	}
+
+	Image<double> Isum, Ione;
+	for (long int this_frame = first_frame; this_frame <= last_frame; this_frame++)
+	{
+    	FileName fn_vol;
+    	fn_vol.compose(fn_in.withoutExtension() + "_" + fn_out + "_frame", this_frame, "", 3);
+    	fn_vol += "_half" + integerToString(this_half) + "_class001_unfil.mrc";
+
+    	if (this_frame == first_frame)
+    	{
+    		Isum.read(fn_vol);
+    	}
+    	else
+    	{
+    		Ione.read(fn_vol);
+    		Isum() += Ione();
+    	}
+	}
+
+	// Write the average map to disc
+	Isum.write(fn_sum);
+
+}
+
+void ParticlePolisher::calculateSingleFrameReconstruction(int this_frame, int this_half)
+{
+
+	FileName fn_vol;
+	fn_vol.compose(fn_in.withoutExtension() + "_" + fn_out + "_frame", this_frame, "", 3);
+	fn_vol += "_half" + integerToString(this_half) + "_class001_unfil.mrc";
+	if (!do_start_all_over && exists(fn_vol))
+	{
+		if (verb > 0)
+			std::cout << std::endl << " + " << fn_vol << " already exists: skipping per-frame reconstruction." << std::endl;
+		return;
+	}
+
+
+
+	int image_size, current_size;
+	// get image size from metadatatable
+	exp_model.MDexp.getValue(EMDL_IMAGE_SIZE, image_size);
+	// Set current_size
+	if (perframe_highres > 0.)
+		current_size = 2 * ROUND(image_size * angpix / perframe_highres);
+	else
+		current_size = image_size;
+	BackProjector backprojector(image_size, 3, fn_sym);
+	backprojector.initZeros(current_size);
+
+	CTF ctf;
+	std::string dum;
+	Matrix2D<double> A3D;
+	MultidimArray<Complex > Faux, F2D, F2Dp, Fsub;
+	MultidimArray<double> Fweight, Fctf;
+	Image<double> img, vol;
+	FourierTransformer transformer;
+	Matrix1D< double > trans(2);
+	double rot, tilt, psi;
+	int i_half;
+	long int i_frame;
+	FileName fn_img, fn_mic;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(exp_model.MDimg)
+	{
+
+		exp_model.MDimg.getValue(EMDL_PARTICLE_RANDOM_SUBSET, i_half);
+		exp_model.MDimg.getValue(EMDL_MICROGRAPH_NAME, fn_mic);
+		fn_mic.decompose(i_frame, dum);
+
+		// TODO!! Make a running average window here
+		if (ABS(i_frame - this_frame) <= frame_running_average/2 && i_half == this_half)
+		{
+			exp_model.MDimg.getValue(EMDL_IMAGE_NAME, fn_img);
+			img.read(fn_img);
+			CenterFFT(img(), true);
+			transformer.FourierTransform(img(), F2Dp);
+			windowFourierTransform(F2Dp, F2D, current_size);
+
+			// Use the prior-angles, as these were determined from the average particles
+			// The individual-frame-determined angles would be too noisy....
+			exp_model.MDimg.getValue(EMDL_ORIENT_ROT_PRIOR, rot);
+			exp_model.MDimg.getValue(EMDL_ORIENT_TILT_PRIOR, tilt);
+			exp_model.MDimg.getValue(EMDL_ORIENT_PSI_PRIOR, psi);
+			Euler_angles2matrix(rot, tilt, psi, A3D);
+
+			// Translations
+			trans.initZeros();
+			exp_model.MDimg.getValue( EMDL_ORIENT_ORIGIN_X, XX(trans));
+			exp_model.MDimg.getValue( EMDL_ORIENT_ORIGIN_Y, YY(trans));
+			if (ABS(XX(trans)) > 0. || ABS(YY(trans)) > 0. )
+				shiftImageInFourierTransform(F2D, F2D, image_size, trans );
+
+			// CTF
+			Fctf.resize(F2D);
+			Fctf.initConstant(1.);
+			if (do_ctf)
+			{
+				ctf.read(exp_model.MDimg, exp_model.MDimg);
+				ctf.getFftwImage(Fctf, image_size, image_size, angpix, ctf_phase_flipped, only_flip_phases, intact_ctf_first_peak, true);
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(F2D)
+				{
+					DIRECT_MULTIDIM_ELEM(F2D, n)  *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+					DIRECT_MULTIDIM_ELEM(Fctf, n) *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+				}
+			}
+
+			backprojector.set2DFourierTransform(F2D, A3D, IS_NOT_INV, &Fctf);
+		}
+
+	}
+
+	// Now do the reconstruction
+	MultidimArray<double> dummy;
+	backprojector.reconstruct(vol(), 10, false, 1., dummy, dummy, dummy, dummy);
+
+	vol.write(fn_vol);
+
+}
+
+void ParticlePolisher::calculateBfactorSingleFrameReconstruction(int this_frame, double &bfactor, double &offset, double &corr_coeff)
+{
+
+	if (NZYXSIZE(Imask()) == 0)
+		REPORT_ERROR("ParticlePolisher::calculateBfactorSingleFrameReconstruction BUG: first read Imask, then call this function.");
+
+	if (this_frame > 0 && XSIZE(fsc_average) == 0)
+		REPORT_ERROR("ParticlePolisher::calculateBfactorSingleFrameReconstruction BUG: first call this function with this_frame < 0 to calculate FSC_average.");
+
+
+		// Read in the 2 half-reconstructions and calculate their FSC
+	FileName fn_root_half;
+	// Make sure that the first call to this function is with this_frame < 0!!!
+	if (this_frame < 0)
+		fn_root_half = fn_in.withoutExtension() + "_" + fn_out+"_avgframes";
+	else
+		fn_root_half.compose(fn_in.withoutExtension() + "_" + fn_out+"_frame",this_frame,"", 3);
+
+	FileName fn_half1, fn_half2;
+	Image<double> I1, I2;
+	MultidimArray<double> fsc_frame;
+	I1.read(fn_root_half + "_half1_class001_unfil.mrc");
+	I2.read(fn_root_half + "_half2_class001_unfil.mrc");
+
+	// Mask both maps
+	I1() *= Imask();
+	I2() *= Imask();
+	getFSC(I1(), I2(), fsc_frame);
+
+	if (this_frame < 0)
+	{
+		fsc_average = fsc_frame;
+		return;
+	}
+	else
+	{
+		// Now use relative ratio of signal amplitudes w.r.t. the average of all single-frame reconstructions
+		// SSNR= tau^2/sigma^2 = FSC / (1 - FSC)
+		// tau_frame / tau_avg = tau_f / tau_a = sqrt (FSC_f / (1 - FSC_f)) / sqrt (FSC_a / (1 - FSC_a))
+		// = sqrt( {FSC_f / (1 - FSC_f)} * {(1 - FSC_a) / FSC_a} )
+		// = sqrt( (FSC_f - FSC_f * FSC_a) / (FSC_a - FSC_f * FSC_a)  )
+		// Then make a Guinier plot of that: ln(tau) versus 1/d^2 and
+		// fit a line through all points where FSC_f < 1 && FSC_f > 0.143
+		// Store the bfactor (4*slope) AND the offset of that line
+
+
+		MetaDataTable MDout;
+		MDout.setName("relative_guinier");
+
+		fit_point2D      onepoint;
+		std::vector<fit_point2D> guinier;
+		for (int i = 1; i < XSIZE(fsc_frame); i++) // ignore origin
+		{
+			double res = (double)i / (XSIZE(I1()) * angpix); // resolution in 1/A
+			double resang = 1. / res;
+			double res2 = res*res;
+
+			double fsc_f = DIRECT_A1D_ELEM(fsc_frame, i);
+			double fsc_a = DIRECT_A1D_ELEM(fsc_average, i);
+
+			if (resang < fit_minres && resang > perframe_highres && fsc_f < 1 && fsc_a < 1 && fsc_f > 0.143 && fsc_a > 0.143)
+			{
+				// ln(tau_f / tau_a)
+				// I could have calculated the same using: ln(tau_f / tau_a)   = ln(tau_f) - ln(tau_a)
+				// where tau_f = sqrt (FSC_f / (1 - FSC_f)) and tau_a = sqrt (FSC_a / (1 - FSC_a))
+				// This is numerically identical
+				double logreltau = log( sqrt( (fsc_f - fsc_f * fsc_a) / (fsc_a - fsc_f * fsc_a) ) );
+
+				onepoint.x = res2;
+				onepoint.y = logreltau;
+				onepoint.w = 1.;
+				guinier.push_back(onepoint);
+
+				MDout.addObject();
+				MDout.setValue(EMDL_POSTPROCESS_GUINIER_RESOL_SQUARED, res2);
+				MDout.setValue(EMDL_POSTPROCESS_GUINIER_VALUE_IN, logreltau);
+			}
+		}
+		MDout.write(fn_root_half + "_guinier.star");
+
+		// Now do the fit
+		fitStraightLine(guinier, bfactor, offset, corr_coeff);
+		// this is the B-factor relative to the average from all single-frame reconstructions!
+		// in this case: positive values mean BETTER than average, and thus HIGHER WEIGHTS!
+		bfactor *= 4.;
+	}
+
+}
+
+void ParticlePolisher::polishParticlesAllMicrographs()
+{
+
+	if (!do_start_all_over && exists(fn_out + ".star"))
+	{
+		if (verb > 0)
+			std::cout << std::endl << " + " << fn_out << ".star already exists: skipping polishing of the particles." << std::endl;
+
+		return;
+	}
+
+	// Loop over all average micrographs
+	int barstep;
+	int my_nr_micrographs = exp_model.average_micrographs.size();
+	if (verb > 0)
+	{
+		std::cout << " + Write out polished particles for all micrographs ... " << std::endl;
+		init_progress_bar(my_nr_micrographs);
+		barstep = XMIPP_MAX(1, my_nr_micrographs/ 60);
+	}
+
+    for (long int i = 0; i < my_nr_micrographs; i++)
+	{
+    	if (verb > 0 && i % barstep == 0)
+			progress_bar(i);
+
+		polishParticlesOneMicrograph(i);
+	}
+
+    writeStarFilePolishedParticles();
+
+    if (verb > 0)
+	{
+		progress_bar(my_nr_micrographs);
+	}
+
+}
+
+void ParticlePolisher::writeStarFilePolishedParticles()
+{
+
+	// Also write the STAR file with the MetaData of the polished particles
+	// Loop over all original_particles in this average_micrograph
+
+	MDshiny.clear();
+	for (long int imic = 0; imic < exp_model.average_micrographs.size(); imic++)
+	{
+		for (long int ipar = 0; ipar < exp_model.average_micrographs[imic].ori_particles_id.size(); ipar++)
+		{
+			long int ori_part_id = exp_model.average_micrographs[imic].ori_particles_id[ipar];
+			long int part_id = exp_model.ori_particles[ori_part_id].particles_id[first_frame - 1];
+			long int img_id = exp_model.getImageId(part_id, 0);
+
+			// Get the corresponding line from the input STAR file
+			MDshiny.addObject(exp_model.MDimg.getObject(img_id));
+
+			// The orientations and offsets in this line of the metadatatable come only from a single frame!!!
+			// Use the ones stored in the prior instead.
+			double xoff, yoff, rot, tilt, psi;
+			MDshiny.getValue(EMDL_ORIENT_ORIGIN_X_PRIOR, xoff);
+			MDshiny.getValue(EMDL_ORIENT_ORIGIN_Y_PRIOR, yoff);
+			MDshiny.getValue(EMDL_ORIENT_ROT_PRIOR, rot);
+			MDshiny.getValue(EMDL_ORIENT_TILT_PRIOR, tilt);
+			MDshiny.getValue(EMDL_ORIENT_PSI_PRIOR, psi);
+			MDshiny.setValue(EMDL_ORIENT_ORIGIN_X, xoff);
+			MDshiny.setValue(EMDL_ORIENT_ORIGIN_Y, yoff);
+			MDshiny.setValue(EMDL_ORIENT_ROT, rot);
+			MDshiny.setValue(EMDL_ORIENT_TILT, tilt);
+			MDshiny.setValue(EMDL_ORIENT_PSI, psi);
+
+			// also get the "@" out of the micrograph name!
+			FileName fn_tmp;
+			MDshiny.getValue(EMDL_MICROGRAPH_NAME, fn_tmp);
+			fn_tmp = fn_tmp.afterFirstOf("@");
+			MDshiny.setValue(EMDL_MICROGRAPH_NAME, fn_tmp);
+
+			// Also change this particle's image_name
+			FileName fn_part, fn_img;
+			exp_model.MDimg.getValue(EMDL_PARTICLE_ORI_NAME, fn_part, img_id);
+			fn_part = fn_part.withoutExtension();
+			std::string mic_name;
+			long int nr;
+			fn_part.decompose(nr, mic_name);
+			fn_part = mic_name + "_" + fn_out + ".mrcs";
+			fn_img.compose(ipar + 1, fn_part);
+
+			MDshiny.setValue(EMDL_IMAGE_NAME, fn_img);
+		}
+	}
+
+	// Deactivate PRIORs so they are not written out
+	MDshiny.deactivateLabel(EMDL_ORIENT_ORIGIN_X_PRIOR);
+	MDshiny.deactivateLabel(EMDL_ORIENT_ORIGIN_Y_PRIOR);
+	MDshiny.deactivateLabel(EMDL_ORIENT_ROT_PRIOR);
+	MDshiny.deactivateLabel(EMDL_ORIENT_TILT_PRIOR);
+	MDshiny.deactivateLabel(EMDL_ORIENT_PSI_PRIOR);
+
+	// Write output metadatatable
+	MDshiny.write(fn_out + ".star");
+	std::cout << " + Written out all polished particles and their corresponding STAR file: " << fn_out << ".star" << std::endl;
+
+}
+
+
+void ParticlePolisher::polishParticlesOneMicrograph(long int imic)
+{
+
+	// Then read in all individual movie frames, apply frame x,y-movements as phase shifts and calculate polished (shiny) particles
+	// as average of the re-aligned frames
+	double x_off_p, y_off_p, x_off_prior_p, y_off_prior_p;
+	FileName fn_img, fn_part;
+	Image<double> img;
+	FourierTransformer transformer;
+	MultidimArray< Complex > Fimg, Fwsum;
+	MultidimArray<double> Fsumw;
+	Matrix1D <double> trans(2);
+	double all_minval = 99999., all_maxval = -99999., all_avg = 0., all_stddev = 0.;
+
+	// Loop over all original_particles in this average_micrograph
+	for (long int ipar = 0; ipar < exp_model.average_micrographs[imic].ori_particles_id.size(); ipar++)
+	{
+		long int ori_part_id = exp_model.average_micrographs[imic].ori_particles_id[ipar];
+
+		// Loop over all frames for motion corrections and possibly dose-dependent weighting
+		for (long int i_frame = first_frame; i_frame <= last_frame; i_frame++ )
+		{
+			long int part_id = exp_model.ori_particles[ori_part_id].particles_id[i_frame - 1]; // start counting frames at 0, not 1
+			long int img_id = exp_model.getImageId(part_id, 0);
+
+			exp_model.MDimg.getValue(EMDL_IMAGE_NAME, fn_img, img_id);
+			exp_model.MDimg.getValue(EMDL_PARTICLE_ORI_NAME, fn_part, img_id);
+			exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_X_PRIOR, x_off_prior_p, img_id);
+			exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_Y_PRIOR, y_off_prior_p, img_id);
+			if (fitting_mode != NO_FIT)
+			{
+				x_off_p = A2D_ELEM(fitted_movements, img_id, 0);
+				y_off_p = A2D_ELEM(fitted_movements, img_id, 1);
+			}
+			else
+			{
+				exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_X, x_off_p, img_id);
+				exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_Y, y_off_p, img_id);
+			}
+
+			img.read(fn_img);
+			double ori_size= XSIZE(img());
+
+			// Get the image shifts relative to the prior
+			XX(trans) = x_off_p - x_off_prior_p;
+			YY(trans) = y_off_p - y_off_prior_p;
+
+#ifdef DEBUG
+			if (fn_part =="000001 at Particles/Micrographs/Falcon_2012_06_13-01_05_13_0_rh15particles.mrcs")
+			{
+				double xp, yp;
+				exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_X, xp, img_id);
+				exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_Y, yp, img_id);
+				std::cerr << " x_off_prior_p= " << x_off_prior_p << " x_off_p= " << x_off_p << " xp= " << xp << std::endl;
+				std::cerr << " y_off_prior_p= " << y_off_prior_p << " y_off_p= " << y_off_p << " yp= " << yp << std::endl;
+				std::cerr << " iframe= " << i_frame << " XX(trans)= " << XX(trans) << " YY(trans)= " << YY(trans) << std::endl;
+			}
+#endif
+
+			// Apply the phase shifts for this translation in Fourier space
+			transformer.FourierTransform(img(), Fimg);
+
+			if (i_frame == first_frame)
+			{
+				Fwsum.initZeros(Fimg);
+				Fsumw.initZeros(Fimg);
+			}
+
+			shiftImageInFourierTransform(Fimg, Fimg, ori_size, trans);
+
+			// Apply (positive!!) B-factor weighting and store weighted sums
+			int iframe = i_frame - first_frame;
+			double bfactor = (do_weighting) ? DIRECT_A1D_ELEM(perframe_bfactors, 3*iframe + 0) : 0.;
+			double offset  = (do_weighting) ? DIRECT_A1D_ELEM(perframe_bfactors, 3*iframe + 1) : 0.;
+			FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM2D(Fimg)
+			{
+				double res = sqrt((double)ip * ip + jp * jp) / (XSIZE(img()) * angpix); // get resolution in 1/Angstrom
+				if (res <= 1. / (angpix * 2.) ) // Apply B-factor weighting until Nyquist
+				{
+					double w = exp( (bfactor / 4)  * res * res  + offset);
+					DIRECT_A2D_ELEM(Fwsum, i, j) += w * DIRECT_A2D_ELEM(Fimg, i, j);
+					DIRECT_A2D_ELEM(Fsumw, i, j) += w;
+				}
+			}
+		}
+
+		// Calculate the weighted average image
+		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fwsum)
+		{
+			if (DIRECT_MULTIDIM_ELEM(Fsumw, n) > 0.)
+				DIRECT_MULTIDIM_ELEM(Fwsum, n) /= DIRECT_MULTIDIM_ELEM(Fsumw, n);
+		}
+		transformer.inverseFourierTransform(Fwsum, img());
+
+		if (do_normalise)
+			normalise(img, bg_radius, white_dust_stddev, black_dust_stddev);
+
+		// Calculate statistics for the (normalised?) particle
+		double minval, maxval, avgval, stddev;
+		img().computeStats(avgval, stddev, minval, maxval);
+
+		// Keep track of overall statistics for all particles in this field-of-view
+		all_minval = XMIPP_MIN(minval, all_minval);
+		all_maxval = XMIPP_MAX(maxval, all_maxval);
+		all_avg	+= avgval;
+		all_stddev += stddev*stddev;
+
+		// write the new average (i.e. the shiny, or polished particle)
+		fn_part = fn_part.withoutExtension();
+		std::string mic_name;
+		long int nr;
+		fn_part.decompose(nr, mic_name);
+		fn_part = mic_name + "_" + fn_out + ".mrcs";
+		fn_img.compose(ipar + 1, fn_part);
+
+		// When last particle, also write the correct header
+		if (ipar == exp_model.average_micrographs[imic].ori_particles_id.size() - 1)
+		{
+			all_avg /= exp_model.average_micrographs[imic].ori_particles_id.size();
+			all_stddev = sqrt(all_stddev/exp_model.average_micrographs[imic].ori_particles_id.size());
+			img.MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN, all_minval);
+			img.MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX, all_maxval);
+			img.MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG, all_avg);
+			img.MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV, all_stddev);
+		}
+
+		if (ipar == 0)
+			img.write(fn_img, -1, false, WRITE_OVERWRITE);
+		else
+			img.write(fn_img, -1, true, WRITE_APPEND);
+
+	}
+
+}
+
+void ParticlePolisher::reconstructShinyParticlesAndFscWeight(int ipass)
+{
+
+	if (verb > 0)
+		std::cout << "+ Reconstructing two halves of shiny particles ..." << std::endl;
+
+	// Re-read the shiny particles' MetaDataTable into exp_model
+	exp_model.read(fn_out + ".star", true);
+
+	// Do the reconstructions for both halves
+	reconstructShinyParticlesOneHalf(1);
+	reconstructShinyParticlesOneHalf(2);
+
+
+	FileName fn_post = (ipass == 1) ? "_post" : "_post2";
+	if (!do_start_all_over && exists(fn_in.withoutExtension() + "_" + fn_out + fn_post + "_masked.mrc")
+					       && exists(fn_in.withoutExtension() + "_" + fn_out + fn_post + ".star") )
+	{
+		if (verb > 0)
+			std::cout << std::endl << " + " << fn_in.withoutExtension() << "_" << fn_out << fn_post << "_masked.mrc already exists: re-reading map into memory." << std::endl;
+
+		if (verb > 0)
+			std::cout << std::endl << " + " << fn_in.withoutExtension() << "_" << fn_out << fn_post << ".star already exists: re-reading resolution from it." << std::endl;
+
+		MetaDataTable MD;
+		MD.read(fn_in.withoutExtension() + "_" + fn_out + fn_post + ".star", "general");
+		MD.getValue(EMDL_POSTPROCESS_FINAL_RESOLUTION, maxres_model);
+	}
+	else
+	{
+		// Re-read the two halves to calculate FSCs
+		Postprocessing prm;
+
+		prm.clear();
+		prm.fn_in = fn_in.withoutExtension() + "_" + fn_out;
+		prm.fn_out = prm.fn_in + fn_post;
+		prm.angpix = angpix;
+		prm.do_auto_mask = false;
+		prm.fn_mask = fn_mask;
+		prm.do_auto_bfac = false;
+		prm.do_fsc_weighting = true;
+		prm.verb = 0;
+		prm.run();
+
+		maxres_model = prm.global_resol;
+	}
+
+	if (verb > 0)
+		std::cout << " + Setting Fourier transforms of the two shiny half-reconstructions ..." << std::endl;
+
+	MultidimArray<double> dum;
+	Image<double> refvol;
+	FileName fn_vol;
+	fn_vol = fn_in.withoutExtension() + "_" + fn_out + "_half1_class001_unfil.mrc";
+	refvol.read(fn_vol);
+	PPrefvol_half1.ori_size = XSIZE(refvol());
+	PPrefvol_half1.padding_factor = 2;
+	PPrefvol_half1.interpolator = TRILINEAR;
+	PPrefvol_half1.r_min_nn = 10;
+	PPrefvol_half1.computeFourierTransformMap(refvol(), dum);
+	fn_vol = fn_in.withoutExtension() + "_" + fn_out + "_half2_class001_unfil.mrc";
+	refvol.read(fn_vol);
+	PPrefvol_half2.ori_size = XSIZE(refvol());
+	PPrefvol_half2.padding_factor = 2;
+	PPrefvol_half2.interpolator = TRILINEAR;
+	PPrefvol_half2.r_min_nn = 10;
+	PPrefvol_half2.computeFourierTransformMap(refvol(), dum);
+
+}
+
+void ParticlePolisher::reconstructShinyParticlesOneHalf(int this_half)
+{
+
+	FileName fn_vol = fn_in.withoutExtension() + "_" + fn_out + "_half" + integerToString(this_half) + "_class001_unfil.mrc";
+	if (!do_start_all_over && exists(fn_vol))
+	{
+		if (verb > 0)
+			std::cout << std::endl << " + " << fn_vol << " already exists: skipping shiny-particle reconstruction." << std::endl;
+		return;
+	}
+
+	// get image size, angpix (from metadatatable), fn_sym
+	int image_size;
+	exp_model.MDexp.getValue(EMDL_IMAGE_SIZE, image_size);
+	BackProjector backprojector(image_size, 3, fn_sym);
+	backprojector.initZeros();
+	Projector projector(image_size);
+
+
+	CTF ctf;
+	std::string dum;
+	Matrix2D<double> A3D;
+	MultidimArray<Complex > Faux, F2D, Fsub;
+	MultidimArray<double> Fweight, Fctf;
+	Image<double> img, vol;
+	FourierTransformer transformer;
+	Matrix1D< double > trans(2);
+	double rot, tilt, psi;
+	int i_half;
+	long int i_frame;
+	FileName fn_img;
+
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(exp_model.MDimg)
+	{
+
+		exp_model.MDimg.getValue(EMDL_PARTICLE_RANDOM_SUBSET, i_half);
+		if (i_half == this_half)
+		{
+			exp_model.MDimg.getValue(EMDL_IMAGE_NAME, fn_img);
+			img.read(fn_img);
+			CenterFFT(img(), true);
+			transformer.FourierTransform(img(), F2D);
+
+			// Use the prior-angles, as these were determined from the average particles
+			// The individual-frame-determined angles would be too noisy....
+			exp_model.MDimg.getValue(EMDL_ORIENT_ROT, rot);
+			exp_model.MDimg.getValue(EMDL_ORIENT_TILT, tilt);
+			exp_model.MDimg.getValue(EMDL_ORIENT_PSI, psi);
+			Euler_angles2matrix(rot, tilt, psi, A3D);
+
+			// Translations
+			trans.initZeros();
+			exp_model.MDimg.getValue( EMDL_ORIENT_ORIGIN_X, XX(trans));
+			exp_model.MDimg.getValue( EMDL_ORIENT_ORIGIN_Y, YY(trans));
+			if (ABS(XX(trans)) > 0. || ABS(YY(trans)) > 0. )
+				shiftImageInFourierTransform(F2D, F2D, image_size, trans );
+
+			// CTF
+			Fctf.resize(F2D);
+			Fctf.initConstant(1.);
+			if (do_ctf)
+			{
+				ctf.read(exp_model.MDimg, exp_model.MDimg);
+				ctf.getFftwImage(Fctf, image_size, image_size, angpix, ctf_phase_flipped, only_flip_phases, intact_ctf_first_peak, true);
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(F2D)
+				{
+					DIRECT_MULTIDIM_ELEM(F2D, n)  *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+					DIRECT_MULTIDIM_ELEM(Fctf, n) *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+				}
+			}
+
+			backprojector.set2DFourierTransform(F2D, A3D, IS_NOT_INV, &Fctf);
+		}
+
+	}
+
+	// Now do the reconstruction
+	MultidimArray<double> dummy;
+	backprojector.reconstruct(vol(), 10, false, 1., dummy, dummy, dummy, dummy);
+
+	vol.write(fn_vol);
+
+}
+
+
+
+void ParticlePolisher::optimiseBeamTiltAndDefocus()
+{
+
+	// This function assumes the shiny particles are in exp_mdel.MDimg!!
+	if (beamtilt_max <= 0. && defocus_shift_max <= 0.)
+		return;
+
+	if (minres_beamtilt < maxres_model)
+	{
+		if (verb > 0)
+			std::cout << " Skipping beamtilt correction, as the resolution of the shiny reconstruction  does not go beyond minres_beamtilt of " << minres_beamtilt << " Ang." << std::endl;
+		return;
+	}
+
+	getBeamTiltGroups();
+
+	initialiseSquaredDifferenceVectors();
+
+	// Loop over all average micrographs
+	int barstep;
+	int my_nr_micrographs = exp_model.micrographs.size();
+	if (verb > 0)
+	{
+		std::cout << " + Optimising beamtilts in all micrographs ... " << std::endl;
+		init_progress_bar(my_nr_micrographs);
+		barstep = XMIPP_MAX(1, my_nr_micrographs/ 60);
+	}
+
+    for (long int i = 0; i < my_nr_micrographs; i++)
+	{
+    	if (verb > 0 && i % barstep == 0)
+			progress_bar(i);
+
+    	optimiseBeamTiltAndDefocusOneMicrograph(i);
+	}
+
+    if (verb > 0)
+	{
+		progress_bar(my_nr_micrographs);
+	}
+
+    // Now get the final optimised beamtilts!
+    applyOptimisedBeamTiltsAndDefocus();
+
+    // Write the new MDTable to disc
+	if (verb > 0)
+		exp_model.MDimg.write(fn_out + ".star");
+
+}
+
+void ParticlePolisher::getBeamTiltGroups()
+{
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(exp_model.MDimg)
+	{
+
+		// Get the name of the beamtilt group (micrograph name if no groups are defined...)
+		FileName fn_group;
+		if (exp_model.MDimg.containsLabel(EMDL_IMAGE_BEAMTILT_GROUP))
+			exp_model.MDimg.getValue(EMDL_IMAGE_BEAMTILT_GROUP, fn_group);
+		else
+			exp_model.MDimg.getValue(EMDL_MICROGRAPH_NAME, fn_group);
+
+		bool is_unique = true;
+		for (int igroup = 0; igroup < fn_beamtilt_groups.size(); igroup++)
+		{
+			if (fn_beamtilt_groups[igroup] == fn_group)
+			{
+				is_unique = false;
+				break;
+			}
+		}
+		if (is_unique)
+		{
+			fn_beamtilt_groups.push_back(fn_group);
+		}
+	}
+
+}
+
+void ParticlePolisher::initialiseSquaredDifferenceVectors()
+{
+
+	nr_sampled_beam_tilts= 0;
+	if (beamtilt_max > 0.)
+	{
+		int n_steps = CEIL(beamtilt_max / beamtilt_step);
+		for (double tilt_y = -n_steps*beamtilt_step; tilt_y <= n_steps*beamtilt_step; tilt_y += beamtilt_step)
+		{
+			for (double tilt_x = -n_steps*beamtilt_step; tilt_x <= n_steps*beamtilt_step; tilt_x += beamtilt_step)
+			{
+				if (sqrt(tilt_y*tilt_y + tilt_x*tilt_x) <= beamtilt_max)
+				{
+					nr_sampled_beam_tilts++;
+				}
+			}
+		}
+		// Store squared differences for all beam tilts and for all data sets
+		diff2_beamtilt.initZeros(fn_beamtilt_groups.size(), nr_sampled_beam_tilts);
+	}
+
+	if (defocus_shift_max > 0.)
+	{
+		defocus_shift_allmics.initZeros(exp_model.micrographs.size());
+	}
+
+
+}
+
+void ParticlePolisher::applyOptimisedBeamTiltsAndDefocus()
+{
+	if (beamtilt_max > 0.)
+	{
+		// Use in two different loops
+		int n_steps = CEIL(beamtilt_max / beamtilt_step);
+
+		best_beamtilts.clear();
+		Matrix1D<double> my_tilts(2);
+		for (int igroup = 0; igroup < fn_beamtilt_groups.size(); igroup++)
+		{
+			double mindiff2 = 99.e99;
+			double best_tilt_x, best_tilt_y;
+			if (verb > 0)
+				std::cout << " + Beamtilt group " << fn_beamtilt_groups[igroup] << std::endl;
+			int n_tilt= 0;
+			for (double tilt_y = -n_steps*beamtilt_step; tilt_y <= n_steps*beamtilt_step; tilt_y += beamtilt_step)
+			{
+				for (double tilt_x = -n_steps*beamtilt_step; tilt_x <= n_steps*beamtilt_step; tilt_x += beamtilt_step)
+				{
+					if (sqrt(tilt_y*tilt_y + tilt_x*tilt_x) <= beamtilt_max)
+					{
+						double diff2 = DIRECT_A2D_ELEM(diff2_beamtilt, igroup, n_tilt);
+						if (verb > 1)
+							std::cout << " + tilt_x = " << tilt_x << " + tilt_y = " << tilt_y << " diff2= " << diff2 << std::endl;
+	#ifdef DEBUG_TILT
+
+						if (verb > 0)
+							std::cerr << " igroup= " << igroup << " n_tilt= " << n_tilt
+							<< " DIRECT_A2D_ELEM(diff2_beamtilt, igroup, n_tilt)= " << DIRECT_A2D_ELEM(diff2_beamtilt, igroup, n_tilt)
+							<< " diff2= " << diff2 << " mindiff2= " << mindiff2
+							<< std::endl;
+	#endif
+						if (diff2 <= mindiff2)
+						{
+							best_tilt_x = tilt_x;
+							best_tilt_y = tilt_y;
+							mindiff2 = diff2;
+						}
+						n_tilt ++;
+					}
+				}
+			}
+			if (verb > 0)
+				std::cout << " + Best tilt_x = " << best_tilt_x << " best tilt_y = " << best_tilt_y << " mindiff2= " << mindiff2 << std::endl;
+			XX(my_tilts) = best_tilt_x;
+			YY(my_tilts) = best_tilt_y;
+			best_beamtilts.push_back(my_tilts);
+		}
+	}
+
+
+	// Now set beamtilts in the MetaDataTable
+    int i_group;
+	for (long int imic = 0; imic < exp_model.micrographs.size(); imic++)
+	{
+
+		double best_defocus_shift = (defocus_shift_max > 0.) ? DIRECT_A1D_ELEM(defocus_shift_allmics, imic) : 0.;
+		for (long int iimg = 0; iimg < exp_model.micrographs[imic].images.size(); iimg++)
+    	{
+    		long int img_id = exp_model.micrographs[imic].images[iimg].id;
+
+    		// Set the optimised beamtilts in the MetadataTable
+    		if (beamtilt_max > 0.)
+    		{
+				// First get which beamtilt group this micrograph comes from
+				if (iimg == 0)
+				{
+					FileName fn_group;
+					if (exp_model.MDimg.containsLabel(EMDL_IMAGE_BEAMTILT_GROUP))
+						exp_model.MDimg.getValue(EMDL_IMAGE_BEAMTILT_GROUP, fn_group, img_id);
+					else
+						exp_model.MDimg.getValue(EMDL_MICROGRAPH_NAME, fn_group, img_id);
+					bool found = false;
+					for (int igroup = 0; igroup < fn_beamtilt_groups.size(); igroup++)
+					{
+						if (fn_group == fn_beamtilt_groups[igroup])
+						{
+							i_group = igroup;
+							found = true;
+							break;
+						}
+					}
+					if (!found)
+						REPORT_ERROR("ParticlePolisher::optimiseBeamTiltOneMicrograph ERROR: could not find data set name for " + fn_group);
+
+				}
+
+				// Then set the corresponding beamtilt values for each particles
+				exp_model.MDimg.setValue(EMDL_IMAGE_BEAMTILT_X, XX(best_beamtilts[i_group]), img_id);
+				exp_model.MDimg.setValue(EMDL_IMAGE_BEAMTILT_Y, YY(best_beamtilts[i_group]), img_id);
+
+    		}
+
+			// Also set the optimised defocus values for each micrograph
+			if (defocus_shift_max > 0.)
+			{
+
+				if (iimg == 0 && verb > 0)
+					std::cout << " + Micrograph " << exp_model.micrographs[imic].name << " defocus_shift= " << best_defocus_shift << std::endl;
+
+				double ori_defocusU, ori_defocusV;
+				exp_model.MDimg.getValue(EMDL_CTF_DEFOCUSU, ori_defocusU, img_id);
+				exp_model.MDimg.getValue(EMDL_CTF_DEFOCUSV, ori_defocusV, img_id);
+				exp_model.MDimg.setValue(EMDL_CTF_DEFOCUSU, ori_defocusU + best_defocus_shift, img_id);
+				exp_model.MDimg.setValue(EMDL_CTF_DEFOCUSV, ori_defocusV + best_defocus_shift, img_id);
+			}
+    	}
+	}
+
+
+
+}
+
+void ParticlePolisher::optimiseBeamTiltAndDefocusOneMicrograph(int imic)
+{
+
+	// get image size, angpix (from metadatatable), fn_sym
+	int image_size;
+	exp_model.MDexp.getValue(EMDL_IMAGE_SIZE, image_size);
+
+	CTF ctf;
+	Matrix2D<double> A3D;
+	MultidimArray<Complex > F2D, F2Dtilt, Fref;
+	MultidimArray<double> Fctf;
+	Image<double> img;
+	FourierTransformer transformer;
+	Matrix1D< double > trans(2);
+	double rot, tilt, psi;
+	FileName fn_img;
+	int i_group = -1, my_half = 0;
+
+	double xsize = angpix * PPrefvol_half1.ori_size;
+
+	// Weighted squared-differences for all defocusses
+	int nr_sampled_defocus_shifts;
+	MultidimArray<double> wdiff2_defocus;
+	if (defocus_shift_max > 0.)
+	{
+		nr_sampled_defocus_shifts = CEIL(defocus_shift_max / defocus_shift_step);
+		wdiff2_defocus.initZeros(2*nr_sampled_defocus_shifts + 1);
+	}
+
+	for (long int iimg = 0; iimg < exp_model.micrographs[imic].images.size(); iimg++)
+	{
+
+		long int img_id = exp_model.micrographs[imic].images[iimg].id;
+
+		// Get which beamtilt group this micrograph comes from
+		if (iimg == 0)
+		{
+			FileName fn_group;
+			if (exp_model.MDimg.containsLabel(EMDL_IMAGE_BEAMTILT_GROUP))
+				exp_model.MDimg.getValue(EMDL_IMAGE_BEAMTILT_GROUP, fn_group, img_id);
+			else
+				exp_model.MDimg.getValue(EMDL_MICROGRAPH_NAME, fn_group, img_id);
+			bool found = false;
+			for (int igroup = 0; igroup < fn_beamtilt_groups.size(); igroup++)
+			{
+				if (fn_group == fn_beamtilt_groups[igroup])
+				{
+					i_group = igroup;
+					found = true;
+					break;
+				}
+			}
+			if (!found)
+				REPORT_ERROR("ParticlePolisher::optimiseBeamTiltOneMicrograph ERROR: could not find beamtilt group name for " + fn_group);
+
+		}
+
+
+		exp_model.MDimg.getValue(EMDL_IMAGE_NAME, fn_img, img_id);
+		img.read(fn_img);
+		CenterFFT(img(), true);
+		transformer.FourierTransform(img(), F2D);
+
+		// Which half do I belong to?
+		exp_model.MDimg.getValue(EMDL_PARTICLE_RANDOM_SUBSET, my_half, img_id);
+
+		// Use the prior-angles, as these were determined from the average particles
+		// The individual-frame-determined angles would be too noisy....
+		exp_model.MDimg.getValue(EMDL_ORIENT_ROT, rot, img_id);
+		exp_model.MDimg.getValue(EMDL_ORIENT_TILT, tilt, img_id);
+		exp_model.MDimg.getValue(EMDL_ORIENT_PSI, psi, img_id);
+		Euler_angles2matrix(rot, tilt, psi, A3D);
+
+		// Get the reference projection
+		Fref.resize(F2D);
+		if (my_half == 1)
+			PPrefvol_half1.get2DFourierTransform(Fref, A3D, IS_NOT_INV);
+		else if (my_half == 2)
+			PPrefvol_half2.get2DFourierTransform(Fref, A3D, IS_NOT_INV);
+		else
+			REPORT_ERROR("ERROR unrecognised random subset, not 1 or 2...");
+
+		// Shift the experimental image
+		trans.initZeros();
+		exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_X, XX(trans), img_id);
+		exp_model.MDimg.getValue(EMDL_ORIENT_ORIGIN_Y, YY(trans), img_id);
+		if (ABS(XX(trans)) > 0. || ABS(YY(trans)) > 0. )
+			shiftImageInFourierTransform(F2D, F2D, image_size, trans );
+
+		// apply CTF to the reference
+		if (do_ctf)
+		{
+
+			Fctf.resize(F2D);
+			ctf.read(exp_model.MDimg, exp_model.MDimg, img_id);
+
+			// Store the original values of defocusU and defocusV
+			double ori_defocusU = ctf.DeltafU;
+			double ori_defocusV = ctf.DeltafV;
+			double best_defocus_shift;
+			double mindiff_thispart = 99.e99;
+			// Optimise per-particle CTF defocus
+			// For now only non-anisotropically
+			if (defocus_shift_max > 0.)
+			{
+
+				int n_defocus = 0;
+				for (double defocus_shift = -nr_sampled_defocus_shifts*defocus_shift_step;
+						defocus_shift <= nr_sampled_defocus_shifts*defocus_shift_step;
+						defocus_shift += defocus_shift_step)
+				{
+					// Get modified CTF and apply to reference
+					ctf.DeltafU = ori_defocusU + defocus_shift;
+					ctf.DeltafV = ori_defocusV + defocus_shift;
+					ctf.initialise();
+					ctf.getFftwImage(Fctf, image_size, image_size, angpix, ctf_phase_flipped, only_flip_phases, intact_ctf_first_peak, true);
+
+					// Calculate squared difference with the image
+					double diff2 = 0.;
+					FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM2D(F2D)
+					{
+						double res = xsize/sqrt((double)(ip * ip + jp * jp)); // get resolution in 1/pixel
+						if (res <= minres_beamtilt && res >= maxres_model)
+				    	{
+							double diff_real = DIRECT_A2D_ELEM(Fctf, i, j) * (DIRECT_A2D_ELEM(Fref, i, j)).real - (DIRECT_A2D_ELEM(F2D, i, j)).real;
+							double diff_imag = DIRECT_A2D_ELEM(Fctf, i, j) * (DIRECT_A2D_ELEM(Fref, i, j)).imag - (DIRECT_A2D_ELEM(F2D, i, j)).imag;
+							diff2 += (diff_real * diff_real + diff_imag * diff_imag);
+				    	}
+					}
+					// Store the accumulated squared differences...
+					if (diff2 < mindiff_thispart)
+					{
+						mindiff_thispart = diff2;
+						best_defocus_shift = defocus_shift;
+					}
+					//std::cerr << " iimg= " << iimg << " defocus_shift= " << defocus_shift << " diff2= " << diff2 << std::endl;
+
+					DIRECT_A1D_ELEM(wdiff2_defocus, n_defocus) += diff2;
+					n_defocus++;
+				}
+
+				// Set best defocus for each individual particle...
+				// TODO!!! This only works in sequential version!!!
+				//exp_model.MDimg.setValue(EMDL_CTF_DEFOCUSU, ori_defocusU + best_defocus_shift, img_id);
+				//exp_model.MDimg.setValue(EMDL_CTF_DEFOCUSV, ori_defocusV + best_defocus_shift, img_id);
+
+				// Re-set the original defocus values in the ctf object
+				ctf.DeltafU = ori_defocusU;
+				ctf.DeltafV = ori_defocusV;
+				ctf.initialise();
+			}
+
+
+		}
+
+		if (beamtilt_max > 0.)
+		{
+
+			if (do_ctf)
+			{
+				// After per-particle assessment, just re-read the stored CTF and apply to the reference projection
+				ctf.getFftwImage(Fctf, image_size, image_size, angpix, ctf_phase_flipped, only_flip_phases, intact_ctf_first_peak, true);
+				FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(F2D)
+				{
+					DIRECT_MULTIDIM_ELEM(Fref, n)  *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+				}
+			}
+
+			F2Dtilt.resize(F2D);
+			// Loop over all beam tilts
+			int n_tilts = 0;
+			int n_steps = CEIL(beamtilt_max / beamtilt_step);
+			for (double tilt_y = -n_steps*beamtilt_step; tilt_y <= n_steps*beamtilt_step; tilt_y += beamtilt_step)
+			{
+				for (double tilt_x = -n_steps*beamtilt_step; tilt_x <= n_steps*beamtilt_step; tilt_x += beamtilt_step)
+				{
+					if (sqrt(tilt_y*tilt_y + tilt_x*tilt_x) <= beamtilt_max)
+					{
+						// Now calculate the squared differences, taking the beamtilt into account
+						applyBeamTilt(F2D, F2Dtilt, tilt_x, tilt_y, ctf.lambda, ctf.Cs, angpix, image_size);
+
+						double diff2 = 0.;
+						double ndiff = 0.;
+						FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM2D(F2Dtilt)
+						{
+							// Store amplitude-weighted phase difference and sum of amplitude-weights
+							double res = xsize/sqrt((double)(ip * ip + jp * jp)); // get resolution in 1/pixel
+							if (res <= minres_beamtilt && res >= maxres_model)
+							{
+
+								double diff_real = (DIRECT_A2D_ELEM(Fref, i, j)).real - (DIRECT_A2D_ELEM(F2Dtilt, i, j)).real;
+								double diff_imag = (DIRECT_A2D_ELEM(Fref, i, j)).imag - (DIRECT_A2D_ELEM(F2Dtilt, i, j)).imag;
+								diff2 += (diff_real * diff_real + diff_imag * diff_imag);
+								ndiff += 1.;
+							}
+						}
+						diff2 /= ndiff;
+
+						// Store the accumulate weighted differences...
+						DIRECT_A2D_ELEM(diff2_beamtilt, i_group, n_tilts) += diff2;
+
+						n_tilts++;
+						if (n_tilts > nr_sampled_beam_tilts)
+						{
+							std::cerr << " n_tilts= " << n_tilts << " nr_sampled_beam_tilts= " << nr_sampled_beam_tilts << " beamtilt_max= " << beamtilt_max << std::endl;
+							std::cerr << " tilt_x= " << tilt_x << " tilt_y= " << tilt_y << " beamtilt_step= " << beamtilt_step << std::endl;
+							REPORT_ERROR("BUG: too large n_tilts....");
+						}
+
+					} // end if sqrt(tilt_y*tilt_y + tilt_x*tilt_x) <= beamtilt_max
+				} // end for tilt_x
+			} // end for tilt_y
+		} // end if beamtilt_max > 0
+
+	} // end for over all particles in this micrograph
+
+
+
+	// Set optimal defocus shift averaged over all particles in this micrograph:
+	if (defocus_shift_max > 0.)
+	{
+		double mindiff2=99.e99, best_defocus_shift;
+		int n_defocus = 0;
+		for (double defocus_shift = -nr_sampled_defocus_shifts*defocus_shift_step;
+				defocus_shift <= nr_sampled_defocus_shifts*defocus_shift_step;
+				defocus_shift += defocus_shift_step)
+		{
+			double diff2 = DIRECT_A1D_ELEM(wdiff2_defocus, n_defocus);
+			//std::cerr << std::setprecision(10) << " imic= " << imic << " defocus_shift= " << defocus_shift << " diff2= " << diff2 << std::endl;
+			if (diff2 < mindiff2)
+			{
+				mindiff2 = diff2;
+				best_defocus_shift = defocus_shift;
+			}
+			n_defocus++;
+		}
+		DIRECT_A1D_ELEM(defocus_shift_allmics, imic) = best_defocus_shift;
+
+		//exp_model.MDimg.setValue(EMDL_CTF_DEFOCUSU, ori_defocusU + best_defocus_shift, img_id);
+		//exp_model.MDimg.setValue(EMDL_CTF_DEFOCUSV, ori_defocusV + best_defocus_shift, img_id);
+		// Set best defocus for all particles on this micrograph
+		// TODO: this only works in sequential version!!!
+		for (long int iimg = 0; iimg < exp_model.micrographs[imic].images.size(); iimg++)
+		{
+
+			long int img_id = exp_model.micrographs[imic].images[iimg].id;
+			double ori_defocusU, ori_defocusV;
+			exp_model.MDimg.getValue(EMDL_CTF_DEFOCUSU, ori_defocusU, img_id);
+			exp_model.MDimg.getValue(EMDL_CTF_DEFOCUSV, ori_defocusV, img_id);
+
+
+			exp_model.MDimg.setValue(EMDL_CTF_DEFOCUSU, ori_defocusU + best_defocus_shift, img_id);
+			exp_model.MDimg.setValue(EMDL_CTF_DEFOCUSV, ori_defocusV + best_defocus_shift, img_id);
+		}
+
+	}
+}
+
+void ParticlePolisher::run()
+{
+
+	// Fit straight lines through all beam-induced translations
+	if (fitting_mode != NO_FIT)
+		fitMovementsAllMicrographs();
+
+	// Perform single-frame reconstructions and estimate dose-dependent B-factors
+	if (do_weighting)
+		calculateAllSingleFrameReconstructionsAndBfactors();
+
+	// Write out the intermediately polished particles
+	polishParticlesAllMicrographs();
+
+	// Now reconstruct with all polished particles: two independent halves, FSC-weighting of the sum of the two...
+	reconstructShinyParticlesAndFscWeight(1);
+
+	// Optimise beam-tilt and defocus per beamtilt group and/or micrograph
+	optimiseBeamTiltAndDefocus();
+
+	// Reconstruct again two halves to see whether the beamtilt and/or defocus optimisation has helped
+	if (beamtilt_max > 0. || defocus_shift_max > 0.)
+		reconstructShinyParticlesAndFscWeight(2);
+
+	if (verb > 0)
+		std::cout << " done!" << std::endl;
+
+}
+
+
diff --git a/src/particle_polisher.h b/src/particle_polisher.h
new file mode 100644
index 0000000..cd7925c
--- /dev/null
+++ b/src/particle_polisher.h
@@ -0,0 +1,225 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef PARTICLE_POLISHER_H_
+#define PARTICLE_POLISHER_H_
+#include "src/image.h"
+#include "src/metadata_table.h"
+#include "src/exp_model.h"
+#include <src/fftw.h>
+#include <src/time.h>
+#include <src/mask.h>
+#include <src/funcs.h>
+#include <src/backprojector.h>
+#include <src/ctf.h>
+#include <src/postprocessing.h>
+
+#define LINEAR_FIT 0
+#define LOGARITHMIC_FIT 1
+#define SQRT_FIT 2
+#define NO_FIT 3
+
+class ParticlePolisher
+{
+public:
+
+	// I/O Parser
+	IOParser parser;
+
+	// Verbosity
+	int verb;
+
+	// Input & Output rootname
+	FileName fn_in, fn_out, fn_sym, fn_mask;
+
+	// The experimental model
+	Experiment exp_model;
+
+	// Standard deviation for a Gaussian-weight on the distance between particles in the micrograph
+	double sigma_neighbour_distance;
+
+	// Maximum resolution in pre-frame reconstructions
+	double perframe_highres;
+
+	// Flag to indicate all calculations have to be repeated from scratch
+	// if false, then intermediate files are re-read from disc and earlier calculations are skipped
+	bool do_start_all_over;
+
+	// First and last frame numbers to include in the average
+	int first_frame, last_frame;
+
+	// Which fitting mode (lienar/logarithmic/nofit)
+	int fitting_mode;
+
+	// Running average window with used for the determination of the frame movements
+	// This will be used to exclude the first and last few frames from the fit (but not from the polsihing!)
+	int running_average_width;
+
+	// CTF stuff for the reconstructions
+	bool do_ctf, ctf_phase_flipped, only_flip_phases, intact_ctf_first_peak;
+
+	// Pixel size (for B-factors)
+	double angpix;
+
+	// Original image size
+	int ori_size;
+
+	// Skip B-factor weighting
+	bool do_weighting;
+
+	// Minimum resolution (in Angstrom) for fitting of B-factor in Guinier plot
+	double fit_minres;
+
+	// Width of a running average window for the single-frame reconstructions
+	int frame_running_average;
+
+	// Vector with the B-factors for all individual frames
+	MultidimArray<double> perframe_bfactors;
+
+	// Fitted movement coordinates for all input images
+	MultidimArray<double> fitted_movements;
+
+	// Image with the mask (used for relative weighting of each frame)
+	Image<double> Imask;
+
+	// FSC curve of the masked, averages of all single-frame reconstructions
+	MultidimArray<double> fsc_average;
+
+	// Metadatatable with the information from the polished particles
+	MetaDataTable MDshiny;
+
+	// Tabulated sin and cosine functions for shifts in Fourier space
+	TabSine tab_sin;
+	TabCosine tab_cos;
+
+	// Reference volume reconstructed from the initially-polished particles to be used for per-particle CTF-refinement and beamtilt-refinement
+	Projector PPrefvol_half1, PPrefvol_half2;
+
+	// Normalise the polished particles?
+	bool do_normalise;
+
+	// Radius of the background-circle for noise normalisation (in pixels)
+	int bg_radius;
+
+	// Sigma-levels for dust removal
+	double white_dust_stddev, black_dust_stddev;
+
+	// Maximum useful resolution in the reconstruction
+	double maxres_model;
+
+	// Maximum beam tilt to analyse, and step-size to sample in X and Y
+	double beamtilt_max, beamtilt_step;
+	// Number of sampled beamtilts
+	int nr_sampled_beam_tilts;
+
+	// Names of the data sets to be separated in the beamtilt refinement
+	std::vector<FileName> fn_beamtilt_groups;
+
+	// Minimum resolution to take beamtilt into account
+	double minres_beamtilt;
+
+	// Weighted squared-differences for all beamtilts
+	MultidimArray<double> diff2_beamtilt;
+
+	// Weighted squared-differences for all defocus values
+	MultidimArray<double> defocus_shift_allmics;
+
+	// Optimal beamtilts for each data set
+	std::vector<Matrix1D<double> > best_beamtilts;
+
+	// Per-particle CTF optimisation
+	double defocus_shift_max, defocus_shift_step;
+
+
+public:
+	// Read command line arguments
+	void read(int argc, char **argv);
+
+	// Print usage instructions
+	void usage();
+
+	// Initialise some stuff after reading
+	void initialise();
+
+	// General Running
+	void run();
+
+	// Fit the beam-induced translations for all average micrographs
+	void fitMovementsAllMicrographs();
+
+	// Fit a function through th observed movements
+	void fitMovementsOneMicrograph(long int imic);
+
+	// Get the B-factor for all single-frame reconstruction
+	void calculateAllSingleFrameReconstructionsAndBfactors();
+
+	// Read/write of STAR file with all per-frame B-factors
+	bool readStarFileBfactors(FileName fn_star);
+	void writeStarFileBfactors(FileName fn_star);
+
+	// Write out an additional STAR file with the resolution-dependent, relative weights per frame
+	void writeStarFileRelativeWeights(FileName fn_star);
+
+	// Get the B-factor for a single-frame reconstruction
+	void calculateSingleFrameReconstruction(int iframe, int ihalf);
+
+	// Run standard post-processing (only unmasked FSC  on the single-frame reconstruction.
+	void postProcessSingleFrameReconstruction(int this_frame);
+
+	// Calculate the B-factors for a single-frame reconstruction
+	void calculateBfactorSingleFrameReconstruction(int this_frame, double &bfactor, double &offset, double &corr_coeff);
+
+	// Calculate the average of all single-frame rconstructions (for a given half)
+	void calculateAverageAllSingleFrameReconstructions(int ihalf);
+
+	// Movie frame re-alignment for a single micrograph
+	void polishParticlesOneMicrograph(long int imic);
+
+	// Movie frame re-alignment for all micrographs
+	void polishParticlesAllMicrographs();
+
+	// Write out the resulting STAR files
+	void writeStarFilePolishedParticles();
+
+	// Reconstruct the two independent halves of the shiny particles
+	void reconstructShinyParticlesAndFscWeight(int ipass);
+
+	// Reconstruct one half of the shiny particles
+	void reconstructShinyParticlesOneHalf(int ihalf);
+
+	// Optimize the beam tilt and defocus for all beamtilt groups and/or micrographs
+	void optimiseBeamTiltAndDefocus();
+
+	// Optimisation for each micrograph (may be run in parallel)
+	void optimiseBeamTiltAndDefocusOneMicrograph(int imic);
+
+	// After optimising, one general function to set results in the MetaDataTable (because optimisation may have been done in parallel)
+	void applyOptimisedBeamTiltsAndDefocus();
+
+	// Optimise beamtilt separately for datasets in different directories
+	void getBeamTiltGroups();
+
+	// Initialise some arrays for parallelisation purposes
+	void initialiseSquaredDifferenceVectors();
+};
+
+
+
+#endif /* PARTICLE_POLISHER_H_ */
diff --git a/src/particle_polisher_mpi.cpp b/src/particle_polisher_mpi.cpp
new file mode 100644
index 0000000..477cd00
--- /dev/null
+++ b/src/particle_polisher_mpi.cpp
@@ -0,0 +1,428 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/particle_polisher_mpi.h"
+
+void ParticlePolisherMpi::read(int argc, char **argv)
+{
+    // Define a new MpiNode
+    node = new MpiNode(argc, argv);
+
+    // First read in non-parallelisation-dependent variables
+    ParticlePolisher::read(argc, argv);
+
+    // Don't put any output to screen for mpi slaves
+    verb = (node->isMaster()) ? verb : 0;
+
+    // Possibly also read parallelisation-dependent variables here
+
+	if (node->size < 2)
+		REPORT_ERROR("ParticlePolisherMpi::read ERROR: this program needs to be run with at least two MPI processes!");
+
+    // Print out MPI info
+	printMpiNodesMachineNames(*node);
+
+
+}
+// Fit the beam-induced translations for all average micrographs
+void ParticlePolisherMpi::fitMovementsAllMicrographs()
+{
+
+	int total_nr_micrographs = exp_model.average_micrographs.size();
+
+	// Each node does part of the work
+	long int my_first_micrograph, my_last_micrograph, my_nr_micrographs;
+	divide_equally(total_nr_micrographs, node->size, node->rank, my_first_micrograph, my_last_micrograph);
+	my_nr_micrographs = my_last_micrograph - my_first_micrograph + 1;
+
+	// Loop over all average micrographs
+	int barstep;
+	if (verb > 0)
+	{
+		std::cout << " + Fitting straight paths for beam-induced movements in all micrographs ... " << std::endl;
+		init_progress_bar(my_nr_micrographs);
+		barstep = XMIPP_MAX(1, my_nr_micrographs/ 60);
+	}
+
+	for (long int i = my_first_micrograph; i <= my_last_micrograph; i++)
+	{
+    	if (verb > 0 && i % barstep == 0)
+			progress_bar(i);
+
+		fitMovementsOneMicrograph(i);
+	}
+
+	// Wait until all micrographs have been done
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	if (verb > 0)
+	{
+		progress_bar(my_nr_micrographs);
+	}
+
+	// Combine results from all nodes
+	MultidimArray<double> allnodes_fitted_movements;
+	allnodes_fitted_movements.resize(fitted_movements);
+	MPI_Allreduce(MULTIDIM_ARRAY(fitted_movements), MULTIDIM_ARRAY(allnodes_fitted_movements), MULTIDIM_SIZE(fitted_movements), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
+	fitted_movements = allnodes_fitted_movements;
+
+    // Set the fitted movements in the xoff and yoff columns of the exp_model.MDimg
+    for (int ipart = 0; ipart < exp_model.numberOfParticles(); ipart++)
+	{
+		long int part_id = exp_model.particles[ipart].id;
+		long int img_id = exp_model.getImageId(part_id, 0);
+		double xoff = DIRECT_A2D_ELEM(fitted_movements, img_id, 0);
+		double yoff = DIRECT_A2D_ELEM(fitted_movements, img_id, 1);
+		exp_model.MDimg.setValue(EMDL_ORIENT_ORIGIN_X, xoff, img_id);
+		exp_model.MDimg.setValue(EMDL_ORIENT_ORIGIN_Y, yoff, img_id);
+	}
+
+    if (node->isMaster())
+    {
+		// Write out the STAR file with all the fitted movements
+		FileName fn_tmp = fn_in.withoutExtension() + "_" + fn_out + ".star";
+		exp_model.MDimg.write(fn_tmp);
+		std::cout << " + Written out all fitted movements in STAR file: " << fn_tmp << std::endl;
+    }
+
+
+}
+
+void ParticlePolisherMpi::calculateAllSingleFrameReconstructionsAndBfactors()
+{
+
+	FileName fn_star = fn_in.withoutExtension() + "_" + fn_out + "_bfactors.star";
+	if (!do_start_all_over && readStarFileBfactors(fn_star))
+	{
+		if (verb > 0)
+			std::cout << " + " << fn_star << " already exists: skipping calculation average of per-frame B-factors." <<std::endl;
+		return;
+	}
+
+	double bfactor, offset, corr_coeff;
+
+	int total_nr_frames = last_frame - first_frame + 1;
+	long int my_first_frame, my_last_frame, my_nr_frames;
+
+	// Loop over all frames (two halves for each frame!) to be included in the reconstruction
+	// Each node does part of the work
+	divide_equally(2*total_nr_frames, node->size, node->rank, my_first_frame, my_last_frame);
+	my_nr_frames = my_last_frame - my_first_frame + 1;
+
+	if (verb > 0)
+	{
+		std::cout << " + Calculating per-frame reconstructions ... " << std::endl;
+		init_progress_bar(my_nr_frames);
+	}
+
+	for (long int i = my_first_frame; i <= my_last_frame; i++)
+	{
+
+		int iframe = (i >= total_nr_frames) ? i - total_nr_frames : i;
+		iframe += first_frame;
+		int ihalf = (i >= total_nr_frames) ? 2 : 1;
+
+		calculateSingleFrameReconstruction(iframe, ihalf);
+
+    	if (verb > 0)
+    		progress_bar(i - my_first_frame + 1);
+	}
+
+	if (verb > 0)
+	{
+		progress_bar(my_nr_frames);
+	}
+
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	// Also calculate the average of all single-frames for both halves
+    if (node->rank == 0)
+    	calculateAverageAllSingleFrameReconstructions(1);
+    else if (node->rank == 1)
+    	calculateAverageAllSingleFrameReconstructions(2);
+
+	// Wait until all reconstructions have been done, and calculate the B-factors per-frame
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	calculateBfactorSingleFrameReconstruction(-1, bfactor, offset, corr_coeff); // FSC between the two averages, also reads mask
+
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	// Loop over all frames (two halves for each frame!) to be included in the reconstruction
+	// Each node does part of the work
+	divide_equally(total_nr_frames, node->size, node->rank, my_first_frame, my_last_frame);
+	my_nr_frames = my_last_frame - my_first_frame + 1;
+
+	if (verb > 0)
+	{
+		std::cout << " + Calculating per-frame B-factors ... " << std::endl;
+		init_progress_bar(my_nr_frames);
+	}
+
+	for (long int i = first_frame+my_first_frame; i <= first_frame+my_last_frame; i++)
+	{
+
+		calculateBfactorSingleFrameReconstruction(i, bfactor, offset, corr_coeff);
+		int iframe = i - first_frame;
+		DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 0) = bfactor;
+       	DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 1) = offset;
+       	DIRECT_A1D_ELEM(perframe_bfactors, iframe * 3 + 2) = corr_coeff;
+
+    	if (verb > 0)
+    		progress_bar(i - first_frame - my_first_frame + 1);
+	}
+
+	// Combine results from all nodes
+	MultidimArray<double> allnodes_perframe_bfactors;
+	allnodes_perframe_bfactors.resize(perframe_bfactors);
+	MPI_Allreduce(MULTIDIM_ARRAY(perframe_bfactors), MULTIDIM_ARRAY(allnodes_perframe_bfactors), MULTIDIM_SIZE(perframe_bfactors), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
+	perframe_bfactors = allnodes_perframe_bfactors;
+
+	if (verb > 0)
+	{
+		progress_bar(my_nr_frames);
+		writeStarFileBfactors(fn_star);
+
+	    // Also write a STAR file with the relative contributions of each frame to all frequencies
+	    fn_star = fn_in.withoutExtension() + "_" + fn_out + "_relweights.star";
+	    writeStarFileRelativeWeights(fn_star);
+	}
+
+}
+
+void ParticlePolisherMpi::polishParticlesAllMicrographs()
+{
+
+	if (!do_start_all_over && exists(fn_out + ".star"))
+	{
+		if (verb > 0)
+			std::cout << std::endl << " + " << fn_out << ".star already exists: skipping polishing of the particles." << std::endl;
+		return;
+	}
+
+	int total_nr_micrographs = exp_model.average_micrographs.size();
+
+	// Each node does part of the work
+	long int my_first_micrograph, my_last_micrograph, my_nr_micrographs;
+	divide_equally(total_nr_micrographs, node->size, node->rank, my_first_micrograph, my_last_micrograph);
+	my_nr_micrographs = my_last_micrograph - my_first_micrograph + 1;
+
+	// Loop over all average micrographs
+	int barstep;
+	if (verb > 0)
+	{
+		std::cout << " + Write out polished particles for all micrographs ... " << std::endl;
+		init_progress_bar(my_nr_micrographs);
+		barstep = XMIPP_MAX(1, my_nr_micrographs/ 60);
+	}
+
+    for (long int i = my_first_micrograph; i <= my_last_micrograph; i++)
+	{
+    	if (verb > 0 && i % barstep == 0)
+			progress_bar(i);
+
+    	polishParticlesOneMicrograph(i);
+	}
+
+   	if (verb > 0)
+   		progress_bar(my_nr_micrographs);
+
+    if (node->isMaster())
+    	writeStarFilePolishedParticles();
+
+    MPI_Barrier(MPI_COMM_WORLD);
+
+}
+
+void ParticlePolisherMpi::reconstructShinyParticlesAndFscWeight(int ipass)
+{
+	if (verb > 0)
+		std::cout << "+ Reconstructing two halves of shiny particles ..." << std::endl;
+
+	// Re-read the shiny particles' metadatatable
+	exp_model.read(fn_out + ".star");
+
+	 // Do the reconstructions for both halves
+	if (node->rank == 0)
+		reconstructShinyParticlesOneHalf(1);
+	else if (node->rank == 1)
+		reconstructShinyParticlesOneHalf(2);
+
+	// Wait until both reconstructions have been done
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	// Only the master performs the FSC-weighting
+	FileName fn_post = (ipass == 1) ? "_post" : "_post2";
+	if (node->rank == 0)
+	{
+
+		if (!do_start_all_over && exists(fn_in.withoutExtension() + "_" + fn_out + fn_post + "_masked.mrc")
+						       && exists(fn_in.withoutExtension() + "_" + fn_out + fn_post + ".star") )
+		{
+			if (verb > 0)
+				std::cout << std::endl << " + " << fn_in.withoutExtension() << "_" << fn_out << fn_post << "_masked.mrc already exists: re-reading map into memory." << std::endl;
+
+			if (verb > 0)
+				std::cout << std::endl << " + " << fn_in.withoutExtension() << "_" << fn_out << fn_post << ".star already exists: re-reading resolution from it." << std::endl;
+
+			MetaDataTable MD;
+			MD.read(fn_in.withoutExtension() + "_" + fn_out + fn_post + ".star", "general");
+			MD.getValue(EMDL_POSTPROCESS_FINAL_RESOLUTION, maxres_model);
+		}
+		else
+		{
+			// Re-read the two halves to calculate FSCs
+			Postprocessing prm;
+
+			prm.clear();
+			prm.fn_in = fn_in.withoutExtension() + "_" + fn_out;
+			prm.fn_out = prm.fn_in + fn_post;
+			prm.angpix = angpix;
+			prm.do_auto_mask = false;
+			prm.fn_mask = fn_mask;
+			prm.do_auto_bfac = false;
+			prm.do_fsc_weighting = true;
+			prm.run();
+
+			maxres_model = prm.global_resol;
+		}
+	}
+
+	// Wait until the FSC-weighting has been done
+	MPI_Barrier(MPI_COMM_WORLD);
+
+	MultidimArray<double> dum;
+	Image<double> refvol;
+	FileName fn_vol;
+	fn_vol = fn_in.withoutExtension() + "_" + fn_out + "_half1_class001_unfil.mrc";
+	refvol.read(fn_vol);
+	PPrefvol_half1.ori_size = XSIZE(refvol());
+	PPrefvol_half1.padding_factor = 2;
+	PPrefvol_half1.interpolator = TRILINEAR;
+	PPrefvol_half1.r_min_nn = 10;
+	PPrefvol_half1.computeFourierTransformMap(refvol(), dum);
+	fn_vol = fn_in.withoutExtension() + "_" + fn_out + "_half2_class001_unfil.mrc";
+	refvol.read(fn_vol);
+	PPrefvol_half2.ori_size = XSIZE(refvol());
+	PPrefvol_half2.padding_factor = 2;
+	PPrefvol_half2.interpolator = TRILINEAR;
+	PPrefvol_half2.r_min_nn = 10;
+	PPrefvol_half2.computeFourierTransformMap(refvol(), dum);
+
+}
+
+void ParticlePolisherMpi::optimiseBeamTilt()
+{
+
+	// This function assumes the shiny particles are in exp_mdel.MDimg!!
+
+	if (beamtilt_max <= 0. && defocus_shift_max <= 0.)
+		return;
+
+	if (minres_beamtilt < maxres_model)
+	{
+		if (verb > 0)
+			std::cout << " Skipping beamtilt correction, as the resolution of the shiny reconstruction  does not go beyond minres_beamtilt of " << minres_beamtilt << " Ang." << std::endl;
+		return;
+	}
+
+	getBeamTiltGroups();
+
+	initialiseSquaredDifferenceVectors();
+
+	int total_nr_micrographs = exp_model.micrographs.size();
+
+	// Each node does part of the work
+	long int my_first_micrograph, my_last_micrograph, my_nr_micrographs;
+	divide_equally(total_nr_micrographs, node->size, node->rank, my_first_micrograph, my_last_micrograph);
+	my_nr_micrographs = my_last_micrograph - my_first_micrograph + 1;
+
+	// Loop over all average micrographs
+	int barstep;
+	if (verb > 0)
+	{
+		std::cout << " + Optimising beamtilts and/or defocus values in all micrographs ... " << std::endl;
+		init_progress_bar(my_nr_micrographs);
+		barstep = XMIPP_MAX(1, my_nr_micrographs/ 60);
+	}
+
+    for (long int i = my_first_micrograph; i <= my_last_micrograph; i++)
+	{
+    	if (verb > 0 && i % barstep == 0)
+			progress_bar(i);
+
+    	optimiseBeamTiltAndDefocusOneMicrograph(i);
+	}
+
+   	if (verb > 0)
+   		progress_bar(my_nr_micrographs);
+
+	// Combine results from all nodes
+	if (beamtilt_max > 0.)
+	{
+		MultidimArray<double> allnodes_diff2_beamtilt;
+		allnodes_diff2_beamtilt.initZeros(diff2_beamtilt);
+		MPI_Allreduce(MULTIDIM_ARRAY(diff2_beamtilt), MULTIDIM_ARRAY(allnodes_diff2_beamtilt), MULTIDIM_SIZE(diff2_beamtilt), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
+		diff2_beamtilt = allnodes_diff2_beamtilt;
+	}
+
+	if (defocus_shift_max > 0.)
+	{
+		MultidimArray<double> allnodes_defocus_shift_allmics;
+		allnodes_defocus_shift_allmics.initZeros(defocus_shift_allmics);
+		MPI_Allreduce(MULTIDIM_ARRAY(defocus_shift_allmics), MULTIDIM_ARRAY(allnodes_defocus_shift_allmics), MULTIDIM_SIZE(defocus_shift_allmics), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
+		defocus_shift_allmics = allnodes_defocus_shift_allmics;
+	}
+
+	// Now get the final optimised beamtilts and defocus shifts, and write results to the MetadataTable
+	applyOptimisedBeamTiltsAndDefocus();
+
+	// Write the new MDTable to disc
+	if (verb > 0)
+		exp_model.MDimg.write(fn_out + ".star");
+
+}
+
+void ParticlePolisherMpi::run()
+{
+	// Fit straight lines through all beam-induced translations
+	if (fitting_mode != NO_FIT)
+		fitMovementsAllMicrographs();
+
+	// Perform single-frame reconstructions to estimate dose-dependent B-factors
+	if (do_weighting)
+            calculateAllSingleFrameReconstructionsAndBfactors();
+
+	// Write out the polished particles
+	polishParticlesAllMicrographs();
+
+	// Now reconstruct with all polished particles: two independent halves, FSC-weighting of the sum of the two...
+	reconstructShinyParticlesAndFscWeight(1);
+
+	// Optimise beam-tilt and defocus per beamtilt group and/or micrograph
+	optimiseBeamTiltAndDefocus();
+
+	// Reconstruct again two halves to see whether the beamtilt and/or defocus optimisation has helped
+	if (beamtilt_max > 0. || defocus_shift_max > 0.)
+		reconstructShinyParticlesAndFscWeight(2);
+
+	if (verb > 0)
+		std::cout << " done!" << std::endl;
+
+}
diff --git a/src/particle_polisher_mpi.h b/src/particle_polisher_mpi.h
new file mode 100644
index 0000000..a2fdf71
--- /dev/null
+++ b/src/particle_polisher_mpi.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef PARTICLE_POLISHER_MPI_H_
+#define PARTICLE_POLISHER_MPI_H_
+
+#include "src/mpi.h"
+#include "src/parallel.h"
+#include "src/particle_polisher.h"
+
+class ParticlePolisherMpi : public ParticlePolisher
+{
+private:
+	MpiNode *node;
+
+public:
+	/** Destructor, calls MPI_Finalize */
+    ~ParticlePolisherMpi()
+    {
+        delete node;
+    }
+
+    /** Read
+     * This could take care of mpi-parallelisation-dependent variables
+     */
+    void read(int argc, char **argv);
+
+	// Parallelized fit the beam-induced translations for all average micrographs
+	void fitMovementsAllMicrographs();
+
+	// Parallelized calculation of B-factors for single-frame reconstructions
+	void calculateAllSingleFrameReconstructionsAndBfactors();
+
+	// Parallelized movie frame re-alignment for all micrographs
+	void polishParticlesAllMicrographs();
+
+	// Calculate two half-reconstructions from shiny particles and calculate FSC-weighted average map, store that in refvol
+	void reconstructShinyParticlesAndFscWeight(int ipass);
+
+	// Parallelized optimisation of beamtilt for all micrographs
+	void optimiseBeamTilt();
+
+	// Parallelized run function
+    void run();
+
+};
+
+
+
+#endif /* PARTICLE_POLISHER_MPI_H_ */
diff --git a/src/particle_sorter.cpp b/src/particle_sorter.cpp
new file mode 100644
index 0000000..ca46b82
--- /dev/null
+++ b/src/particle_sorter.cpp
@@ -0,0 +1,693 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/particle_sorter.h"
+//#define DEBUG
+
+void ParticleSorter::read(int argc, char **argv)
+{
+
+	parser.setCommandLine(argc, argv);
+
+	int gen_section = parser.addSection("General options");
+	fn_in = parser.getOption("--i", "Input STAR file ");
+	fn_ref = parser.getOption("--ref", "STAR file with the reference names, or an MRC stack with all references");
+	fn_out = parser.getOption("--o", "Output rootname (if empty the input file will be overwritten)", "");
+	angpix = textToFloat(parser.getOption("--angpix", "Pixel size in Angstroms"));
+	particle_diameter = textToFloat(parser.getOption("--particle_diameter", "Diameter of the circular mask that will be applied to the experimental images (in Angstroms)"));
+	lowpass = textToFloat(parser.getOption("--lowpass", "Lowpass filter in Angstroms for the references (prevent Einstein-from-noise!)","-1"));
+	do_invert = parser.checkOption("--invert", "Density in particles is inverted w.r.t. density in template");
+	do_ctf = parser.checkOption("--ctf", "Perform CTF correction on the references?");
+	intact_ctf_first_peak = parser.checkOption("--ctf_intact_first_peak", "Ignore CTFs until their first peak?");
+	min_z = textToFloat(parser.getOption("--min_z", "Minimum Z-value to count in the sorting of outliers","0"));
+
+	int expert_section = parser.addSection("Expert options");
+	verb = textToInteger(parser.getOption("--verb", "Verbosity", "1"));
+
+	// Check for errors in the command-line option
+	if (parser.checkForErrors())
+		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+}
+
+void ParticleSorter::usage()
+{
+	parser.writeUsage(std::cerr);
+}
+
+void ParticleSorter::initialise()
+{
+
+	// Read in input metadata file
+	MDin.read(fn_in);
+
+	if (fn_out != "")
+		fn_out = fn_in.withoutExtension() + "_" + fn_out;
+	else
+		fn_out = fn_in.withoutExtension();
+
+	// Read in the references
+	Mrefs.clear();
+	if (fn_ref.isStarFile())
+	{
+
+		MetaDataTable MDref;
+		if (fn_ref.contains("_model.star"))
+		{
+			MDref.read(fn_ref, "model_classes");
+		}
+		else
+		{
+			// Just read normal STAR file with user-provided references
+			MDref.read(fn_ref);
+		}
+
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDref)
+		{
+			// Get all reference images and their names
+			Image<double> Iref;
+
+			FileName fn_img;
+			if (!MDref.getValue(EMDL_MLMODEL_REF_IMAGE, fn_img))
+			{
+				if (!MDref.getValue(EMDL_IMAGE_NAME, fn_img)) // perhaps the reference are called rlnImageName?
+					REPORT_ERROR("ParticleSorter::initialise ERROR: either provide rlnReferenceImage or rlnImageName in the reference STAR file!");
+			}
+			Iref.read(fn_img);
+			Iref().setXmippOrigin();
+			Mrefs.push_back(Iref());
+		}
+	}
+	else
+	{
+		Image<double> Istk, Iref;
+		Istk.read(fn_ref);
+		for (int n = 0; n < NSIZE(Istk()); n++)
+		{
+			Istk().getImage(n, Iref());
+			Iref().setXmippOrigin();
+			Mrefs.push_back(Iref());
+		}
+	}
+
+	particle_size = XSIZE(Mrefs[0]);
+
+	// Get the squared particle radius (in integer pixels)
+	particle_radius2 = ROUND(particle_diameter/(2. * angpix));
+	particle_radius2*= particle_radius2;
+
+	// Invert references if necessary (do this AFTER automasking them!)
+	if (do_invert)
+	{
+		for (int iref = 0; iref < Mrefs.size(); iref++)
+		{
+			Mrefs[iref] *= -1.;
+		}
+	}
+
+
+	// Calculate the size of the FTs given the low-pass filter
+	if (lowpass < 0.)
+	{
+		lowpass = 2. * angpix;
+		current_size = particle_size;
+	}
+	else
+	{
+		current_size = 2 * ROUND(particle_size * angpix / lowpass);
+	}
+
+	// Calculate (downsized) Fourier transforms of the references
+	PPref.clear();
+	MultidimArray<double> dummy;
+	Projector projector(particle_size);
+	for (int iref = 0; iref < Mrefs.size(); iref++)
+	{
+		projector.computeFourierTransformMap(Mrefs[iref], dummy, current_size);
+		PPref.push_back(projector);
+	}
+
+#ifdef DEBUG
+	std::cerr << "Finishing initialise" << std::endl;
+#endif
+}
+
+void ParticleSorter::run()
+{
+
+
+	int nr_parts = MDin.numberOfObjects();
+	features.resize(nr_parts, NR_FEATURES);
+
+	int barstep;
+	if (verb > 0)
+	{
+		std::cout << "Calculating sorting features for all input particles..." << std::endl;
+		init_progress_bar(nr_parts);
+		barstep = XMIPP_MAX(1, nr_parts / 60);
+	}
+
+	long int ipart = 0;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDin)
+	{
+
+		if (verb > 0 && ipart % barstep == 0)
+			progress_bar(ipart);
+
+		calculateFeaturesOneParticle(ipart);
+
+	    ipart++;
+	}
+
+	if (verb > 0)
+		progress_bar(nr_parts);
+
+	normaliseFeatures();
+
+	writeFeatures();
+
+
+}
+
+void ParticleSorter::calculateFeaturesOneParticle(long int ipart)
+{
+
+	FourierTransformer transformer;
+	Image<double> img;
+	MultidimArray<double> Mref_rot;
+	MultidimArray<Complex > Fimg, Fref;
+
+	// Get the image
+	FileName fn_img;
+	MDin.getValue(EMDL_IMAGE_NAME, fn_img, ipart);
+	img.read(fn_img);
+
+	if (XSIZE(img()) != particle_size)
+	{
+		std::cerr << " fn_img= " << fn_img << " XSIZE(img())= " << XSIZE(img()) << " reference size= " << particle_size << std::endl;
+		REPORT_ERROR("ParticleSorter::calculateFeaturesOneParticle ERROR: References and images do not have the same size!");
+	}
+#ifdef DEBUG
+	std::cerr << " fn_img= " << fn_img << std::endl;
+	Image<double> tt;
+	tt = img;
+	tt.write("debug_ori_image.spi");
+#endif
+
+	// If the particle has non-zero shifts, then apply the rounded shifts here!
+	Matrix1D<double> offset(2);
+	MDin.getValue(EMDL_ORIENT_ORIGIN_X, XX(offset), ipart);
+	MDin.getValue(EMDL_ORIENT_ORIGIN_Y, YY(offset), ipart);
+	offset.selfROUND();
+	if ( ABS(XX(offset)) > 0. || ABS(YY(offset)) > 0.)
+		selfTranslate(img(), offset, DONT_WRAP);
+
+#ifdef DEBUG
+	tt = img;
+	tt.write("debug_trans_image.spi");
+#endif
+
+	// Low-pass filter the image if necessary
+	if (lowpass > 0.)
+	{
+		double radius = XSIZE(img()) * angpix / lowpass;
+		radius -= WIDTH_FMASK_EDGEB / 2.;
+		double radius_p = radius + WIDTH_FMASK_EDGEB;
+		transformer.FourierTransform(img(), Fimg);
+		FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Fimg)
+		{
+			double r = sqrt((double)(kp*kp + ip*ip + jp*jp));
+			if (r < radius)
+				continue;
+			else if (r > radius_p)
+				DIRECT_A3D_ELEM(Fimg, k, i, j) = 0.;
+			else
+			{
+				DIRECT_A3D_ELEM(Fimg, k, i, j) *= 0.5 - 0.5 * cos(PI * (radius_p - r) / WIDTH_FMASK_EDGEB);
+			}
+		}
+		transformer.inverseFourierTransform(Fimg, img());
+	}
+
+#ifdef DEBUG
+	tt = img;
+	tt.write("debug_lowpass_image.spi");
+#endif
+
+	// Get the transformation parameters and which reference this is
+	double psi = 0.;
+	double rot = 0.;
+	double tilt = 0.;
+	int iref;
+	MDin.getValue(EMDL_ORIENT_ROT, rot, ipart);
+	MDin.getValue(EMDL_ORIENT_TILT, tilt, ipart);
+	MDin.getValue(EMDL_ORIENT_PSI, psi, ipart);
+	if (!MDin.getValue(EMDL_PARTICLE_CLASS, iref, ipart) && PPref.size() > 1)
+		REPORT_ERROR("ParticleSorter::calculateFeatures: cannot find class number in input STAR file");
+
+	// Manually added particles were given a class number of -999 in the relion_display program
+	// These particles should be OK, and therefore will be at the top of the sorted list
+	if (iref == -999)
+	{
+		DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_AVG) = 0.;
+		DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_SIG) = 0.;
+		DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_SKW) = 0.;
+		DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_KRT) = 0.;
+		DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_QUADSIG) = 0.;
+		DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_ROTFOURCORR) = 0.;
+
+		return;
+	}
+
+	iref -= 1; // start counting at 0 instead of 1
+	if (iref >= PPref.size())
+	{
+		MetaDataTable MDt;
+		MDt.addObject(MDin.getObject(ipart));
+		MDt.write(std::cerr);
+		REPORT_ERROR("Too large class number for the given number of references: " + integerToString(iref));
+	}
+
+	// Get the rotational matrix
+	Matrix2D<double> A;
+	Euler_angles2matrix(rot, tilt, psi, A);
+
+	// Get the reference image in the right orientation
+	Fref.resize(current_size, current_size/2 + 1);
+	PPref[iref].get2DFourierTransform(Fref, A, IS_NOT_INV);
+	if (do_ctf)
+	{
+		CTF ctf;
+		MultidimArray<double> Fctf;
+		ctf.read(MDin, MDin, ipart);
+		Fctf.resize(Fref);
+		ctf.getFftwImage(Fctf, XSIZE(img()), YSIZE(img()), angpix, false, false, intact_ctf_first_peak, true);
+		FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Fref)
+		{
+			DIRECT_MULTIDIM_ELEM(Fref, n) *= DIRECT_MULTIDIM_ELEM(Fctf, n);
+		}
+	}
+	if (lowpass > 0.)
+	{
+		// Set the Fourier transform back to its original size...
+		MultidimArray<Complex > Frefp;
+		windowFourierTransform(Fref, Frefp, XSIZE(img()));
+		Fref = Frefp;
+	}
+	Mref_rot.resize(img());
+	transformer.inverseFourierTransform(Fref, Mref_rot);
+	CenterFFT(Mref_rot, true);
+
+#ifdef DEBUG
+	tt() = Mref_rot;
+	tt.write("debug_rotated_ctf_ref.spi");
+#endif
+
+	/*
+	// Calculate the optimal scale between the image and the reference:
+	double sumxa = 0.;
+	double suma2 = 0.;
+	FOR_ALL_DIRECT_ELEMENTS_IN_MULTIDIMARRAY(Mref_rot)
+	{
+		if (DIRECT_MULTIDIM_ELEM(iMsk, n) > 0.5)
+		{
+			sumxa += DIRECT_MULTIDIM_ELEM(Mref_rot, n) * DIRECT_MULTIDIM_ELEM(img(), n);
+			suma2 += DIRECT_MULTIDIM_ELEM(Mref_rot, n) * DIRECT_MULTIDIM_ELEM(Mref_rot, n);
+		}
+	}
+	if (suma2 < 1e-10)
+		REPORT_ERROR("ERROR: Empty reference encountered!!");
+	double scale = sumxa/suma2;
+	// Calculate the difference between the particle and the oriented reference
+	img() -= scale * Mref_rot;
+	*/
+
+	// Calculate the difference between the particle and the oriented reference
+	img() -= Mref_rot;
+
+	// Let's mask it already here (also useful for RotationalSymmetryInFourierTransform)
+	img().setXmippOrigin();
+	FOR_ALL_ELEMENTS_IN_ARRAY2D(img())
+	{
+		if (i*i + j*j >= particle_radius2)
+			A2D_ELEM(img(), i, j) = 0.;
+	}
+
+#ifdef DEBUG
+	tt = img;
+	tt.write("debug_differene_image.spi");
+#endif
+
+	// Calculate real-space statistics on the difference image (only within the masked protein area)
+	//iMsk.initConstant(1.);
+    double mean = 0., stddev = 0., skew = 0., kurt = 0., quadrant_stddev = 0., rotsym = 0.;
+	calculateStatsOneImage(img(), mean, stddev, skew, kurt, quadrant_stddev);
+	DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_AVG) = mean;
+	DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_SIG) = stddev;
+	DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_SKW) = skew;
+	DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_KRT) = kurt;
+	DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_QUADSIG) = quadrant_stddev;
+
+	// Calculate the rotational Symmetry of the Fourier Transform of the masked difference image
+	transformer.FourierTransform(img(), Fimg);
+	rotsym = rotationalSymmetryFourierTransform(Fimg);
+	DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_ROTFOURCORR) = rotsym;
+
+
+#ifdef DEBUG
+	std::cerr << "Difference image protein area" << std::endl;
+	std::cerr << " mean= " << mean << " stddev= " << stddev << " skew= " << skew << " kurt= " << kurt << " quadrant_stddev= " <<  quadrant_stddev << " rotSym= " << rotsym << std::endl;
+	std::cerr << " Press any key to continue... "  << std::endl;
+	char c;
+	std::cin >> c;
+#endif
+
+}
+
+void ParticleSorter::normaliseFeatures()
+{
+
+	// Ignore manually added particles, which will have all features set to 0...
+	std::vector< std::vector<double> > normfeatures(XSIZE(features));
+	MultidimArray<double> onerow;
+	for (int ipart = 0; ipart < YSIZE(features); ipart++)
+	{
+		features.getRow(ipart, onerow);
+		double abssum = 0.;
+		for (int ifeat = 0; ifeat < XSIZE(features); ifeat++)
+		{
+			abssum += ABS(DIRECT_A1D_ELEM(onerow, ifeat));
+		}
+		if (abssum > 0.)
+		{
+			for (int ifeat = 0; ifeat < XSIZE(features); ifeat++)
+			{
+				normfeatures[ifeat].push_back(DIRECT_A1D_ELEM(onerow, ifeat));
+			}
+		}
+	}
+
+	// Now calculate average and stddev for all particles which did not have all features set to 0
+	std::vector<double> avg(XSIZE(features), 0.), stddev(XSIZE(features), 0.);
+	for (int ifeat = 0; ifeat < XSIZE(features); ifeat++)
+	{
+		// average
+		for (long int i =0; i < (normfeatures[ifeat]).size(); i++)
+			avg[ifeat] += normfeatures[ifeat][i];
+		avg[ifeat] /= (normfeatures[ifeat]).size();
+
+		// stddev
+		for (long int i =0; i < (normfeatures[ifeat]).size(); i++)
+			stddev[ifeat] += (normfeatures[ifeat][i] - avg[ifeat]) * (normfeatures[ifeat][i] - avg[ifeat]);
+		stddev[ifeat] = sqrt(stddev[ifeat] / (normfeatures[ifeat]).size());
+	}
+
+	// Calculate Z-scores for all particles, except the ones that were added manually
+	for (int ipart = 0; ipart < YSIZE(features); ipart++)
+	{
+		features.getRow(ipart, onerow);
+		double abssum = 0.;
+		for (int ifeat = 0; ifeat < XSIZE(features); ifeat++)
+		{
+			abssum += ABS(DIRECT_A1D_ELEM(onerow, ifeat));
+		}
+		if (abssum > 0.)
+		{
+			for (int ifeat = 0; ifeat < XSIZE(features); ifeat++)
+			{
+				DIRECT_A1D_ELEM(onerow, ifeat) =  (DIRECT_A1D_ELEM(onerow, ifeat) - avg[ifeat]) / stddev[ifeat];
+				if (DIRECT_A1D_ELEM(onerow, ifeat) < min_z)
+					DIRECT_A1D_ELEM(onerow, ifeat) = 0.;
+			}
+		}
+		else
+		{
+			// Set negative Z-scores (-1) for manually picked particles
+			for (int ifeat = 0; ifeat < XSIZE(features); ifeat++)
+			{
+				DIRECT_A1D_ELEM(onerow, ifeat) = - 1.;
+			}
+		}
+		features.setRow(ipart, onerow);
+	}
+
+}
+
+void ParticleSorter::writeFeatures()
+{
+
+	FileName fn_img;
+	FileName fn_tmp = fn_out +"_features.libsvm";
+#ifdef WRITE_LIBSVM
+	std::ofstream  fh, fh2, fh3;
+	fh.open((fn_tmp).c_str(), std::ios::out);
+	if (!fh)
+		REPORT_ERROR( (std::string)" ParticleSorter::writeFeatures: Cannot write file: " + fn_tmp);
+	fn_tmp = fn_out +"_features.dat";
+	fh2.open((fn_tmp).c_str(), std::ios::out);
+	if (!fh2)
+		REPORT_ERROR( (std::string)" ParticleSorter::writeFeatures: Cannot write file: " + fn_tmp);
+#endif
+
+	MultidimArray<double> sumfeatures(YSIZE(features));
+	sumfeatures.initZeros();
+	for (int ipart = 0; ipart < YSIZE(features); ipart++)
+	{
+#ifdef WRITE_LIBSVM
+		fh2 << ipart << " ";
+#endif
+		for (int ifeat = 0; ifeat < XSIZE(features); ifeat++)
+		{
+#ifdef WRITE_LIBSVM
+			fh << ifeat <<":"<<DIRECT_A2D_ELEM(features, ipart, ifeat)<<" ";
+			fh2 << DIRECT_A2D_ELEM(features, ipart, ifeat)<<" ";
+#endif
+			DIRECT_A1D_ELEM(sumfeatures, ipart) += DIRECT_A2D_ELEM(features, ipart, ifeat);
+		}
+		DIRECT_A1D_ELEM(sumfeatures, ipart) /= XSIZE(features);
+#ifdef WRITE_LIBSVM
+		MultidimArray<double> row(1);
+		features.getRow(ipart, row);
+		fh2<< " sum= " << DIRECT_A1D_ELEM(sumfeatures, ipart);
+		MDin.getValue(EMDL_IMAGE_NAME, fn_img, ipart);
+		fh2<< " "<< fn_img;
+		fh << std::endl;
+		fh2 << std::endl;
+#endif
+	}
+#ifdef WRITE_LIBSVM
+	fh.close();
+	fh2.close();
+#endif
+
+	int ipart = 0;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDin)
+	{
+#ifdef DEBUG
+		MDin.setValue(EMDL_IMAGE_STATS_AVG, DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_AVG));
+		MDin.setValue(EMDL_IMAGE_STATS_STDDEV, DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_SIG));
+		MDin.setValue(EMDL_IMAGE_STATS_SKEW, DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_SKW));
+		MDin.setValue(EMDL_IMAGE_STATS_KURT, DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_KRT));
+		MDin.setValue(EMDL_PARTICLE_DLL, DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_QUADSIG));
+		MDin.setValue(EMDL_POSTPROCESS_GUINIER_FIT_CORRELATION, DIRECT_A2D_ELEM(features, ipart, FEATURE_DF_ROTFOURCORR));
+#endif
+		MDin.setValue(EMDL_SELECT_PARTICLES_ZSCORE, DIRECT_A1D_ELEM(sumfeatures, ipart));
+		ipart++;
+	}
+	fn_tmp = fn_out + ".star";
+	MDin.write(fn_tmp);
+
+
+	if (verb>0)
+		std::cout <<" Written out "<< fn_tmp << std::endl;
+}
+
+double ParticleSorter::rotationalSymmetryFourierTransform(MultidimArray<Complex > &Fimg)
+{
+	double result;
+	// Calculate average and stddev per ring
+
+	int radius = ROUND(YSIZE(Fimg) * angpix / lowpass);
+	MultidimArray<double> count, power;
+
+    power.initZeros(radius+1);
+    count.initZeros(radius+1);
+    FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM2D(Fimg)
+    {
+    	long int idx = ROUND(sqrt(ip*ip + jp*jp));
+    	if (idx < radius)
+    	{
+			power(idx) += norm(DIRECT_A2D_ELEM(Fimg, i, j));
+			count(idx) += 1.;
+    	}
+    }
+
+    for (long int i = 0; i < radius+1; i++)
+    {        if (count(i) > 0.)
+            power(i) /= count(i);
+    }
+
+    double sum = 0.;
+    double sum2 = 0.;
+    double cc  = 0.;
+    FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM2D(Fimg)
+    {
+    	long int idx = ROUND(sqrt(ip*ip + jp*jp));
+    	if (idx < radius)
+    	{
+    		double aux = norm(DIRECT_A2D_ELEM(Fimg, i, j)) - power(idx);
+    		sum += aux;
+    		sum2 += aux*aux;
+    		cc++;
+    	}
+    }
+
+    sum  /= cc;
+	sum2 /= cc;
+	result = sum2 - sum * sum;
+	result *= YXSIZE(Fimg)*YXSIZE(Fimg);
+#ifdef DEBUG
+	std::cerr <<" rotSym="<<result<<std::endl;
+#endif
+	return result;
+}
+
+void ParticleSorter::calculateStatsOneImage(MultidimArray<double> &img,
+							double &mean, double &stddev, double &skew, double &kurt, double &quadrant_stddev)
+{
+
+	// First pass: calculate mean
+	int na = 0;
+	int n1 = 0;
+	int n2 = 0;
+	int n3 = 0;
+	int n4 = 0;
+	double mean_q1 = 0.;
+	double mean_q2 = 0.;
+	double mean_q3 = 0.;
+	double mean_q4 = 0.;
+	double stddev_q1 = 0.;
+	double stddev_q2 = 0.;
+	double stddev_q3 = 0.;
+	double stddev_q4 = 0.;
+	mean = 0.;
+	stddev = 0;
+	skew   = 0.;
+	kurt   = 0.;
+
+	img.setXmippOrigin();
+
+	FOR_ALL_ELEMENTS_IN_ARRAY2D(img)
+	{
+		if (i*i + j*j < particle_radius2)
+		{
+			mean += A2D_ELEM(img, i, j);
+			na++;
+
+			if (i > 0 && j > 0)
+			{
+				mean_q1 += A2D_ELEM(img, i, j);
+				n1++;
+			}
+			else if (i > 0 && j <= 0)
+			{
+				mean_q2 += A2D_ELEM(img, i, j);
+				n2++;
+			}
+			else if (i <= 0 && j > 0)
+			{
+				mean_q3 += A2D_ELEM(img, i, j);
+				n3++;
+			}
+			else if (i <= 0 && j <= 0)
+			{
+				mean_q4 += A2D_ELEM(img, i, j);
+				n4++;
+			}
+		}
+	}
+
+	// Second pass calculate higher moments
+	mean /= na;
+	mean_q1 /= n1;
+	mean_q2 /= n2;
+	mean_q3 /= n3;
+	mean_q4 /= n4;
+
+	FOR_ALL_ELEMENTS_IN_ARRAY2D(img)
+	{
+		if (i*i + j*j < particle_radius2)
+		{
+			double aux = A2D_ELEM(img, i, j) - mean;
+			double aux2 = aux * aux;
+			stddev += aux2;
+			skew += aux2 * aux;
+			kurt += aux2 * aux2;
+			if (i > 0 && j > 0)
+			{
+				aux = A2D_ELEM(img, i, j) - mean_q1;
+				aux2 = aux * aux;
+				stddev_q1 += aux2;
+			}
+			else if (i > 0 && j <= 0)
+			{
+				aux = A2D_ELEM(img, i, j) - mean_q2;
+				aux2 = aux * aux;
+				stddev_q2 += aux2;
+			}
+			else if (i <= 0 && j > 0)
+			{
+				aux = A2D_ELEM(img, i, j) - mean_q3;
+				aux2 = aux * aux;
+				stddev_q3 += aux2;
+			}
+			else if (i <= 0 && j <= 0)
+			{
+				aux = A2D_ELEM(img, i, j) - mean_q4;
+				aux2 = aux * aux;
+				stddev_q4 += aux2;
+			}
+		}
+	}
+	double var = stddev/na;
+	stddev = sqrt(var);
+	skew = (skew/na)/(var*stddev);
+	kurt = (kurt/na)/(var*var) - 3.;
+
+	var = stddev_q1/n1;
+	stddev_q1 = sqrt(var);
+
+	var = stddev_q2/n2;
+	stddev_q2 = sqrt(var);
+
+	var = stddev_q3/n3;
+	stddev_q3 = sqrt(var);
+
+	var = stddev_q4/n4;
+	stddev_q4 = sqrt(var);
+
+	double mean_stddevs = 0.;
+	double stddev_stddevs = 0.;
+	mean_stddevs = (stddev_q1 + stddev_q2 + stddev_q3 + stddev_q4) / 4.;
+	stddev_stddevs += (stddev_q1-mean_stddevs)*(stddev_q1-mean_stddevs) + (stddev_q2-mean_stddevs)*(stddev_q2-mean_stddevs) + (stddev_q3-mean_stddevs)*(stddev_q3-mean_stddevs) + (stddev_q4-mean_stddevs)*(stddev_q4-mean_stddevs);
+	quadrant_stddev = sqrt(stddev_stddevs / 4.);
+
+}
+
+
diff --git a/src/particle_sorter.h b/src/particle_sorter.h
new file mode 100644
index 0000000..8691fdd
--- /dev/null
+++ b/src/particle_sorter.h
@@ -0,0 +1,126 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef PARTICLE_SORTER_H_
+#define PARTICLE_SORTER_H_
+
+#include "src/image.h"
+#include "src/multidim_array.h"
+#include "src/metadata_table.h"
+#include "src/projector.h"
+#include "src/ctf.h"
+#include <src/fftw.h>
+#include <src/time.h>
+
+#define FEATURE_DF_AVG      0
+#define FEATURE_DF_SIG      1
+#define FEATURE_DF_SKW      2
+#define FEATURE_DF_KRT      3
+#define FEATURE_DF_QUADSIG  4
+#define FEATURE_DF_ROTFOURCORR 5
+#define NR_FEATURES 6
+
+#define WIDTH_FMASK_EDGEB 2
+
+
+class ParticleSorter
+{
+public:
+
+	// I/O Parser
+	IOParser parser;
+
+	// Verbosity
+	int verb;
+
+	// Input & Output rootname
+	FileName fn_in, fn_ref, fn_out;
+
+	// Input metadata
+	MetaDataTable MDin;
+
+	// Pixel size (for low-pass filter and particle diameter)
+	double angpix;
+
+	// Particle diameter (in Angstroms)
+	double particle_diameter;
+	int particle_radius2;
+
+	// Low pass filetr cutoff (in Angstroms)
+	double lowpass;
+
+	// Original size of the reference images
+	int particle_size;
+
+	// Dimension of the filtered image
+	int current_size;
+
+	// Minimum Z-value to count in the sorting
+	double min_z;
+
+	// Vector with all original reference images
+	std::vector<MultidimArray<double> > Mrefs;
+
+	// FTs of the reference images for feature calculation
+	std::vector<Projector > PPref;
+
+	// Feature values for all input images
+	MultidimArray<double> features;
+
+	// Is density in micrograph inverted wrt templates?
+	bool do_invert;
+
+	// Correct the references for CTF effects?
+	bool do_ctf;
+
+	// Keep the CTFs unchanged until the first peak?
+	bool intact_ctf_first_peak;
+
+public:
+	// Read command line arguments
+	void read(int argc, char **argv);
+
+	// Print usage instructions
+	void usage();
+
+	// General function to decide what to do
+	void run();
+
+	// Initialise some general stuff after reading
+	void initialise();
+
+	void calculateFeaturesOneParticle(long int ipart);
+
+protected:
+
+	void normaliseFeatures();
+
+	// Write out (for now in libsvm format)
+	void writeFeatures();
+
+	void calculateStatsOneImage(MultidimArray<double> &img,
+			double &mean, double &stddev, double &skew, double &kurt, double &quadrant_stddev);
+
+	double rotationalSymmetryFourierTransform(MultidimArray<Complex > &Fimg);
+
+};
+
+
+#endif /* PARTICLE_SORTER_H_ */
diff --git a/src/particle_sorter_mpi.cpp b/src/particle_sorter_mpi.cpp
new file mode 100644
index 0000000..1fe04c6
--- /dev/null
+++ b/src/particle_sorter_mpi.cpp
@@ -0,0 +1,91 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/particle_sorter_mpi.h"
+
+void ParticleSorterMpi::read(int argc, char **argv)
+{
+    // Define a new MpiNode
+    node = new MpiNode(argc, argv);
+
+    // First read in non-parallelisation-dependent variables
+    ParticleSorter::read(argc, argv);
+
+    // Don't put any output to screen for mpi slaves
+    verb = (node->isMaster()) ? 1 : 0;
+
+    // Possibly also read parallelisation-dependent variables here
+
+    // Print out MPI info
+	printMpiNodesMachineNames(*node);
+
+
+}
+void ParticleSorterMpi::run()
+{
+
+	int total_nr_images = MDin.numberOfObjects();
+	features.resize(total_nr_images, NR_FEATURES);
+
+	// Each node does part of the work
+	long int my_first_image, my_last_image, my_nr_images;
+	divide_equally(total_nr_images, node->size, node->rank, my_first_image, my_last_image);
+	my_nr_images = my_last_image - my_first_image + 1;
+
+	int barstep;
+	if (verb > 0)
+	{
+		std::cout << "Calculating sorting features for all input particles..." << std::endl;
+		init_progress_bar(my_nr_images);
+		barstep = XMIPP_MAX(1, my_nr_images/ 60);
+	}
+
+	long int ipart = 0;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDin)
+	{
+
+		if (ipart >= my_first_image && ipart <= my_last_image)
+		{
+			if (verb > 0 && ipart % barstep == 0)
+				progress_bar(ipart);
+
+			calculateFeaturesOneParticle(ipart);
+
+		}
+		ipart++;
+	}
+
+	if (verb > 0)
+		progress_bar(my_nr_images);
+
+	// Combine results from all nodes
+	MultidimArray<double> allnodes_features;
+	allnodes_features.resize(features);
+	MPI_Allreduce(MULTIDIM_ARRAY(features), MULTIDIM_ARRAY(allnodes_features), MULTIDIM_SIZE(features), MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
+	features = allnodes_features;
+
+	// Only the master writes out files
+	if (verb > 0)
+	{
+		normaliseFeatures();
+
+		writeFeatures();
+	}
+
+}
diff --git a/src/particle_sorter_mpi.h b/src/particle_sorter_mpi.h
new file mode 100644
index 0000000..5294460
--- /dev/null
+++ b/src/particle_sorter_mpi.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef PARTICLE_SORTER_MPI_H_
+#define PARTICLE_SORTER_MPI_H_
+
+#include "src/mpi.h"
+#include "src/particle_sorter.h"
+#include "src/parallel.h"
+
+class ParticleSorterMpi : public ParticleSorter
+{
+private:
+	MpiNode *node;
+
+public:
+	/** Destructor, calls MPI_Finalize */
+    ~ParticleSorterMpi()
+    {
+        delete node;
+    }
+
+    /** Read
+     * This could take care of mpi-parallelisation-dependent variables
+     */
+    void read(int argc, char **argv);
+
+    // Parallelized run function
+    void run();
+
+};
+
+
+#endif /* PARTICLE_SORTER_MPI_H_ */
diff --git a/src/postprocessing.cpp b/src/postprocessing.cpp
new file mode 100644
index 0000000..440db85
--- /dev/null
+++ b/src/postprocessing.cpp
@@ -0,0 +1,647 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include "src/postprocessing.h"
+
+void Postprocessing::read(int argc, char **argv)
+{
+
+	parser.setCommandLine(argc, argv);
+	int gen_section = parser.addSection("General options");
+	fn_in = parser.getOption("--i", "Input rootname, e.g. run1");
+	fn_out = parser.getOption("--o", "Output rootname", "postprocess");
+	angpix = textToFloat(parser.getOption("--angpix", "Pixel size in Angstroms"));
+
+	int mask_section = parser.addSection("Masking options");
+	do_auto_mask = parser.checkOption("--auto_mask", "Perform automated masking, based on a density threshold");
+	ini_mask_density_threshold = textToFloat(parser.getOption("--inimask_threshold", "Density at which to threshold the map for the initial seed mask", "0.02"));
+	extend_ini_mask = textToFloat(parser.getOption("--extend_inimask", "Number of pixels to extend the initial seed mask", "3."));
+	width_soft_mask_edge  = textToFloat(parser.getOption("--width_mask_edge", "Width for the raised cosine soft mask edge (in pixels)", "6."));
+	fn_mask = parser.getOption("--mask", "Filename of a user-provided mask (1=protein, 0=solvent, all values in range [0,1])", "");
+
+	int sharp_section = parser.addSection("Sharpening options");
+	fn_mtf = parser.getOption("--mtf", "User-provided STAR-file with the MTF-curve of the detector", "");
+	do_auto_bfac = parser.checkOption("--auto_bfac", "Perform automated B-factor determination (Rosenthal and Henderson, 2003)");
+	fit_minres = textToFloat(parser.getOption("--autob_lowres", "Lowest resolution (in A) to include in fitting of the B-factor", "10."));
+	fit_maxres = textToFloat(parser.getOption("--autob_highres", "Highest resolution (in A) to include in fitting of the B-factor", "0."));
+	adhoc_bfac =  textToFloat(parser.getOption("--adhoc_bfac", "User-provided B-factor (in A^2) for map sharpening, e.g. -400", "0."));
+
+	int filter_section = parser.addSection("Filtering options");
+	do_fsc_weighting = !parser.checkOption("--skip_fsc_weighting", "Do not use FSC-weighting (Rosenthal and Henderson, 2003) in the sharpening process");
+	// include low-pass filter option in the program? This could be useful for structurally heterogeneous reconstructions (instead of FSC-weighting)
+	low_pass_freq = textToFloat(parser.getOption("--low_pass", "Resolution (in Angstroms) at which to low-pass filter the final map (by default at final resolution)", "0."));
+
+	int expert_section = parser.addSection("Expert options");
+	randomize_fsc_at = textToFloat(parser.getOption("--randomize_at_fsc", "Randomize phases from the resolution where FSC drops below this value", "0.8"));
+	filter_edge_width = textToInteger(parser.getOption("--filter_edge_width", "Width of the raised cosine on the low-pass filter edge (in resolution shells)", "2"));
+	verb = textToInteger(parser.getOption("--verb", "Verbosity", "1"));
+
+	// Check for errors in the command-line option
+	if (parser.checkForErrors())
+		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+}
+
+void Postprocessing::usage()
+{
+	parser.writeUsage(std::cerr);
+}
+
+void Postprocessing::clear()
+{
+	fn_in = "";
+	fn_out="postprocess";
+	angpix = 1.;
+	do_auto_mask = false;
+	ini_mask_density_threshold = 0.02;
+	width_soft_mask_edge = 6.;
+	fn_mask = "";
+	fn_mtf = "";
+	do_auto_bfac = false;
+	fit_minres = 10.;
+	fit_maxres = 0.;
+	adhoc_bfac = 0.;
+	do_fsc_weighting = true;
+	low_pass_freq = 0.;
+	randomize_fsc_at = 0.8;
+	filter_edge_width = 2.;
+	verb = 1;
+
+}
+
+void Postprocessing::initialise()
+{
+	// Read in the input maps
+	fn_I1 = fn_in + "_half1_class001_unfil.mrc";
+	fn_I2 = fn_in + "_half2_class001_unfil.mrc";
+
+	if (verb > 0)
+	{
+		std::cout <<"== Reading input half-reconstructions: " <<std::endl;
+		std::cout.width(35); std::cout << std::left <<"  + half1-map: "; std::cout << fn_I1 << std::endl;
+		std::cout.width(35); std::cout << std::left <<"  + half2-map: "; std::cout << fn_I2 << std::endl;
+	}
+
+	I1.read(fn_I1);
+	I2.read(fn_I2);
+	I1().setXmippOrigin();
+	I2().setXmippOrigin();
+
+	if (!I1().sameShape(I2()))
+	{
+		std::cerr << " Size of half1 map: "; I1().printShape(std::cerr); std::cerr << std::endl;
+		std::cerr << " Size of half2 map: "; I2().printShape(std::cerr); std::cerr << std::endl;
+		REPORT_ERROR("Postprocessing::initialise ERROR: The two half reconstructions are not of the same size!");
+	}
+
+	if (do_auto_mask && fn_mask != "")
+		REPORT_ERROR("Postprocessing::initialise ERROR: provide either --auto_mask OR --mask, but not both!");
+
+	if (do_auto_bfac && ABS(adhoc_bfac) > 0.)
+		REPORT_ERROR("Postprocessing::initialise ERROR: provide either --auto_bfac OR --adhoc_bfac, but not both!");
+}
+
+void Postprocessing::getAutoMask()
+{
+
+	if (verb > 0)
+	{
+		std::cout << "== Perform auto-masking ..." << std::endl;
+		std::cout.width(35); std::cout << std::left  << "  + density threshold: "; std::cout  << ini_mask_density_threshold << std::endl;
+		std::cout.width(35); std::cout << std::left  << "  + extend ini mask: "; std::cout  << extend_ini_mask << " pixels" << std::endl;
+		std::cout.width(35); std::cout << std::left  << "  + width soft edge: "; std::cout  << width_soft_mask_edge << " pixels" << std::endl;
+	}
+
+	// Store sum of both masks in Im
+	I1() += I2();
+	I1() /= 2.;
+	autoMask(I1(), Im(), ini_mask_density_threshold, extend_ini_mask, width_soft_mask_edge, true); // true sets verbosity
+
+	// Re-read original I1 into memory
+	I1.read(fn_I1);
+	I1().setXmippOrigin();
+
+}
+
+bool Postprocessing::getMask()
+{
+
+	// A. Check whether a user-provided mask is to be used
+	if (do_auto_mask)
+	{
+		getAutoMask();
+
+	}
+	else if (fn_mask != "")
+	{
+		if (verb > 0)
+		{
+			std::cout << "== Using a user-provided mask ... " <<std::endl;
+			std::cout.width(35); std::cout << std::left   << "  + input mask: "; std::cout  << fn_mask <<std::endl;
+		}
+
+		// Read the mask in memory
+		Im.read(fn_mask);
+		Im().setXmippOrigin();
+
+		// Check values are between 0 and 1
+		double avg, stddev, minval, maxval;
+		Im().computeStats(avg, stddev, minval, maxval);
+		if (minval < -1e-6 || maxval - 1. > 1.e-6)
+		{
+			std::cerr << " minval= " << minval << " maxval= " << maxval << std::endl;
+			REPORT_ERROR("Postprocessing::mask ERROR: mask values not in range [0,1]!");
+		}
+
+		// Also check the mask is the same size as the input maps
+		if (!Im().sameShape(I2()))
+		{
+			std::cerr << " Size of input mask: "; Im().printShape(std::cerr); std::cerr<< std::endl;
+			std::cerr << " Size of input maps: "; I1().printShape(std::cerr); std::cerr<< std::endl;
+			REPORT_ERROR("Postprocessing::mask ERROR: mask and input maps do not have the same size!");
+		}
+
+	}
+	else
+	{
+		if (verb > 0)
+		{
+			std::cout << "== Not performing any masking ... " << std::endl;
+		}
+		return false;
+	}
+
+	return true;
+}
+
+void Postprocessing::divideByMtf(MultidimArray<Complex > &FT)
+{
+
+	if (fn_mtf != "")
+	{
+		if (verb > 0)
+		{
+			std::cout << "== Dividing map by the MTF of the detector ..." << std::endl;
+			std::cout.width(35); std::cout << std::left <<"  + mtf STAR-file: "; std::cout << fn_mtf << std::endl;
+		}
+
+		correctMapForMTF(FT, XSIZE(I1()), fn_mtf);
+	}
+
+}
+
+
+void Postprocessing::sharpenMap()
+{
+
+	MultidimArray<Complex > FT;
+	FourierTransformer transformer;
+	transformer.FourierTransform(I1(), FT, true);
+
+	makeGuinierPlot(FT, guinierin);
+
+	// A. If MTF curve is given, first divide by the MTF
+	divideByMtf(FT);
+	makeGuinierPlot(FT, guinierinvmtf);
+
+	// B. Then perform B-factor sharpening
+	if (do_fsc_weighting)
+	{
+		if (verb > 0)
+		{
+			std::cout <<"== Applying sqrt(2*FSC/(FSC+1)) weighting (as in Rosenthal & Henderson, 2003) ..." <<std::endl;
+		}
+		applyFscWeighting(FT, fsc_true);
+	}
+	makeGuinierPlot(FT, guinierweighted);
+
+	global_bfactor = 0.;
+	if (do_auto_bfac)
+	{
+		if (verb > 0)
+		{
+			std::cout <<"== Fitting straight line through Guinier plot to find B-factor ..." <<std::endl;
+			std::cout.width(35); std::cout << std::left <<"  + fit from resolution: "; std::cout << fit_minres << std::endl;
+			std::cout.width(35); std::cout << std::left  <<"  + fit until resolution: "; std::cout << fit_maxres << std::endl;
+		}
+
+		fitStraightLine(guinierweighted, global_slope, global_intercept, global_corr_coeff);
+		global_bfactor = 4. * global_slope;
+		if (verb > 0)
+		{
+			std::cout.width(35); std::cout << std::left  <<"  + slope of fit: "; std::cout << global_slope << std::endl;
+			std::cout.width(35); std::cout << std::left  <<"  + intercept of fit: "; std::cout << global_intercept << std::endl;
+			std::cout.width(35); std::cout << std::left  <<"  + correlation of fit: "; std::cout << global_corr_coeff << std::endl;
+		}
+	}
+	else if (ABS(adhoc_bfac) > 0.)
+	{
+		if (verb > 0)
+		{
+			std::cout <<"== Using a user-provided (ad-hoc) B-factor ..." <<std::endl;
+		}
+		if (adhoc_bfac > 0.)
+			std::cout <<" WARNING: using a positive B-factor. This will effectively dampen your map. Use negative value to sharpen it!" << std::endl;
+		global_bfactor = adhoc_bfac;
+	}
+
+	// Now apply the B-factor
+	if (ABS(global_bfactor) > 0.)
+	{
+		if (verb > 0)
+		{
+			std::cout.width(35); std::cout << std::left  <<"  + apply b-factor of: "; std::cout << global_bfactor << std::endl;
+		}
+		applyBFactorToMap(FT, XSIZE(I1()), global_bfactor, angpix);
+	}
+
+	makeGuinierPlot(FT, guiniersharpen);
+
+	if (verb > 0)
+	{
+		std::cout << "== Low-pass filtering final map ... " << std::endl;
+	}
+	double my_filter = (low_pass_freq > 0.) ? low_pass_freq : global_resol;
+	if (verb > 0)
+	{
+		std::cout.width(35); std::cout << std::left  <<"  + filter frequency: "; std::cout << my_filter << std::endl;
+	}
+	lowPassFilterMap(FT, XSIZE(I1()), my_filter, angpix, filter_edge_width);
+
+	transformer.inverseFourierTransform(FT, I1());
+
+}
+
+void Postprocessing::applyFscWeighting(MultidimArray<Complex > &FT, MultidimArray<double> my_fsc)
+{
+	// Find resolution where fsc_true drops below zero for the first time
+	// Set all weights to zero beyond that resolution
+	int ires_max = 0 ;
+	FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(my_fsc)
+	{
+		if (DIRECT_A1D_ELEM(my_fsc, i) < 1e-10)
+			break;
+		ires_max = i;
+	}
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(FT)
+	{
+    	int ires = ROUND(sqrt((double)kp * kp + ip * ip + jp * jp));
+		if (ires <= ires_max)
+		{
+	        double fsc = DIRECT_A1D_ELEM(my_fsc, ires);
+	        if (fsc < 1e-10)
+	        	REPORT_ERROR("Postprocessing::applyFscWeighting BUG: fsc <= 0");
+	        DIRECT_A3D_ELEM(FT, k, i, j) *= sqrt((2 * fsc) / (1 + fsc));
+		}
+		else
+		{
+			DIRECT_A3D_ELEM(FT, k, i, j) = 0.;
+		}
+	}
+
+}
+
+void Postprocessing::makeGuinierPlot(MultidimArray<Complex > &FT, std::vector<fit_point2D> &guinier)
+{
+
+	MultidimArray<int> radial_count(XSIZE(FT));
+	MultidimArray<double> lnF(XSIZE(FT));
+	fit_point2D      onepoint;
+
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(FT)
+	{
+    	int r2 = kp * kp + ip * ip + jp * jp;
+    	int ires = ROUND(sqrt((double)r2));
+		if (ires < XSIZE(radial_count))
+		{
+
+	        lnF(ires) += abs(DIRECT_A3D_ELEM(FT, k, i, j));
+	        radial_count(ires)++;
+		}
+	}
+
+	double xsize = XSIZE(I1());
+	guinier.clear();
+	FOR_ALL_ELEMENTS_IN_ARRAY1D(radial_count)
+	{
+
+		double res = (xsize * angpix)/(double)i; // resolution in Angstrom
+		if (res >= angpix * 2.) // Apply B-factor sharpening until Nyquist, then low-pass filter later on (with a soft edge)
+        {
+            onepoint.x = 1. / (res * res);
+            if (DIRECT_A1D_ELEM(lnF, i) > 0.)
+            {
+                onepoint.y = log ( DIRECT_A1D_ELEM(lnF, i) / DIRECT_A1D_ELEM(radial_count, i) );
+                if (res <= fit_minres && res >= fit_maxres)
+                {
+                    onepoint.w = 1.;
+                }
+                else
+                {
+                    onepoint.w = 0.;
+                }
+            }
+            else
+            {
+                onepoint.y = -99.;
+                onepoint.w = 0.;
+            }
+            //std::cerr << " onepoint.x= " << onepoint.x << " onepoint.y= " << onepoint.y << " onepoint.w= " << onepoint.w << std::endl;
+            guinier.push_back(onepoint);
+        }
+	}
+
+}
+
+void Postprocessing::writeOutput()
+{
+
+	if (verb > 0)
+	{
+		std::cout <<"== Writing out put files ..." <<std::endl;
+	}
+	// Write all relevant output information
+	FileName fn_tmp;
+	fn_tmp = fn_out + ".mrc";
+
+	double avg, stddev, minval, maxval;
+    I1().computeStats(avg, stddev, minval, maxval);
+    I1.MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN, minval);
+    I1.MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX, maxval);
+    I1.MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG, avg);
+    I1.MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV, stddev);
+    I1.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_X, angpix);
+    I1.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Y, angpix);
+    I1.MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Z, angpix);
+	I1.write(fn_tmp);
+	if (verb > 0)
+	{
+		std::cout.width(35); std::cout << std::left   <<"  + Processed map: "; std::cout << fn_tmp<< std::endl;
+	}
+
+	// Also write the masked postprocessed map
+	if (do_auto_mask || fn_mask != "")
+	{
+		fn_tmp = fn_out + "_masked.mrc";
+		I1() *= Im();
+	    I1().computeStats(avg, stddev, minval, maxval);
+	    I1.MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN, minval);
+	    I1.MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX, maxval);
+	    I1.MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG, avg);
+	    I1.MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV, stddev);
+		I1.write(fn_tmp);
+		if (verb > 0)
+		{
+			std::cout.width(35); std::cout << std::left   <<"  + Processed masked map: "; std::cout << fn_tmp<< std::endl;
+		}
+	}
+
+	// Also write mask
+	if (do_auto_mask)
+	{
+		fn_tmp = fn_out + "_automask.mrc";
+		Im().computeStats(avg, stddev, minval, maxval);
+		Im.MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN, minval);
+		Im.MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX, maxval);
+		Im.MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG, avg);
+		Im.MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV, stddev);
+		Im.write(fn_tmp);
+		if (verb > 0)
+		{
+			std::cout.width(35); std::cout << std::left   <<"  + Auto-mask: "; std::cout << fn_tmp<< std::endl;
+		}
+	}
+
+	// Write an output STAR file with FSC curves, Guinier plots etc
+	std::ofstream  fh;
+	fn_tmp = fn_out + ".star";
+	if (verb > 0)
+	{
+		std::cout.width(35); std::cout << std::left <<"  + Metadata file: "; std::cout << fn_tmp<< std::endl;
+	}
+
+	fh.open((fn_tmp).c_str(), std::ios::out);
+	if (!fh)
+		REPORT_ERROR( (std::string)"MlOptimiser::write: Cannot write file: " + fn_tmp);
+
+	// Write the command line as a comment in the header
+	fh << "# RELION postprocess" << std::endl;
+	fh << "# ";
+	parser.writeCommandLine(fh);
+
+	MetaDataTable MDlist, MDfsc, MDguinier;
+
+	MDlist.setIsList(true);
+	MDlist.setName("general");
+	MDlist.addObject();
+	MDlist.setValue(EMDL_POSTPROCESS_FINAL_RESOLUTION, global_resol);
+	MDlist.setValue(EMDL_POSTPROCESS_BFACTOR, global_bfactor );
+	if (do_auto_bfac)
+	{
+		MDlist.setValue(EMDL_POSTPROCESS_GUINIER_FIT_SLOPE, global_slope);
+		MDlist.setValue(EMDL_POSTPROCESS_GUINIER_FIT_INTERCEPT, global_intercept);
+		MDlist.setValue(EMDL_POSTPROCESS_GUINIER_FIT_CORRELATION, global_corr_coeff);
+	}
+	MDlist.write(fh);
+
+	MDfsc.setName("fsc");
+	FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(fsc_true)
+	{
+		MDfsc.addObject();
+		double res = (i > 0) ? (XSIZE(I1()) * angpix / (double)i) : 999.;
+		MDfsc.setValue(EMDL_SPECTRAL_IDX, (int)i);
+		MDfsc.setValue(EMDL_RESOLUTION, 1./res);
+		MDfsc.setValue(EMDL_RESOLUTION_ANGSTROM, res);
+		if (do_mask)
+		{
+			MDfsc.setValue(EMDL_POSTPROCESS_FSC_TRUE, DIRECT_A1D_ELEM(fsc_true, i) );
+			MDfsc.setValue(EMDL_POSTPROCESS_FSC_UNMASKED, DIRECT_A1D_ELEM(fsc_unmasked, i) );
+			MDfsc.setValue(EMDL_POSTPROCESS_FSC_MASKED, DIRECT_A1D_ELEM(fsc_masked, i) );
+			MDfsc.setValue(EMDL_POSTPROCESS_FSC_RANDOM_MASKED, DIRECT_A1D_ELEM(fsc_random_masked, i) );
+		}
+		else
+		{
+			MDfsc.setValue(EMDL_POSTPROCESS_FSC_UNMASKED, DIRECT_A1D_ELEM(fsc_true, i) );
+		}
+	}
+	MDfsc.write(fh);
+
+	// Also write XML file with FSC_true curve for EMDB submission
+	writeFscXml(MDfsc);
+
+	MDguinier.setName("guinier");
+	for (int i = 0; i < guinierin.size(); i++)
+	{
+		MDguinier.addObject();
+		MDguinier.setValue(EMDL_POSTPROCESS_GUINIER_RESOL_SQUARED, guinierin[i].x);
+		MDguinier.setValue(EMDL_POSTPROCESS_GUINIER_VALUE_IN, guinierin[i].y);
+		if (fn_mtf != "")
+			MDguinier.setValue(EMDL_POSTPROCESS_GUINIER_VALUE_INVMTF, guinierinvmtf[i].y);
+		if (do_fsc_weighting)
+			MDguinier.setValue(EMDL_POSTPROCESS_GUINIER_VALUE_WEIGHTED, guinierweighted[i].y);
+		if (do_auto_bfac || ABS(adhoc_bfac) > 0.)
+			MDguinier.setValue(EMDL_POSTPROCESS_GUINIER_VALUE_SHARPENED, guiniersharpen[i].y);
+		if (do_auto_bfac)
+			MDguinier.setValue(EMDL_POSTPROCESS_GUINIER_VALUE_INTERCEPT, global_intercept);
+	}
+	MDguinier.write(fh);
+
+	fh.close();
+
+	if (verb > 0)
+	{
+		std::cout.width(35); std::cout << std::left   <<"  + FINAL RESOLUTION: "; std::cout << global_resol<< std::endl;
+	}
+
+}
+
+void Postprocessing::writeFscXml(MetaDataTable &MDfsc)
+{
+
+    FileName fn_fsc = fn_out + "_fsc.xml";
+	std::ofstream  fh;
+    fh.open((fn_fsc).c_str(), std::ios::out);
+    if (!fh)
+        REPORT_ERROR( (std::string)"MetaDataTable::write Cannot write to file: " + fn_fsc);
+
+    fh << "<fsc title=\"RELION masked-corrected FSC\" xaxis=\"Resolution (A-1)\" yaxis=\"Correlation Coefficient\">"<<std::endl;
+
+    FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDfsc)
+    {
+    	double xx, yy;
+    	MDfsc.getValue(EMDL_RESOLUTION, xx);
+    	MDfsc.getValue(EMDL_POSTPROCESS_FSC_TRUE, yy);
+    	fh << "  <coordinate>" << std::endl;
+    	fh << "    <x>" << xx << "</x>" << std::endl;
+    	fh << "    <y>" << yy << "</y>" << std::endl;
+    	fh << "  </coordinate>" << std::endl;
+    }
+    fh << "</fsc>" << std::endl;
+    fh.close();
+    std::cout.width(35); std::cout << std::left <<"  + EMDB xml-format FSC curve: "; std::cout << fn_fsc << std::endl;
+}
+
+void Postprocessing::run()
+{
+
+	// Read inout maps and perform some checks
+	initialise();
+
+	// Calculate FSC of the unmask maps
+	getFSC(I1(), I2(), fsc_unmasked);
+
+	// Check whether we'll do masking
+	do_mask = getMask();
+	if (do_mask)
+	{
+		if (verb > 0)
+		{
+			std::cout <<"== Masking input maps ..." <<std::endl;
+		}
+		// Mask I1 and I2 and calculated fsc_masked
+		I1() *= Im();
+		I2() *= Im();
+		getFSC(I1(), I2(), fsc_masked);
+
+		// To save memory re-read the same input maps again and randomize phases before masking
+		I1.read(fn_I1);
+		I2.read(fn_I2);
+		I1().setXmippOrigin();
+		I2().setXmippOrigin();
+
+		// Check at which resolution shell the FSC drops below randomize_fsc_at
+		int randomize_at = -1;
+		FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(fsc_unmasked)
+		{
+			if (i > 0 && DIRECT_A1D_ELEM(fsc_unmasked, i) < randomize_fsc_at)
+			{
+				randomize_at = i;
+				break;
+			}
+		}
+		if (verb > 0)
+		{
+			std::cout.width(35); std::cout << std::left << "  + randomize phases beyond: "; std::cout << XSIZE(I1())* angpix / randomize_at << " Angstroms" << std::endl;
+		}
+		if (randomize_at > 0)
+		{
+			randomizePhasesBeyond(I1(), randomize_at);
+			randomizePhasesBeyond(I2(), randomize_at);
+			// Mask randomized phases maps and calculated fsc_random_masked
+			I1() *= Im();
+			I2() *= Im();
+			getFSC(I1(), I2(), fsc_random_masked);
+
+		}
+		else
+			REPORT_ERROR("Postprocessing::run ERROR: FSC curve never drops below randomize_fsc_at");
+
+		// Now that we have fsc_masked and fsc_random_masked, calculate fsc_true according to Richard's formula
+		// FSC_true = FSC_t - FSC_n / ( )
+		fsc_true.resize(fsc_masked);
+		FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(fsc_true)
+		{
+			if (i < randomize_at)
+			{
+				DIRECT_A1D_ELEM(fsc_true, i) = DIRECT_A1D_ELEM(fsc_masked, i);
+			}
+			else
+			{
+				double fsct = DIRECT_A1D_ELEM(fsc_masked, i);
+				double fscn = DIRECT_A1D_ELEM(fsc_random_masked, i);
+				if (fscn > fsct)
+					DIRECT_A1D_ELEM(fsc_true, i) = 0.;
+				else
+					DIRECT_A1D_ELEM(fsc_true, i) = (fsct - fscn) / (1. - fscn);
+			}
+		}
+
+		// Now re-read the original maps yet again into memory
+		I1.read(fn_I1);
+		I2.read(fn_I2);
+		I1().setXmippOrigin();
+		I2().setXmippOrigin();
+
+	}
+	else
+	{
+		fsc_true = fsc_unmasked;
+	}
+
+	global_resol = 999.;
+	// See where corrected FSC drops below 0.143
+	FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(fsc_true)
+	{
+		if ( DIRECT_A1D_ELEM(fsc_true, i) < 0.143)
+			break;
+		global_resol = XSIZE(I1())*angpix/(double)i;
+	}
+
+	// Add the two half-maps together for subsequent sharpening
+	I1() += I2();
+
+	// Divide by MTF and perform FSC-weighted B-factor sharpening, as in Rosenthal and Henderson, 2003
+	// also low-pass filters...
+	sharpenMap();
+
+	// Write original and corrected FSC curve, Guinier plot, etc.
+	writeOutput();
+
+}
diff --git a/src/postprocessing.h b/src/postprocessing.h
new file mode 100644
index 0000000..aed30c1
--- /dev/null
+++ b/src/postprocessing.h
@@ -0,0 +1,151 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef POSTPROCESSING_H_
+#define POSTPROCESSING_H_
+
+#include "src/image.h"
+#include "src/multidim_array.h"
+#include "src/metadata_table.h"
+#include <src/fftw.h>
+#include <src/time.h>
+#include <src/mask.h>
+#include <src/funcs.h>
+
+
+
+class Postprocessing
+{
+public:
+
+	// I/O Parser
+	IOParser parser;
+
+	// Verbosity
+	int verb;
+
+	// Input & Output rootname
+	FileName fn_in, fn_out, fn_I1, fn_I2;
+
+	// Images for the two half-reconstructions and the mask
+	Image<double> I1, I2, I1phi, I2phi, Im;
+
+	// Pixel size in Angstroms
+	double angpix;
+
+	/////// Masking
+
+	// Perform automated masking (based on a density threshold)
+	bool do_auto_mask;
+
+	// Density threshold below which to calculate initial mask seed
+	double ini_mask_density_threshold;
+
+	// Number of pixels to extend the mask beyond the initial mask seed
+	double extend_ini_mask;
+
+	// Width (in pixels) for soft mask edge
+	double width_soft_mask_edge;
+
+	// From the resolution where the FSC drops below this value, randomize the phases in the two maps
+	double randomize_fsc_at;
+
+	// Filename for a user-provided mask
+	FileName fn_mask;
+
+	//////// Sharpening
+
+	// Filename for the STAR-file with the MTF of the detector
+	FileName fn_mtf;
+
+	// Flag to indicate whether to perform Rosenthal&Henderson-2003 like B-factor estimation
+	bool do_auto_bfac;
+
+	// Flag to indicate whether we'll do masking
+	bool do_mask;
+
+	// Minimum and maximum resolution to use in the fit
+	double fit_minres, fit_maxres;
+
+	// User-provided (ad hoc) B-factor
+	double adhoc_bfac;
+
+	///////// Filtering
+
+	// Flag to indicate whether to use FSC-weighting before B-factor sharpening
+	bool do_fsc_weighting;
+
+	// Frequency at which to low-pass filter the final map
+	double low_pass_freq;
+
+	// Width of raised cosine edge on low-pass filter
+	int filter_edge_width;
+
+	// Arrays to store FSC, Guinier curves etc
+	MultidimArray<double> fsc_unmasked;
+	MultidimArray<double> fsc_masked, fsc_random_masked, fsc_true;
+	double global_intercept, global_slope, global_corr_coeff, global_bfactor, global_resol;
+	// The Guinier plots
+	std::vector<fit_point2D>  guinierin, guinierinvmtf, guinierweighted, guiniersharpen;
+
+public:
+	// Read command line arguments
+	void read(int argc, char **argv);
+
+	// Print usage instructions
+	void usage();
+
+	// Set parameters to some useful defaults
+	void clear();
+
+	// Initialise some stuff after reading
+	void initialise();
+
+	// Generate the mask (or read it from file)
+	// Returns true if masking needs to be done, false otherwise
+	bool getMask();
+
+	// Make a mask automatically based on initial density threshold
+	void getAutoMask();
+
+	// Divide by MTF and perform FSC-weighted B-factor sharpening, as in Rosenthal and Henderson, 2003
+	void sharpenMap();
+
+	// This divides the input FT by the mtf (if fn_mtf !="")
+	void divideByMtf(MultidimArray<Complex > &FT);
+
+	// Make a Guinier plot from the Fourier transform of an image
+	void makeGuinierPlot(MultidimArray<Complex > &FT, std::vector<fit_point2D> &guinier);
+
+	// Apply sqrt(2FSC/(FSC=1)) weighting prior to B-factor sharpening
+	void applyFscWeighting(MultidimArray<Complex > &FT, MultidimArray<double> my_fsc);
+
+	// Output map and STAR files with metadata, also write final resolution to screen
+	void writeOutput();
+
+	// Write XML file for EMDB submission
+	void writeFscXml(MetaDataTable &MDfsc);
+
+	// General Running
+	void run();
+
+};
+
+#endif /* POSTPROCESSING_H_ */
diff --git a/src/preprocessing.cpp b/src/preprocessing.cpp
new file mode 100644
index 0000000..a171b38
--- /dev/null
+++ b/src/preprocessing.cpp
@@ -0,0 +1,849 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/preprocessing.h"
+
+void Preprocessing::read(int argc, char **argv, int rank)
+{
+
+	parser.setCommandLine(argc, argv);
+	int gen_section = parser.addSection("General options");
+	fn_out = parser.getOption("--o", "Output rootname", "particles");
+	// Dont allow for directories here!
+	fn_out = fn_out.removeDirectories();
+
+	int particle_section = parser.addSection("Particle selection");
+	fns_coords_in = parser.getOption("--coord_files", "The coordinate files for all particles to be output (may contain wildcards e.g. \"mics/*.box\" or \"mics/???.star\" )","");
+	fn_star_in = parser.getOption("--mic_star", "The STAR file with all (selected) micrographs to extract particles from","");
+	fn_pick_suffix = parser.getOption("--coord_suffix", "The suffix for the coordinate files, e.g. \"_picked.star\" or \".box\"","");
+
+	int extract_section = parser.addSection("Particle extraction");
+	do_extract = parser.checkOption("--extract", "Extract all particles from the micrographs");
+	extract_size = textToInteger(parser.getOption("--extract_size", "Size of the box to extract the particles in (in pixels)", "-1"));
+	extract_bias_x  = textToInteger(parser.getOption("--extract_bias_x", "Bias in X-direction of picked particles (this value in pixels will be added to the coords)", "0"));
+	extract_bias_y  = textToInteger(parser.getOption("--extract_bias_y", "Bias in Y-direction of picked particles (this value in pixels will be added to the coords)", "0"));
+	do_movie_extract = parser.checkOption("--extract_movies", "Extract particles from movie stacks (e.g. from DDDs)");
+	avg_n_frames = textToInteger(parser.getOption("--avg_movie_frames", "Average over this number of individual movie frames", "1"));
+	movie_first_frame = textToInteger(parser.getOption("--first_movie_frame", "Extract from this movie frame onwards", "1"));
+	movie_first_frame--; // (start counting at 0, not 1)
+	movie_last_frame = textToInteger(parser.getOption("--last_movie_frame", "Extract until this movie frame (default=all movie frames)", "0"));
+	movie_last_frame--; // (start counting at 0, not 1)
+	fn_movie = parser.getOption("--movie_rootname", "Common name to relate movies to the single micrographs (e.g. mic001_movie.mrcs related to mic001.mrc)", "movie");
+
+	int perpart_section = parser.addSection("Particle operations");
+	do_project_3d = parser.checkOption("--project3d", "Project sub-tomograms along Z to generate 2D particles");
+	scale  = textToInteger(parser.getOption("--scale", "Re-scale the particles to this size (in pixels)", "-1"));
+	window  = textToInteger(parser.getOption("--window", "Re-window the particles to this size (in pixels)", "-1"));
+	do_normalise = parser.checkOption("--norm", "Normalise the background to average zero and stddev one");
+	bg_radius = textToInteger(parser.getOption("--bg_radius", "Radius of the circular mask that will be used to define the background area (in pixels)", "-1"));
+	white_dust_stddev = textToFloat(parser.getOption("--white_dust", "Sigma-values above which white dust will be removed (negative value means no dust removal)","-1"));
+	black_dust_stddev = textToFloat(parser.getOption("--black_dust", "Sigma-values above which black dust will be removed (negative value means no dust removal)","-1"));
+	do_invert_contrast = parser.checkOption("--invert_contrast", "Invert the contrast in the input images");
+	fn_operate_in = parser.getOption("--operate_on", "The operations above are applied to all extracted particles. Use this option to operate on an input stack/STAR file", "");
+
+	// Initialise verb for non-parallel execution
+	verb = 1;
+
+	if (!( checkParameter(argc, argv, "--o") || checkParameter(argc, argv, "--operate_on") ))
+		REPORT_ERROR("Provide either --o or --operate_on");
+
+	// Check for errors in the command-line option
+	if (parser.checkForErrors())
+		REPORT_ERROR("Errors encountered on the command line (see above), exiting...");
+
+}
+
+void Preprocessing::usage()
+{
+	parser.writeUsage(std::cerr);
+}
+
+void Preprocessing::initialise()
+{
+
+	if (fns_coords_in == "" && fn_star_in == "" && fn_operate_in == "" && !do_join_starfile)
+		REPORT_ERROR("Provide either --extract, --join_starfile or --operate_on");
+
+	// Set up which coordinate files to extract particles from (or to join STAR file for)
+	do_join_starfile = false;
+	if (fns_coords_in != "" || fn_star_in != "")
+	{
+		do_join_starfile = true;
+		if (do_extract && verb > 0)
+		{
+			if (extract_size < 0)
+				REPORT_ERROR("Preprocessing::initialise ERROR: please provide the size of the box to extract particle using --extract_size ");
+
+			std::cout << " Extract particles based on the following coordinate files: " << std::endl;
+		}
+		else if (!do_extract && verb > 0)
+		{
+			std::cout << " Creating output STAR file for particles based on the following coordinate files: " << std::endl;
+		}
+
+		// Get the filenames of all micrographs to be processed by CTFFIND
+		if (fns_coords_in != "")
+		{
+			fns_coords_in.globFiles(fn_coords);
+		}
+		else if (fn_star_in != "")
+		{
+			MetaDataTable MDmics;
+			MDmics.read(fn_star_in);
+			if (!MDmics.containsLabel(EMDL_MICROGRAPH_NAME))
+				REPORT_ERROR("Preprocessing::initialise ERROR: Input micrograph STAR file has no rlnMicrographName column!");
+			fn_coords.clear();
+			FileName fn_mic;
+			FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDmics)
+			{
+				MDmics.getValue(EMDL_MICROGRAPH_NAME, fn_mic);
+				fn_mic = fn_mic.withoutExtension() + fn_pick_suffix;
+				if (exists(fn_mic))
+					fn_coords.push_back(fn_mic);
+				else if (verb > 0)
+					std::cout << "Warning: coordinate file " << fn_mic << " does not exist..." << std::endl;
+			}
+		}
+
+		if (verb > 0)
+			for(unsigned  int  i = 0; i < fn_coords.size(); ++i)
+				std::cout << "  * " << fn_coords[i] << std::endl;
+	}
+
+
+	if (do_extract || fn_operate_in != "")
+	{
+		// Check whether to do re-scaling
+		do_rescale = (scale > 0);
+		if (do_rescale && scale%2 != 0)
+			REPORT_ERROR("ERROR: only re-scaling to even-sized images is allowed in RELION...");
+
+		// Check whether to do re-windowing
+		do_rewindow = (window > 0);
+		if (do_rewindow && window%2 != 0)
+			REPORT_ERROR("ERROR: only re-windowing to even-sized images is allowed in RELION...");
+
+		// Check for bg_radius in case of normalisation
+		if (do_normalise && bg_radius < 0)
+			REPORT_ERROR("ERROR: please provide a radius for a circle that defines the background area when normalising...");
+	}
+
+}
+
+void Preprocessing::run()
+{
+
+	if (do_extract)
+		runExtractParticles();
+
+	if (do_join_starfile)
+		joinAllStarFiles();
+
+	if (fn_operate_in != "")
+		runOperateOnInputFile(fn_operate_in);
+
+	if (verb > 0)
+		std::cout << " Done!" <<std::endl;
+}
+
+
+void Preprocessing::joinAllStarFiles()
+{
+
+	MetaDataTable MDout, MDonestack;
+
+	// Fix order of the labels in the output file
+	MDout.addLabel(EMDL_MICROGRAPH_NAME);
+	MDout.addLabel(EMDL_IMAGE_COORD_X);
+	MDout.addLabel(EMDL_IMAGE_COORD_Y);
+	MDout.addLabel(EMDL_IMAGE_NAME);
+
+	std::cout << " Joining all metadata in one STAR file..." << std::endl;
+	bool has_other_ctfs, has_this_ctf;
+	double defU, defV, defAng, CC, HT, CS, AmpCnst, XMAG, DStep;
+	has_other_ctfs = false;
+	FileName prev_fn_mic="";
+	for (long int ipos = 0; ipos < fn_coords.size(); ipos++)
+    {
+		FileName fn_mic = getMicrographNameFromRootName((fn_coords[ipos]).withoutExtension());
+		// If the micrograph did not exist, particles were not extracted: just continue with the next one
+		if (fn_mic == "")
+			continue;
+
+		if (fn_mic != prev_fn_mic)
+		{
+			FileName fn_microot = getRootNameFromMicrographName(fn_mic);
+			// Gather the results from ctffind
+			has_this_ctf = getCtffind3Results(fn_microot, defU, defV, defAng, CC,
+					HT, CS, AmpCnst, XMAG, DStep);
+
+		}
+		prev_fn_mic = fn_mic;
+
+			// Re-scaled detector pixel size
+		if (has_this_ctf && do_rescale)
+                    DStep *= (double)extract_size/(double)scale;
+
+		if (ipos == 0 && has_this_ctf)
+		{
+			// Set has_other_ctfs to true if the first micrograph has a logfile
+			// In that case add all CTF labels to the output MDtable
+			has_other_ctfs = true;
+			MDout.addLabel(EMDL_CTF_DEFOCUSU);
+			MDout.addLabel(EMDL_CTF_DEFOCUSV);
+			MDout.addLabel(EMDL_CTF_DEFOCUS_ANGLE);
+			MDout.addLabel(EMDL_CTF_VOLTAGE);
+			MDout.addLabel(EMDL_CTF_CS);
+			MDout.addLabel(EMDL_CTF_Q0);
+			MDout.addLabel(EMDL_CTF_MAGNIFICATION);
+			MDout.addLabel(EMDL_CTF_DETECTOR_PIXEL_SIZE);
+			MDout.addLabel(EMDL_CTF_FOM);
+		}
+
+		if (!has_this_ctf && has_other_ctfs)
+			REPORT_ERROR("joinAllStarFiles%ERROR: Exiting because of missing CTFFIND3 logfiles for micrograph " + fn_mic);
+
+		if (has_this_ctf && !has_other_ctfs)
+			REPORT_ERROR("joinAllStarFiles%ERROR: Exiting because of missing CTFFIND3 logfiles ...");
+
+
+		FileName fn_star = "Particles/" + fn_mic.withoutExtension() + "_" + fn_out + ".star";
+		MDonestack.read(fn_star);
+
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDonestack)
+		{
+			// This was double, right?
+			//MDonestack.setValue(EMDL_MICROGRAPH_NAME, fn_mic);
+
+			if (has_this_ctf)
+			{
+				MDonestack.setValue(EMDL_CTF_DEFOCUSU, defU);
+				MDonestack.setValue(EMDL_CTF_DEFOCUSV, defV);
+				MDonestack.setValue(EMDL_CTF_DEFOCUS_ANGLE, defAng);
+				MDonestack.setValue(EMDL_CTF_VOLTAGE, HT);
+				MDonestack.setValue(EMDL_CTF_Q0, AmpCnst);
+				MDonestack.setValue(EMDL_CTF_CS, CS);
+				MDonestack.setValue(EMDL_CTF_MAGNIFICATION, XMAG);
+				MDonestack.setValue(EMDL_CTF_DETECTOR_PIXEL_SIZE, DStep);
+				MDonestack.setValue(EMDL_CTF_FOM, CC);
+			}
+
+			// Add the entire line to the joined STAR-file
+			MDout.addObject(MDonestack.getObject());
+
+			// Remove the individual star file to clean up
+			//remove(fn_star.c_str());
+		}
+
+    }
+
+	// Write out the joined star file
+	FileName fn_tmp;
+	if (do_movie_extract)
+		fn_tmp = fn_out + "_" + fn_movie + ".star";
+	else
+		fn_tmp = fn_out + ".star";
+	MDout.write(fn_tmp);
+	std::cout << " Written out STAR file with all particles in " << fn_tmp << std::endl;
+
+}
+
+void Preprocessing::runExtractParticles()
+{
+
+	int barstep;
+	if (verb > 0)
+	{
+		std::cout << " Extracting particles from the micrographs ..." << std::endl;
+		init_progress_bar(fn_coords.size());
+		barstep = XMIPP_MAX(1, fn_coords.size() / 60);
+	}
+
+	FileName fn_olddir = "";
+	for (long int ipos = 0; ipos < fn_coords.size(); ipos++)
+    {
+
+		FileName fn_dir = "Particles/" + fn_coords[ipos].beforeLastOf("/");
+		if (fn_dir != fn_olddir)
+		{
+			// Make a Particles directory
+			system(("mkdir -p " + fn_dir).c_str());
+			fn_olddir = fn_dir;
+		}
+
+		if (verb > 0 && ipos % barstep == 0)
+			progress_bar(ipos);
+
+    	extractParticlesFromFieldOfView(fn_coords[ipos]);
+	}
+
+	if (verb > 0)
+		progress_bar(fn_coords.size());
+
+}
+
+
+void Preprocessing::readCoordinates(FileName fn_coord, MetaDataTable &MD)
+{
+    MD.clear();
+
+    bool is_star = (fn_coord.getExtension() == "star");
+    bool is_box = (fn_coord.getExtension() == "box");
+
+    if (is_star)
+	{
+		MD.read(fn_coord);
+		/*
+		bool has_z = MD.containsLabel(EMDL_IMAGE_COORD_Z);
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MD)
+		{
+			Matrix1D<int> onepos(3);
+			MD.getValue(EMDL_IMAGE_COORD_X, XX(onepos));
+			MD.getValue(EMDL_IMAGE_COORD_Y, YY(onepos));
+			if (has_z)
+				MD.getValue(EMDL_IMAGE_COORD_Z, ZZ(onepos));
+			all_pos.push_back(onepos);
+		}
+		*/
+	}
+	else
+	{
+		std::ifstream in(fn_coord.data(), std::ios_base::in);
+		if (in.fail())
+			REPORT_ERROR( (std::string) "Preprocessing::readCoordinates ERROR: File " + fn_coord + " does not exists" );
+
+		// Start reading the ifstream at the top
+		in.seekg(0);
+		std::string line;
+		int n = 0;
+		while (getline(in, line, '\n'))
+		{
+			std::vector<std::string> words;
+			tokenize(line, words);
+
+			if (is_box)
+			{
+				if (words.size() < 4)
+					REPORT_ERROR("Preprocessing::readCoordinates Unexpected number of words on data line of " + fn_coord);
+				int num1 =  textToInteger(words[0]);
+				int num2 =  textToInteger(words[1]);
+				int num3 =  textToInteger(words[2]);
+				int num4 =  textToInteger(words[3]);
+				int xpos = num1 + num3 / 2;
+				int ypos = num2 + num4 / 2;
+
+				MD.addObject();
+				MD.setValue(EMDL_IMAGE_COORD_X, (double)xpos);
+				MD.setValue(EMDL_IMAGE_COORD_Y, (double)ypos);
+			}
+			else // Try reading as plain ASCII....
+			{
+				// The first line might be a special header (as in ximdisp or xmipp2 format)
+				// But could also be a data line (as in plain text format)
+				if (n==0)
+				{
+
+					int num1, num2, num3;
+					bool is_data = false;
+
+					// Ignore lines that do not have at least two integer numbers on it (at this point I do not know dimensionality yet....)
+					if (words.size() > 1 && sscanf(words[0].c_str(), "%d", &num1) && sscanf(words[1].c_str(), "%d", &num2))
+					{
+						MD.addObject();
+						MD.setValue(EMDL_IMAGE_COORD_X, (double)num1);
+						MD.setValue(EMDL_IMAGE_COORD_Y, (double)num2);
+
+						// It could also be a X,Y,Z coordinate...
+						if (words.size() > 2 && sscanf(words[2].c_str(), "%d", &num3))
+							MD.setValue(EMDL_IMAGE_COORD_Z, (double)num3);
+					}
+
+
+				}
+				else
+				{
+					// All other lines contain x, y as first two entries, and possibly a Z-coordinate as well.
+					// Note the Z-coordinate will only be used for 3D micrographs (i.e. tomograms), so the third column for a 2D Ximdisp format will be ignored later on
+					if (words.size() < 2)
+						REPORT_ERROR("Preprocessing::readCoordinates Unexpected number of words on data line of " + fn_coord);
+
+					int num1 = textToInteger(words[0]);
+					int num2 = textToInteger(words[1]);
+					int num3;
+
+					MD.addObject();
+					MD.setValue(EMDL_IMAGE_COORD_X, (double)num1);
+					MD.setValue(EMDL_IMAGE_COORD_Y, (double)num2);
+					// It could also be a X,Y,Z coordinate...
+					if (words.size() > 2 && sscanf(words[2].c_str(), "%d", &num3))
+						MD.setValue(EMDL_IMAGE_COORD_Z, (double)num3);
+
+				}
+			}
+			n++;
+
+		}
+		in.close();
+	}
+}
+
+void Preprocessing::extractParticlesFromFieldOfView(FileName fn_coord)
+{
+	MetaDataTable MDin, MDout;
+
+	// Read in the coordinates file
+	readCoordinates(fn_coord, MDin);
+
+	// Correct for bias in the picked coordinates
+	if (ABS(extract_bias_x) > 0 || ABS(extract_bias_y) > 0)
+	{
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MDin)
+		{
+			double xcoor, ycoor;
+			MDin.getValue(EMDL_IMAGE_COORD_X, xcoor);
+			MDin.getValue(EMDL_IMAGE_COORD_Y, ycoor);
+			xcoor += extract_bias_x;
+			ycoor += extract_bias_y;
+			MDin.setValue(EMDL_IMAGE_COORD_X, xcoor);
+			MDin.setValue(EMDL_IMAGE_COORD_Y, ycoor);
+		}
+	}
+
+	// Warn for small groups
+	int npos = MDin.numberOfObjects();
+	if (npos < 10)
+	{
+		std:: cout << "WARNING: there are only " << npos << " particles in " << fn_coord <<". Consider joining multiple micrographs into one group. "<< std::endl;
+	}
+
+	// Check the micrograph exists
+	FileName fn_mic;
+	fn_mic = getMicrographNameFromRootName(fn_coord.withoutExtension());
+	// Return if the micrograph does not exist
+	if (fn_mic == "")
+	{
+		std::cout << "WARNING: cannot find micrograph for coordinate file " << fn_coord << " with " << npos << " particles" << std::endl;
+		return;
+	}
+
+	// Read the header of the micrograph to see how many frames there are.
+	Image<double> Imic;
+	Imic.read(fn_mic, false, -1, false); // readData = false, select_image = -1, mapData= false, is_2D = true);
+
+	int xdim, ydim, zdim;
+	long int ndim;
+	Imic.getDimensions(xdim, ydim, zdim, ndim);
+	dimensionality = (zdim > 1) ? 3 : 2;
+
+	// Name of the output stack
+	// Add the same root as the output STAR file (that way one could extract two "families" of different particle stacks)
+	FileName fn_output_img_root = "Particles/" + fn_mic.withoutExtension() + "_" + fn_out;
+	// Name of this micrographs STAR file
+	FileName fn_star = fn_output_img_root + ".star";
+
+	// Just to be sure...
+	if (do_movie_extract && ndim < 2)
+		std::cout << "WARNING: movie " << fn_mic << " does not have multiple frames..." << std::endl;
+
+	long int my_current_nr_images = 0;
+	double all_avg = 0;
+	double all_stddev = 0;
+	double all_minval = 99.e99;
+	double all_maxval = -99.e99;
+
+	// To deal with default movie_last_frame value
+	if (movie_last_frame < 0)
+		movie_last_frame = ndim - 1;
+
+	int n_frames = movie_last_frame - movie_first_frame + 1;
+	// The total number of images to be extracted
+	long int my_total_nr_images = npos * n_frames;
+
+	for (long int iframe = movie_first_frame; iframe <= movie_last_frame; iframe += avg_n_frames)
+	{
+		extractParticlesFromOneFrame(MDin, fn_mic, iframe, n_frames, fn_output_img_root, my_current_nr_images, my_total_nr_images,
+				all_avg, all_stddev, all_minval, all_maxval);
+
+		MDout.append(MDin);
+		// Keep track of total number of images extracted thus far
+		my_current_nr_images += npos;
+
+	}
+
+	MDout.setName("images");
+	MDout.write(fn_star);
+
+
+}
+
+// Actually extract particles. This can be from one (average) micrograph or from a single movie frame
+void Preprocessing::extractParticlesFromOneFrame(MetaDataTable &MD,
+		FileName fn_mic, int iframe, int n_frames,
+		FileName fn_output_img_root, long int &my_current_nr_images, long int my_total_nr_images,
+		double &all_avg, double &all_stddev, double &all_minval, double &all_maxval)
+{
+
+	Image<double> Ipart, Imic, Itmp;
+
+	FileName fn_frame;
+	// If movies, then average over avg_n_frames
+	if (n_frames > 1)
+	{
+		for (int ii =0; ii < avg_n_frames; ii++)
+		{
+			int iiframe = iframe + ii;
+			// If we run over the size of the movie, then discard these frames
+			if (iiframe >= n_frames)
+				return;
+			fn_frame.compose(iiframe + 1, fn_mic);
+			if (ii==0)
+			{
+				Imic.read(fn_frame, true, -1, false, true); // readData = true, select_image = -1, mapData= false, is_2D = true
+			}
+			else
+			{
+				Itmp.read(fn_frame, true, -1, false, true); // readData = true, select_image = -1, mapData= false, is_2D = true
+				Imic() += Itmp();
+				Itmp.clear();
+			}
+		}
+	}
+	else
+	{
+		fn_frame = fn_mic;
+		Imic.read(fn_frame);
+	}
+
+	// Now window all particles from the micrograph
+	int ipos = 0;
+	FOR_ALL_OBJECTS_IN_METADATA_TABLE(MD)
+	{
+		double dxpos, dypos, dzpos;
+		long int xpos, ypos, zpos;
+		long int x0, xF, y0, yF, z0, zF;
+		MD.getValue(EMDL_IMAGE_COORD_X, dxpos);
+		MD.getValue(EMDL_IMAGE_COORD_Y, dypos);
+		xpos = (long int)dxpos;
+		ypos = (long int)dypos;
+		x0 = xpos + FIRST_XMIPP_INDEX(extract_size);
+		xF = xpos + LAST_XMIPP_INDEX(extract_size);
+		y0 = ypos + FIRST_XMIPP_INDEX(extract_size);
+		yF = ypos + LAST_XMIPP_INDEX(extract_size);
+		if (dimensionality == 3)
+		{
+			MD.getValue(EMDL_IMAGE_COORD_Z, dzpos);
+			zpos = (long int)dzpos;
+			z0 = zpos + FIRST_XMIPP_INDEX(extract_size);
+			zF = zpos + LAST_XMIPP_INDEX(extract_size);
+		}
+
+		// extract one particle in Ipart
+		if (dimensionality == 3)
+			Imic().window(Ipart(), z0, y0, x0, zF, yF, xF);
+		else
+			Imic().window(Ipart(), y0, x0, yF, xF);
+
+		// Discard particles that are completely outside the micrograph and print a warning
+		if (yF < 0 || y0 >= YSIZE(Imic()) || xF < 0 || x0 >= XSIZE(Imic()) ||
+				(dimensionality==3 &&
+						(zF < 0 || z0 >= ZSIZE(Imic()))
+				)
+			)
+		{
+			REPORT_ERROR("Preprocessing::extractParticlesFromOneFrame ERROR: particle" + integerToString(ipos+1) + " lies completely outside micrograph " + fn_mic);
+		}
+		else
+		{
+			// Check boundaries: fill pixels outside the boundary with the nearest ones inside
+			// This will create lines at the edges, rather than zeros
+			Ipart().setXmippOrigin();
+
+			// X-boundaries
+			if (x0 < 0 || xF >= XSIZE(Imic()) )
+			{
+				FOR_ALL_ELEMENTS_IN_ARRAY3D(Ipart())
+				{
+					if (j + xpos < 0)
+						A3D_ELEM(Ipart(), k, i, j) = A3D_ELEM(Ipart(), k, i, -xpos);
+					else if (j + xpos >= XSIZE(Imic()))
+						A3D_ELEM(Ipart(), k, i, j) = A3D_ELEM(Ipart(), k, i, XSIZE(Imic()) - xpos - 1);
+				}
+			}
+
+			// Y-boundaries
+			if (y0 < 0 || yF >= YSIZE(Imic()))
+			{
+				FOR_ALL_ELEMENTS_IN_ARRAY3D(Ipart())
+				{
+					if (i + ypos < 0)
+						A3D_ELEM(Ipart(), k, i, j) = A3D_ELEM(Ipart(), k, -ypos, j);
+					else if (i + ypos >= YSIZE(Imic()))
+						A3D_ELEM(Ipart(), k, i, j) = A3D_ELEM(Ipart(), k, YSIZE(Imic()) - ypos - 1, j);
+				}
+			}
+
+			if (dimensionality == 3)
+			{
+				// Z-boundaries
+				if (z0 < 0 || zF >= ZSIZE(Imic()))
+				{
+					FOR_ALL_ELEMENTS_IN_ARRAY3D(Ipart())
+					{
+						if (k + zpos < 0)
+							A3D_ELEM(Ipart(), k, i, j) = A3D_ELEM(Ipart(), -zpos, i, j);
+						else if (k + zpos >= ZSIZE(Imic()))
+							A3D_ELEM(Ipart(), k, i, j) = A3D_ELEM(Ipart(), ZSIZE(Imic()) - zpos - 1, i, j);
+					}
+				}
+			}
+
+			//
+			if (dimensionality == 3 && do_project_3d)
+			{
+				// Project the 3D sub-tomogram into a 2D particle again
+				Image<double> Iproj(YSIZE(Ipart()), XSIZE(Ipart()));
+				Iproj().setXmippOrigin();
+				FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY3D(Ipart())
+				{
+					DIRECT_A2D_ELEM(Iproj(), i, j) += DIRECT_A3D_ELEM(Ipart(), k, i, j);
+				}
+				Ipart = Iproj;
+			}
+
+			// performPerImageOperations will also append the particle to the output stack in fn_stack
+			performPerImageOperations(Ipart, fn_output_img_root, n_frames, my_current_nr_images + ipos, my_total_nr_images, all_avg, all_stddev, all_minval, all_maxval);
+
+			// Also store all the particles information in the STAR file
+			FileName fn_img;
+			if (Ipart().getDim() == 3)
+				fn_img.compose(fn_output_img_root, my_current_nr_images + ipos + 1, "mrc");
+			else
+				fn_img.compose(my_current_nr_images + ipos + 1, fn_output_img_root + ".mrcs"); // start image counting in stacks at 1!
+			if (do_movie_extract)
+			{
+				FileName fn_part, fn_mic;
+				long int dum;
+				fn_frame.decompose(dum, fn_mic);
+				fn_part.compose(ipos + 1,  "Particles/" + getRootNameFromMicrographName(fn_mic)); // start image counting in stacks at 1!
+				// for automated re-alignment of particles in relion_refine: have rlnParticleName equal to rlnImageName in non-movie star file
+				fn_part += "_" + fn_out + ".mrcs";
+				MD.setValue(EMDL_PARTICLE_NAME, fn_part);
+			}
+			MD.setValue(EMDL_IMAGE_NAME, fn_img);
+			MD.setValue(EMDL_MICROGRAPH_NAME, fn_frame);
+		}
+		ipos++;
+	}
+
+
+}
+
+
+void Preprocessing::runOperateOnInputFile(FileName fn_operate_on)
+{
+	Image<double> Ipart, Iout;
+	MetaDataTable MD;
+	long int Nimg;
+
+	FileName fn_stack = fn_out+".mrcs";
+	FileName fn_star = fn_out+".star";
+
+	if (fn_operate_on.isStarFile())
+	{
+		// Readt STAR file and get total number of images
+		MD.read(fn_operate_on);
+		Nimg = 0;
+		FOR_ALL_OBJECTS_IN_METADATA_TABLE(MD)
+		{
+			Nimg++;
+		}
+		MD.firstObject(); // reset pointer to the first object in the table
+	}
+	else
+	{
+		// Read the header of the stack to see how many images there
+		Iout.read(fn_operate_on, false);
+		Nimg = NSIZE(Iout());
+	}
+
+	double all_avg = 0;
+	double all_stddev = 0;
+	double all_minval = 99.e99;
+	double all_maxval = -99.e99;
+	init_progress_bar(Nimg);
+	int barstep = XMIPP_MAX(1, Nimg / 120);
+	for (long int i = 0; i < Nimg; i++)
+	{
+		FileName fn_tmp;
+
+		// Read in individual miages from the stack
+		Ipart.clear();
+		if (fn_operate_on.isStarFile())
+		{
+			MD.getValue(EMDL_IMAGE_NAME, fn_tmp);
+			Ipart.read(fn_tmp);
+
+			// Set the new name at this point in the MDtable, e.g. as 000001 at out.mrcs
+			fn_tmp.compose(i+1,fn_stack);
+			MD.setValue(EMDL_IMAGE_NAME, fn_tmp);
+			if (i < (Nimg - 1))
+				MD.nextObject();
+		}
+		else
+		{
+			Ipart.read(fn_operate_on, true, i);
+			// Set the new name at this point in the MDtable, e.g. as 000001 at out.mrcs
+			fn_tmp.compose(i+1,fn_stack);
+			MD.addObject();
+			MD.setValue(EMDL_IMAGE_NAME, fn_tmp);
+		}
+
+		performPerImageOperations(Ipart, fn_stack, 1, i, Nimg, all_avg, all_stddev, all_minval, all_maxval);
+
+		// progress bar
+		if (i % barstep == 0) progress_bar(i);
+
+	}
+	progress_bar(Nimg);
+
+	std::cout << " Done writing to " << fn_stack << std::endl;
+	MD.setName("images");
+	MD.write(fn_star);
+	std::cout << " Also written a STAR file with the image names as " << fn_star << std::endl;
+
+}
+
+
+void Preprocessing::performPerImageOperations(Image<double> &Ipart, FileName fn_output_img_root, int nframes, long int image_nr, long int nr_of_images,
+		double &all_avg, double &all_stddev, double &all_minval, double &all_maxval)
+{
+
+	Ipart().setXmippOrigin();
+
+	if (do_rescale) rescale(Ipart, scale);
+
+	if (do_rewindow) rewindow(Ipart, window);
+
+	if (do_normalise) normalise(Ipart, bg_radius, white_dust_stddev, black_dust_stddev);
+
+	if (do_invert_contrast) invert_contrast(Ipart);
+
+	// For movies: multiple the image intensities by sqrt(nframes) so the stddev in the average of the normalised frames is again 1
+	if (nframes > 1)
+		Ipart() *= sqrt((double)nframes/(double)avg_n_frames);
+
+	// Calculate mean, stddev, min and max
+	double avg, stddev, minval, maxval;
+	Ipart().computeStats(avg, stddev, minval, maxval);
+
+	if (Ipart().getDim() == 3)
+	{
+		Ipart.MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN, minval);
+		Ipart.MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX, maxval);
+		Ipart.MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG, avg);
+		Ipart.MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV, stddev);
+
+		// Write one mrc file for every subtomogram
+		FileName fn_img;
+		fn_img.compose(fn_output_img_root, image_nr + 1, "mrc");
+		Ipart.write(fn_img);
+
+	}
+	else
+	{
+		// Keep track of overall statistics
+		all_minval = XMIPP_MIN(minval, all_minval);
+		all_maxval = XMIPP_MAX(maxval, all_maxval);
+		all_avg	+= avg;
+		all_stddev += stddev*stddev;
+
+		// Last particle: reset the min, max, avg and stddev values in the main header
+		if (image_nr == (nr_of_images - 1))
+		{
+			all_avg /= nr_of_images;
+			all_stddev = sqrt(all_stddev/nr_of_images);
+			Ipart.MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN, all_minval);
+			Ipart.MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX, all_maxval);
+			Ipart.MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG, all_avg);
+			Ipart.MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV, all_stddev);
+		}
+
+		// Write this particle to the stack on disc
+		// First particle: write stack in overwrite mode, from then on just append to it
+		if (image_nr == 0)
+			Ipart.write(fn_output_img_root+".mrcs", -1, (nr_of_images > 1), WRITE_OVERWRITE);
+		else
+			Ipart.write(fn_output_img_root+".mrcs", -1, false, WRITE_APPEND);
+	}
+
+}
+
+FileName Preprocessing::getMicrographNameFromRootName(FileName fn_root)
+{
+	FileName fn_mic, fn_mic_nos;
+	//Search the unique part of the micrograph name (i.e. coord name may have additional text after the micrograph name without extension...
+	// e.g. fn_root="mic001_all.pos" may correspond to mic001.mrc
+	for (int i = 0; i < fn_root.length(); i++)
+	{
+		if (do_movie_extract)
+		{
+			fn_mic = fn_root.substr(0, fn_root.length() - i) + "_" + fn_movie + ".mrcs";
+			// For movies also allow name without the s of .mrcs
+			fn_mic_nos = fn_root.substr(0, fn_root.length() - i) + "_" + fn_movie + ".mrc";
+		}
+		else
+			fn_mic = fn_root.substr(0, fn_root.length() - i) + ".mrc";
+		std::vector<FileName> fn_mics;
+		if (fn_mic.globFiles(fn_mics) == 1)
+		{
+			fn_mic = fn_mics[0];
+			break;
+		}
+		else if (do_movie_extract && fn_mic_nos.globFiles(fn_mics) == 1)
+		{
+			// For movies also allow name without the s of .mrcs
+			fn_mic = fn_mics[0];
+			break;
+		}
+		if (i == fn_root.length() - 1)
+		{
+			return "";
+		}
+	}
+
+	return fn_mic;
+
+}
+
+FileName Preprocessing::getRootNameFromMicrographName(FileName fn_mic)
+{
+	if (do_movie_extract)
+	{
+		if (fn_mic.contains(".mrcs"))
+			return fn_mic.without("_" + fn_movie + ".mrcs");
+		else if (fn_mic.contains(".mrc"))
+			return fn_mic.without("_" + fn_movie + ".mrc");
+		else
+			REPORT_ERROR("Preprocessing::getRootNameFromMicrographName ERROR: movie name does not end in \"_\" + movie-identifier + \".mrc\" or \".mrcs\"");
+	}
+	else
+		return fn_mic.without(".mrc");
+
+
+}
diff --git a/src/preprocessing.h b/src/preprocessing.h
new file mode 100644
index 0000000..d345ad3
--- /dev/null
+++ b/src/preprocessing.h
@@ -0,0 +1,167 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+
+#ifndef PREPROCESSING_H_
+#define PREPROCESSING_H_
+#include  <glob.h>
+#include  <vector>
+#include  <string>
+#include  <stdlib.h>
+#include  <stdio.h>
+#include "src/image.h"
+#include "src/multidim_array.h"
+#include "src/metadata_table.h"
+#include "src/ctffind_runner.h"
+#include <src/fftw.h>
+#include <src/time.h>
+
+class Preprocessing
+{
+public:
+
+	// I/O Parser
+	IOParser parser;
+
+	// Verbosity
+	int verb;
+
+	// Output rootname
+	FileName fn_in, fn_out;
+
+	////////////////////////////////////// Extract particles from the micrographs
+	// Perform particle extraction?
+	bool do_extract;
+
+	// Extract particles from movies instead of single micrographs
+	bool do_movie_extract;
+
+	// First frame to extract from movies
+	int movie_first_frame;
+
+	// Last frame to extract from movies
+	int movie_last_frame;
+
+	// Number of individual movie frames to average over
+	int avg_n_frames;
+
+	// Rootname to identify movies, e.g. mic001_movie.mrcs will be the movie of mic001.mrc if fn_movie="movie"
+	FileName fn_movie;
+
+	// Filenames (may include wildcards) for all coordinate files to be used for particle extraction
+	FileName fns_coords_in;
+
+	// Alternative niput: STAR file with all (selected) micrographs and their rootname for the picked coordinates files
+	FileName fn_star_in, fn_pick_suffix;
+
+	// Filenames of all the coordinate files to use for particle extraction
+	std::vector<FileName> fn_coords;
+
+	// Dimensionality of the micrographs (2 for normal micrographs, 3 for tomograms)
+	int dimensionality;
+
+	// Flag to project subtomograms along Z
+	bool do_project_3d;
+
+	// Box size to extract the particles in
+	int extract_size;
+
+	// Bias in picked coordinates in X and in Y direction (in pixels)
+	double extract_bias_x, extract_bias_y;
+
+	////////////////////////////////////// Post-extraction image modifications
+	// Perform re-scaling of extracted images
+	bool do_rescale;
+	int scale;
+
+	// Perform re-windowing of extracted images
+	bool do_rewindow;
+	int window;
+
+	// Perform normalization of the extract images
+	bool do_normalise;
+
+	// Perform contrast inversion of the extracted images
+	bool do_invert_contrast;
+
+	// Standard deviations to remove black and white dust
+	double white_dust_stddev, black_dust_stddev;
+
+	// Radius of a circle in the extracted images outside of which one calculates background mean and stddev
+	int bg_radius;
+
+	// Use input stack to perform the image modifications
+	FileName fn_operate_in;
+
+	// Name of output stack (only when fn_operate in is given)
+	FileName fn_operate_out;
+
+	//////////////////////////////////// Output STAR file
+	bool do_join_starfile;
+
+public:
+	// Read command line arguments
+	void read(int argc, char **argv, int rank = 0);
+
+	// Print usage instructions
+	void usage();
+
+	// Initialise some stuff after reading
+	void initialise();
+
+	// General Running
+	void run();
+
+	// join all STAR files into one
+	// This is done separate from runExtractParticles to allow particle extraction to be done in parallel...
+	void joinAllStarFiles();
+
+	// Extract particles from the micrographs
+	void runExtractParticles();
+
+	// Read coordinates from text files
+	void readCoordinates(FileName fn_coord, MetaDataTable &MD);
+
+	// For the given coordinate file, read the micrograph and/or movie and extract all particles
+	void extractParticlesFromFieldOfView(FileName fn_coord);
+
+	// Actually extract particles. This can be from one (average) micrgraph or from a single frame from a movie
+	void extractParticlesFromOneFrame(MetaDataTable &MD,
+			FileName fn_mic, int iframe, int n_frames, FileName fn_output_img_root, long int &my_current_nr_images, long int my_total_nr_images,
+			double &all_avg, double &all_stddev, double &all_minval, double &all_maxval);
+
+	// Perform per-image operations (e.g. normalise, rescaling, rewindowing and inverting contrast) on an input stack (or STAR file)
+	void runOperateOnInputFile(FileName fn_perimage_in);
+
+	// Here normalisation, windowing etc is performed on an individual image and it is written to disc
+	void performPerImageOperations(Image<double> &Ipart, FileName fn_output_img_root, int nframes, long int image_nr, long int nr_of_images,
+			double &all_avg, double &all_stddev, double &all_minval, double &all_maxval);
+
+	// Get micrograph name from the rootname
+	// The rootname may have an additional string after the uniqye micrograph name
+	// That way, multiple "families" of distinct particle types may be extracted from the same micrographs
+	FileName getMicrographNameFromRootName(FileName fn_root);
+
+	// The inverse of the function above
+	FileName getRootNameFromMicrographName(FileName fn_mic);
+
+};
+
+#endif /* PREPROCESSING_H_ */
diff --git a/src/preprocessing_mpi.cpp b/src/preprocessing_mpi.cpp
new file mode 100644
index 0000000..5c3099e
--- /dev/null
+++ b/src/preprocessing_mpi.cpp
@@ -0,0 +1,107 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/preprocessing_mpi.h"
+
+void PreprocessingMpi::read(int argc, char **argv)
+{
+    // Define a new MpiNode
+    node = new MpiNode(argc, argv);
+
+    // First read in non-parallelisation-dependent variables
+    Preprocessing::read(argc, argv, node->rank);
+
+    // Don't put any output to screen for mpi slaves
+    verb = (node->isMaster()) ? 1 : 0;
+
+    // Possibly also read parallelisation-dependent variables here
+
+    // Print out MPI info
+	printMpiNodesMachineNames(*node);
+
+
+}
+
+
+void PreprocessingMpi::runExtractParticles()
+{
+
+	// Each node does part of the work
+	long int my_first_coord, my_last_coord, my_nr_coords;
+	divide_equally(fn_coords.size(), node->size, node->rank, my_first_coord, my_last_coord);
+	my_nr_coords = my_last_coord - my_first_coord + 1;
+
+	int barstep;
+	if (verb > 0)
+	{
+		std::cout << " Extracting particles from the micrographs ..." << std::endl;
+		init_progress_bar(my_nr_coords);
+		barstep = XMIPP_MAX(1, my_nr_coords / 60);
+
+		// Make a Particles directory
+		system("mkdir -p Particles");
+	}
+
+	FileName fn_olddir = "";
+	for (long int ipos = my_first_coord; ipos <= my_last_coord; ipos++)
+    {
+		FileName fn_dir = "Particles/" + fn_coords[ipos].beforeLastOf("/");
+		if (fn_dir != fn_olddir)
+		{
+			// Make a Particles directory
+			system(("mkdir -p " + fn_dir).c_str());
+			fn_olddir = fn_dir;
+		}
+
+		if (verb > 0 && ipos % barstep == 0)
+			progress_bar(ipos);
+
+    	extractParticlesFromFieldOfView(fn_coords[ipos]);
+	}
+
+	if (verb > 0)
+		progress_bar(my_nr_coords);
+
+}
+
+
+
+void PreprocessingMpi::run()
+{
+
+	// Extract and operate on particles in parallel
+	if (do_extract)
+	{
+		runExtractParticles();
+
+		// Wait until all nodes have finished to make final star file
+		MPI_Barrier(MPI_COMM_WORLD);
+	}
+
+	if (do_join_starfile && node->isMaster())
+		Preprocessing::joinAllStarFiles();
+
+	// The following has not been parallelised....
+	if (fn_operate_in != "" && node->isMaster())
+		Preprocessing::runOperateOnInputFile(fn_operate_in);
+
+	if (verb > 0)
+		std::cout << " Done!" <<std::endl;
+
+}
diff --git a/src/preprocessing_mpi.h b/src/preprocessing_mpi.h
new file mode 100644
index 0000000..a2ef56d
--- /dev/null
+++ b/src/preprocessing_mpi.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef PREPROCESSING_MPI_H_
+#define PREPROCESSING_MPI_H_
+#include "src/mpi.h"
+#include "src/preprocessing.h"
+#include "src/parallel.h"
+
+class PreprocessingMpi: public Preprocessing
+{
+private:
+	MpiNode *node;
+
+public:
+	/** Destructor, calls MPI_Finalize */
+    ~PreprocessingMpi()
+    {
+        delete node;
+    }
+
+    /** Read
+     * This could take care of mpi-parallelisation-dependent variables
+     */
+    void read(int argc, char **argv);
+
+    // Parallelized run functions
+    void runExtractParticles();
+    void run();
+
+};
+
+#endif /* PREPROCESSING_MPI_H_ */
diff --git a/src/projector.cpp b/src/projector.cpp
new file mode 100644
index 0000000..e4aa431
--- /dev/null
+++ b/src/projector.cpp
@@ -0,0 +1,478 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/projector.h"
+//#define DEBUG
+
+void Projector::initialiseData(int current_size)
+{
+	// By default r_max is half ori_size
+	if (current_size < 0)
+		r_max = ori_size / 2;
+	else
+		r_max = current_size / 2;
+
+	// Never allow r_max beyond Nyquist...
+	r_max = XMIPP_MIN(r_max, ori_size / 2);
+
+	// Set pad_size
+	pad_size = 2 * (padding_factor * r_max + 1) + 1;
+
+	// Short side of data array
+	switch (ref_dim)
+	{
+	case 2:
+	   data.resize(pad_size, pad_size / 2 + 1);
+	   break;
+	case 3:
+	   data.resize(pad_size, pad_size, pad_size / 2 + 1);
+	   break;
+	default:
+	   REPORT_ERROR("Projector::resizeData%%ERROR: Dimension of the data array should be 2 or 3");
+	}
+
+	// Set origin in the y.z-center, but on the left side for x.
+	data.setXmippOrigin();
+	data.xinit=0;
+
+}
+
+void Projector::initZeros(int current_size)
+{
+	initialiseData(current_size);
+	data.initZeros();
+}
+
+long int Projector::getSize()
+{
+	// Short side of data array
+	switch (ref_dim)
+	{
+		case 2:
+		   return pad_size * (pad_size / 2 + 1);
+		   break;
+		case 3:
+		   return pad_size * pad_size * (pad_size / 2 + 1);
+		   break;
+		default:
+		   REPORT_ERROR("Projector::resizeData%%ERROR: Dimension of the data array should be 2 or 3");
+	}
+
+}
+
+// Fill data array with oversampled Fourier transform, and calculate its power spectrum
+void Projector::computeFourierTransformMap(MultidimArray<double> &vol_in, MultidimArray<double> &power_spectrum, int current_size, int nr_threads, bool do_gridding)
+{
+
+	MultidimArray<double> Mpad;
+	MultidimArray<Complex > Faux;
+    FourierTransformer transformer;
+    // DEBUGGING: multi-threaded FFTWs are giving me a headache?
+	// For a long while: switch them off!
+	//transformer.setThreadsNumber(nr_threads);
+    double normfft;
+
+	// Size of padded real-space volume
+	int padoridim = padding_factor * ori_size;
+
+	// Initialize data array of the oversampled transform
+	ref_dim = vol_in.getDim();
+
+	// Make Mpad
+	switch (ref_dim)
+	{
+	case 2:
+	   Mpad.initZeros(padoridim, padoridim);
+	   normfft = (double)(padding_factor * padding_factor);
+	   break;
+	case 3:
+	   Mpad.initZeros(padoridim, padoridim, padoridim);
+	   normfft = (double)(padding_factor * padding_factor * padding_factor * ori_size);
+	   break;
+	default:
+	   REPORT_ERROR("Projector::get2DSlice%%ERROR: Dimension of the data array should be 2 or 3");
+	}
+
+	// First do a gridding pre-correction on the real-space map:
+	// Divide by the inverse Fourier transform of the interpolator in Fourier-space
+	// 10feb11: at least in 2D case, this seems to be the wrong thing to do!!!
+	// Still to check the 3D case...
+	/////////////////// TODO: removed this for subtomo averaging!!!! Go back and check 3d-> 2d projection!!!!!
+	/////////////////// TODO: removed this for subtomo averaging!!!! Go back and check 3d-> 2d projection!!!!!
+	/////////////////// TODO: removed this for subtomo averaging!!!! Go back and check 3d-> 2d projection!!!!!
+	/////////////////// TODO: removed this for subtomo averaging!!!! Go back and check 3d-> 2d projection!!!!!
+	/////////////////// TODO: removed this for subtomo averaging!!!! Go back and check 3d-> 2d projection!!!!!
+	/////////////////// TODO: removed this for subtomo averaging!!!! Go back and check 3d-> 2d projection!!!!!
+	/////////////////// TODO: removed this for subtomo averaging!!!! Go back and check 3d-> 2d projection!!!!!
+	if (do_gridding)
+		griddingCorrect(vol_in);
+
+	// Pad translated map with zeros
+	vol_in.setXmippOrigin();
+	Mpad.setXmippOrigin();
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(vol_in) // This will also work for 2D
+		A3D_ELEM(Mpad, k, i, j) = A3D_ELEM(vol_in, k, i, j);
+
+	// Translate padded map to put origin of FT in the center
+	CenterFFT(Mpad, true);
+
+	// Calculate the oversampled Fourier transform
+	transformer.FourierTransform(Mpad, Faux, false);
+
+	// Free memory: Mpad no longer needed
+	Mpad.clear();
+
+	// Resize data array to the right size and initialise to zero
+	initZeros(current_size);
+
+	// Fill data only for those points with distance to origin less than max_r
+	// (other points will be zero because of initZeros() call above
+	// Also calculate radial power spectrum
+	power_spectrum.initZeros(ori_size / 2 + 1);
+	MultidimArray<double> counter(power_spectrum);
+	counter.initZeros();
+
+	int max_r2 = r_max * r_max * padding_factor * padding_factor;
+	FOR_ALL_ELEMENTS_IN_FFTW_TRANSFORM(Faux) // This will also work for 2D
+	{
+		int r2 = kp*kp + ip*ip + jp*jp;
+		// The Fourier Transforms are all "normalised" for 2D transforms of size = ori_size x ori_size
+		if (r2 <= max_r2)
+		{
+			// Set data array
+			A3D_ELEM(data, kp, ip, jp) = DIRECT_A3D_ELEM(Faux, k, i, j) * normfft;
+
+			// Calculate power spectrum
+			int ires = ROUND( sqrt((double)r2) / padding_factor );
+			// Factor two because of two-dimensionality of the complex plane
+			DIRECT_A1D_ELEM(power_spectrum, ires) += norm(A3D_ELEM(data, kp, ip, jp)) / 2.;
+			DIRECT_A1D_ELEM(counter, ires) += 1.;
+		}
+	}
+
+	// Calculate radial average of power spectrum
+	FOR_ALL_DIRECT_ELEMENTS_IN_ARRAY1D(power_spectrum)
+	{
+		if (DIRECT_A1D_ELEM(counter, i) < 1.)
+			DIRECT_A1D_ELEM(power_spectrum, i) = 0.;
+		else
+			DIRECT_A1D_ELEM(power_spectrum, i) /= DIRECT_A1D_ELEM(counter, i);
+	}
+
+	transformer.cleanup();
+
+}
+
+void Projector::griddingCorrect(MultidimArray<double> &vol_in)
+{
+	// Correct real-space map by dividing it by the Fourier transform of the interpolator(s)
+	vol_in.setXmippOrigin();
+	FOR_ALL_ELEMENTS_IN_ARRAY3D(vol_in)
+	{
+		double r = sqrt((double)(k*k+i*i+j*j));
+		// if r==0: do nothing (i.e. divide by 1)
+		if (r > 0.)
+		{
+			double rval = r / (ori_size * padding_factor);
+			double sinc = sin(PI * rval) / ( PI * rval);
+			//double ftblob = blob_Fourier_val(rval, blob) / blob_Fourier_val(0., blob);
+			// Interpolation (goes with "interpolator") to go from arbitrary to fine grid
+			if (interpolator==NEAREST_NEIGHBOUR && r_min_nn == 0)
+			{
+				// NN interpolation is convolution with a rectangular pulse, which FT is a sinc function
+            	A3D_ELEM(vol_in, k, i, j) /= sinc;
+			}
+			else if (interpolator==TRILINEAR || (interpolator==NEAREST_NEIGHBOUR && r_min_nn > 0) )
+			{
+				// trilinear interpolation is convolution with a triangular pulse, which FT is a sinc^2 function
+				A3D_ELEM(vol_in, k, i, j) /= sinc * sinc;
+			}
+			else
+				REPORT_ERROR("BUG Projector::griddingCorrect: unrecognised interpolator scheme.");
+//#define DEBUG_GRIDDING_CORRECT
+#ifdef DEBUG_GRIDDING_CORRECT
+			if (k==0 && i==0 && j > 0)
+				std::cerr << " j= " << j << " sinc= " << sinc << std::endl;
+#endif
+		}
+	}
+}
+
+void Projector::project(MultidimArray<Complex > &f2d, Matrix2D<double> &A, bool inv)
+{
+	double fx, fy, fz, xp, yp, zp;
+	int x0, x1, y0, y1, z0, z1, y, y2, r2;
+	bool is_neg_x;
+	Complex d000, d001, d010, d011, d100, d101, d110, d111;
+	Complex dx00, dx01, dx10, dx11, dxy0, dxy1;
+	Matrix2D<double> Ainv;
+
+    // f2d should already be in the right size (ori_size,orihalfdim)
+    // AND the points outside r_max should already be zero...
+    // f2d.initZeros();
+
+	// Use the inverse matrix
+    if (inv)
+    	Ainv = A;
+    else
+    	Ainv = A.transpose();
+
+    // The f2d image may be smaller than r_max, in that case also make sure not to fill the corners!
+    int my_r_max = XMIPP_MIN(r_max, XSIZE(f2d) - 1);
+
+    // Go from the 2D slice coordinates to the 3D coordinates
+    Ainv *= (double)padding_factor;  // take scaling into account directly
+    int max_r2 = my_r_max * my_r_max;
+    int min_r2_nn = r_min_nn * r_min_nn;
+
+//#define DEBUG
+#ifdef DEBUG
+    std::cerr << " XSIZE(f2d)= "<< XSIZE(f2d) << std::endl;
+    std::cerr << " YSIZE(f2d)= "<< YSIZE(f2d) << std::endl;
+    std::cerr << " XSIZE(data)= "<< XSIZE(data) << std::endl;
+    std::cerr << " YSIZE(data)= "<< YSIZE(data) << std::endl;
+    std::cerr << " STARTINGX(data)= "<< STARTINGX(data) << std::endl;
+    std::cerr << " STARTINGY(data)= "<< STARTINGY(data) << std::endl;
+    std::cerr << " STARTINGZ(data)= "<< STARTINGZ(data) << std::endl;
+    std::cerr << " max_r= "<< r_max << std::endl;
+    std::cerr << " Ainv= " << Ainv << std::endl;
+#endif
+
+	for (int i=0; i < YSIZE(f2d); i++)
+	{
+		// Dont search beyond square with side max_r
+		if (i <= my_r_max)
+		{
+			y = i;
+		}
+		else if (i >= YSIZE(f2d) - my_r_max)
+		{
+			y = i - YSIZE(f2d);
+		}
+		else
+			continue;
+
+		y2 = y * y;
+		for (int x=0; x <= my_r_max; x++)
+		{
+	    	// Only include points with radius < max_r (exclude points outside circle in square)
+			r2 = x * x + y2;
+			if (r2 > max_r2)
+				continue;
+
+			// Get logical coordinates in the 3D map
+			xp = Ainv(0,0) * x + Ainv(0,1) * y;
+			yp = Ainv(1,0) * x + Ainv(1,1) * y;
+			zp = Ainv(2,0) * x + Ainv(2,1) * y;
+
+			if (interpolator == TRILINEAR || r2 < min_r2_nn)
+			{
+
+				// Only asymmetric half is stored
+				if (xp < 0)
+				{
+					// Get complex conjugated hermitian symmetry pair
+					xp = -xp;
+					yp = -yp;
+					zp = -zp;
+					is_neg_x = true;
+				}
+				else
+				{
+					is_neg_x = false;
+				}
+
+				// Trilinear interpolation (with physical coords)
+				// Subtract STARTINGY and STARTINGZ to accelerate access to data (STARTINGX=0)
+				// In that way use DIRECT_A3D_ELEM, rather than A3D_ELEM
+    			x0 = FLOOR(xp);
+				fx = xp - x0;
+				x1 = x0 + 1;
+
+				y0 = FLOOR(yp);
+				fy = yp - y0;
+				y0 -=  STARTINGY(data);
+				y1 = y0 + 1;
+
+				z0 = FLOOR(zp);
+				fz = zp - z0;
+				z0 -= STARTINGZ(data);
+				z1 = z0 + 1;
+
+				// Matrix access can be accelerated through pre-calculation of z0*xydim etc.
+				d000 = DIRECT_A3D_ELEM(data, z0, y0, x0);
+				d001 = DIRECT_A3D_ELEM(data, z0, y0, x1);
+				d010 = DIRECT_A3D_ELEM(data, z0, y1, x0);
+				d011 = DIRECT_A3D_ELEM(data, z0, y1, x1);
+				d100 = DIRECT_A3D_ELEM(data, z1, y0, x0);
+				d101 = DIRECT_A3D_ELEM(data, z1, y0, x1);
+				d110 = DIRECT_A3D_ELEM(data, z1, y1, x0);
+				d111 = DIRECT_A3D_ELEM(data, z1, y1, x1);
+
+				// Set the interpolated value in the 2D output array
+				dx00 = LIN_INTERP(fx, d000, d001);
+				dx01 = LIN_INTERP(fx, d100, d101);
+				dx10 = LIN_INTERP(fx, d010, d011);
+				dx11 = LIN_INTERP(fx, d110, d111);
+				dxy0 = LIN_INTERP(fy, dx00, dx10);
+				dxy1 = LIN_INTERP(fy, dx01, dx11);
+				DIRECT_A2D_ELEM(f2d, i, x) = LIN_INTERP(fz, dxy0, dxy1);
+
+				// Take complex conjugated for half with negative x
+				if (is_neg_x)
+					DIRECT_A2D_ELEM(f2d, i, x) = conj(DIRECT_A2D_ELEM(f2d, i, x));
+
+			} // endif TRILINEAR
+			else if (interpolator == NEAREST_NEIGHBOUR )
+			{
+				x0 = ROUND(xp);
+				y0 = ROUND(yp);
+				z0 = ROUND(zp);
+				if (x0 < 0)
+					DIRECT_A2D_ELEM(f2d, i, x) = conj(A3D_ELEM(data, -z0, -y0, -x0));
+				else
+					DIRECT_A2D_ELEM(f2d, i, x) = A3D_ELEM(data, z0, y0, x0);
+
+			} // endif NEAREST_NEIGHBOUR
+			else
+				REPORT_ERROR("Unrecognized interpolator in Projector::project");
+
+		} // endif x-loop
+	} // endif y-loop
+
+
+#ifdef DEBUG
+    std::cerr << "done with project..." << std::endl;
+#endif
+}
+
+void Projector::rotate2D(MultidimArray<Complex > &f2d, Matrix2D<double> &A, bool inv)
+{
+	double fx, fy, xp, yp;
+	int x0, x1, y0, y1, y, y2, r2;
+	bool is_neg_x;
+	Complex d00, d01, d10, d11, dx0, dx1;
+	Matrix2D<double> Ainv;
+
+    // f2d should already be in the right size (ori_size,orihalfdim)
+    // AND the points outside max_r should already be zero...
+    // f2d.initZeros();
+	// Use the inverse matrix
+    if (inv)
+    	Ainv = A;
+    else
+    	Ainv = A.transpose();
+
+    // The f2d image may be smaller than r_max, in that case also make sure not to fill the corners!
+    int my_r_max = XMIPP_MIN(r_max, XSIZE(f2d) - 1);
+
+    // Go from the 2D slice coordinates to the map coordinates
+    Ainv *= (double)padding_factor;  // take scaling into account directly
+    int max_r2 = my_r_max * my_r_max;
+    int min_r2_nn = r_min_nn * r_min_nn;
+#ifdef DEBUG
+    std::cerr << " XSIZE(f2d)= "<< XSIZE(f2d) << std::endl;
+    std::cerr << " YSIZE(f2d)= "<< YSIZE(f2d) << std::endl;
+    std::cerr << " XSIZE(data)= "<< XSIZE(data) << std::endl;
+    std::cerr << " YSIZE(data)= "<< YSIZE(data) << std::endl;
+    std::cerr << " STARTINGX(data)= "<< STARTINGX(data) << std::endl;
+    std::cerr << " STARTINGY(data)= "<< STARTINGY(data) << std::endl;
+    std::cerr << " STARTINGZ(data)= "<< STARTINGZ(data) << std::endl;
+    std::cerr << " max_r= "<< r_max << std::endl;
+    std::cerr << " Ainv= " << Ainv << std::endl;
+#endif
+	for (int i=0; i < YSIZE(f2d); i++)
+	{
+		// Don't search beyond square with side max_r
+		if (i <= my_r_max)
+		{
+			y = i;
+		}
+		else if (i >= YSIZE(f2d) - my_r_max)
+		{
+			y = i - YSIZE(f2d);
+		}
+		else
+			continue;
+		y2 = y * y;
+		for (int x=0; x <= my_r_max; x++)
+		{
+	    	// Only include points with radius < max_r (exclude points outside circle in square)
+			r2 = x * x + y2;
+			if (r2 > max_r2)
+				continue;
+
+			// Get logical coordinates in the 3D map
+			xp = Ainv(0,0) * x + Ainv(0,1) * y;
+			yp = Ainv(1,0) * x + Ainv(1,1) * y;
+			if (interpolator == TRILINEAR || r2 < min_r2_nn)
+			{
+				// Only asymmetric half is stored
+				if (xp < 0)
+				{
+					// Get complex conjugated hermitian symmetry pair
+					xp = -xp;
+					yp = -yp;
+					is_neg_x = true;
+				}
+				else
+				{
+					is_neg_x = false;
+				}
+
+				// Trilinear interpolation (with physical coords)
+				// Subtract STARTINGY to accelerate access to data (STARTINGX=0)
+				// In that way use DIRECT_A3D_ELEM, rather than A3D_ELEM
+    			x0 = FLOOR(xp);
+				fx = xp - x0;
+				x1 = x0 + 1;
+
+				y0 = FLOOR(yp);
+				fy = yp - y0;
+				y0 -=  STARTINGY(data);
+				y1 = y0 + 1;
+
+				// Matrix access can be accelerated through pre-calculation of z0*xydim etc.
+				d00 = DIRECT_A2D_ELEM(data, y0, x0);
+				d01 = DIRECT_A2D_ELEM(data, y0, x1);
+				d10 = DIRECT_A2D_ELEM(data, y1, x0);
+				d11 = DIRECT_A2D_ELEM(data, y1, x1);
+
+				// Set the interpolated value in the 2D output array
+				dx0 = LIN_INTERP(fx, d00, d01);
+				dx1 = LIN_INTERP(fx, d10, d11);
+				DIRECT_A2D_ELEM(f2d, i, x) = LIN_INTERP(fy, dx0, dx1);
+				// Take complex conjugated for half with negative x
+				if (is_neg_x)
+					DIRECT_A2D_ELEM(f2d, i, x) = conj(DIRECT_A2D_ELEM(f2d, i, x));
+			} // endif TRILINEAR
+			else if (interpolator == NEAREST_NEIGHBOUR )
+			{
+				x0 = ROUND(xp);
+				y0 = ROUND(yp);
+				if (x0 < 0)
+					DIRECT_A2D_ELEM(f2d, i, x) = conj(A2D_ELEM(data, -y0, -x0));
+				else
+					DIRECT_A2D_ELEM(f2d, i, x) = A2D_ELEM(data, y0, x0);
+			} // endif NEAREST_NEIGHBOUR
+			else
+				REPORT_ERROR("Unrecognized interpolator in Projector::project");
+		} // endif x-loop
+	} // endif y-loop
+}
diff --git a/src/projector.h b/src/projector.h
new file mode 100644
index 0000000..6ee2e51
--- /dev/null
+++ b/src/projector.h
@@ -0,0 +1,230 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#ifndef __PROJECTOR_H
+#define __PROJECTOR_H
+
+#include "src/fftw.h"
+#include "src/multidim_array.h"
+#include "src/image.h"
+
+#define NEAREST_NEIGHBOUR 0
+#define TRILINEAR 1
+#define CONVOLUTE_BLOB 2
+
+#define FORWARD_PROJECTION 0
+#define BACKWARD_PROJECTION 1
+
+#define ACT_ON_DATA 0
+#define ACT_ON_WEIGHT 1
+
+class Projector
+{
+public:
+	// The Fourier-space image data array
+    MultidimArray<Complex > data;
+
+    // Only points within this many pixels from the origin (in the original size) will be interpolated
+    int r_max;
+
+    // Radius of sphere within TRILINEAR interpolation will be used in NEAREST_NEIGHBOUR interpolator
+    int r_min_nn;
+
+    // Original size of the real-space map
+    int ori_size;
+
+    // Padded size of the map in Fourier-space
+    int pad_size;
+
+    // Interpolation scheme (TRILINEAR or NEAREST_NEIGHBOUR, for BackProjector also CONVOLUTE_BLOB)
+    int interpolator;
+
+    // Oversample FT by padding in real space
+    int padding_factor;
+
+    // Dimension of the reference (currently allowed 2 or 3)
+    int ref_dim;
+
+public:
+
+    /** Empty constructor
+     *
+     * A default Projector is created.
+     *
+     * @code
+     * Projector PPref;
+     * @endcode
+     */
+    Projector()
+    {
+    	clear();
+    }
+
+   /** Constructor with parameters
+     *
+     * A default Projector is created.
+     *
+     * @code
+     * Projector PPref(ori_size, NEAREST_NEIGHBOUR);
+     * @endcode
+     */
+    Projector(int _ori_size, int _interpolator = TRILINEAR, int _padding_factor_3d = 2, int _r_min_nn = 10)
+    {
+
+    	// Store original dimension
+    	ori_size = _ori_size;
+
+    	// Padding factor for the map
+    	padding_factor = _padding_factor_3d;
+
+    	// Interpolation scheme
+    	interpolator = _interpolator;
+
+    	// Minimum radius for NN interpolation
+    	r_min_nn = _r_min_nn;
+
+    }
+
+    /** Copy constructor
+     *
+     * The created Projector is a perfect copy of the input array but with a
+     * different memory assignment.
+     *
+     * @code
+     * Projector V2(V1);
+     * @endcode
+     */
+	Projector(const Projector& op)
+    {
+		clear();
+        *this = op;
+    }
+
+	/** Assignment.
+     *
+     * You can build as complex assignment expressions as you like. Multiple
+     * assignment is allowed.
+     */
+	Projector& operator=(const Projector& op)
+    {
+        if (&op != this)
+        {
+        	data = op.data;
+        	ori_size = op.ori_size;
+        	pad_size = op.pad_size;
+        	r_max = op.r_max;
+        	r_min_nn = op.r_min_nn;
+        	interpolator = op.interpolator;
+        	padding_factor = op.padding_factor;
+        	ref_dim = op.ref_dim;
+        }
+        return *this;
+    }
+
+	/** Destructor
+      *
+      * Clears everything
+      *
+      * @code
+      * FourierInterpolator fourint;
+      * @endcode
+      */
+     ~Projector()
+     {
+         clear();
+     }
+
+   /** Clear.
+     * Initialize everything to back to default and empty arrays
+     */
+    void clear()
+    {
+    	data.clear();
+    	r_max = r_min_nn = interpolator = padding_factor = ref_dim = pad_size = 0;
+    }
+
+    /*
+     * Resize data array to the given size
+     */
+    void initialiseData(int current_size = -1);
+
+    /*
+     * Initialise data array to all zeros
+     */
+    void initZeros(int current_size = -1);
+
+    /*
+     *  Only get the size of the data array
+     */
+    long int getSize();
+
+    /* ** Prepares a 3D map for taking slices in its 3D Fourier Transform
+    *
+    * This routine does the following:
+    * 1. It pads the input map with zeros to obtain oversampling in the Fourier transform
+    * 2. It does the Fourier transform
+    * 3. It sets values beyond Nyquist for images of current_size to zero in the transform and windows the transform at max_r+1
+    * Depending on whether 2D or 3D Fourier Transforms will be extracted, the map is normalized internally in a different manner
+    *
+    */
+   void computeFourierTransformMap(MultidimArray<double> &vol_in, MultidimArray<double> &power_spectrum, int current_size = -1, int nr_threads = 1, bool do_gridding = true);
+
+   /* Because we interpolate in Fourier space to make projections and/or reconstructions, we have to correct
+    * the real-space maps by dividing them by the Fourier Transform of the interpolator
+    * Note these corrections are made on the not-oversampled, i.e. originally sized real-space map
+    */
+   void griddingCorrect(MultidimArray<double> &vol_in);
+
+   /*
+	* Get a 2D Fourier Transform from the 2D or 3D data array
+	* Depending on the dimension of the map, this will be a projection or a rotation operation
+	*/
+	void get2DFourierTransform(MultidimArray<Complex > &img_out, Matrix2D<double> &A, bool inv)
+	{
+		// Rotation of a 3D Fourier Transform
+		switch (ref_dim)
+		{
+		case 2:
+		   rotate2D(img_out, A, inv);
+		   break;
+		case 3:
+		   project(img_out, A, inv);
+		   break;
+		default:
+		   REPORT_ERROR("Projector::get2DSlice%%ERROR: Dimension of the data array should be 2 or 3");
+		}
+	}
+
+	/*
+	* Get a 2D slice from the 3D map (forward projection)
+	*/
+	void project(MultidimArray<Complex > &img_out, Matrix2D<double> &A, bool inv);
+
+	/*
+	* Get an in-plane rotated version of the 2D map (mere interpolation)
+	*/
+	void rotate2D(MultidimArray<Complex > &img_out, Matrix2D<double> &A, bool inv);
+
+
+};
+
+
+
+
+#endif
diff --git a/src/rwIMAGIC.h b/src/rwIMAGIC.h
new file mode 100644
index 0000000..bc35933
--- /dev/null
+++ b/src/rwIMAGIC.h
@@ -0,0 +1,343 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/*
+ Based on rwIMAGIC.h
+ Header file for reading and writing Image Science's Imagic files
+ Format: 2D image file format for the program Imagic (Image Science)
+ Author: Bernard Heymann
+ Created: 19990424  Modified: 20011030
+*/
+
+#ifndef RWIMAGIC_H_
+#define RWIMAGIC_H_
+
+#include "src/metadata_label.h"
+
+#define IMAGICSIZE 1024 // Size of the IMAGIC header for each image
+
+///@defgroup Imagic Imagic File format
+///@ingroup ImageFormats
+
+/** Imagic Header
+  * @ingroup Imagic
+*/
+struct IMAGIChead
+{             // file header for IMAGIC data
+    int imn;          //  0      image location number (1,2,...)
+    int ifn;          //  1      # images following
+    int ierror;       //  2      error code: error if >0
+    int nhfr;         //  3      # header records per image
+    int ndate;        //  4      creation day
+    int nmonth;       //  5      creation month
+    int nyear;        //  6      creation year
+    int nhour;        //  7      creation hour
+    int nminut;       //  8      creation minute
+    int nsec;         //  9      creation second
+    int npix2;        // 10      # 4-byte reals in image
+    int npixel;       // 11      # image elements
+    int ixlp;       // 12      lines per image (Y)
+    int iylp;        // 13      pixels per line (X)
+    char type[4];      // 14      image type
+    int ixold;       // 15      top-left X coordinate
+    int iyold;       // 16      top-left Y coordinate
+    float avdens;       // 17      average
+    float sigma;       // 18      standard deviation
+    float varian;       // 19      variance
+    float oldavd;      // 20      old average
+    float densmax;       // 21      maximum
+    float densmin;       // 22      minimum
+    //     double sum;       // 23+24  sum of densities
+    //     double squares;    // 25+26  sum of squares
+    float dummy[4];   // 23-26  dummy place holder
+    char lastpr[8];      // 27+28     last program writing file
+    char name[80];       // 29-48     image name
+    float extra_1[8];   // 49-56     additional parameters
+    float eman_alt;   // 57      EMAN: equiv to psi & PFT omega
+    float eman_az;    // 58      EMAN: equiv to theta
+    float eman_phi;   // 59      EMAN: equiv to phi
+    float extra_2[69];   // 60-128     additional parameters
+    float euler_alpha;  // 129   Euler angles: psi
+    float euler_beta;  // 130       theta
+    float euler_gamma;  // 131       phi
+    float proj_weight;  // 132   weight of each projection
+    float extra_3[66];   // 133-198     additional parameters
+    char history[228];      // 199-255   history
+} ;
+
+/************************************************************************
+ at Function: readIMAGIC
+ at Description:
+ Reading an IMAGIC image format.
+ at Algorithm:
+ A 2D file format for the IMAGIC package.
+ The header is stored in a separate file with extension ".hed" and
+  a fixed size of 1024 bytes per image.
+ The image data is stored in a single block in a file with the
+  extension ".img".
+ Byte order determination: Year and hour values
+        must be less than 256*256.
+ Data types:     PACK = byte, INTG = short, REAL = float,
+        RECO,COMP = complex float.
+ Note that the x and y dimensions are interchanged (actually a display issue).
+ at Arguments:
+ Bimage* p   the image structure.
+ int select   image selection in multi-image file (-1 = all images).
+ at Returns:
+ int     error code (<0 means failure).
+**************************************************************************/
+/** Imagic reader
+  * @ingroup Imagic
+*/
+int  readIMAGIC(long int img_select)
+{
+#ifdef DEBUG
+    printf("DEBUG readIMAGIC: Reading Imagic file\n");
+#endif
+
+    IMAGIChead* header = new IMAGIChead;
+
+    if ( fread( header, IMAGICSIZE, 1, fhed ) < 1 )
+        REPORT_ERROR((std::string)"readIMAGIC: header file of " + filename + " cannot be read");
+
+    // Determine byte order and swap bytes if from little-endian machine
+    char*   b = (char *) header;
+    int    swap = 0;
+    long int extent = IMAGICSIZE - 916;  // exclude char bytes from swapping
+    if ( ( abs(header->nyear) > SWAPTRIG ) || ( header->ixlp > SWAPTRIG ) )
+    {
+        swap = 1;
+        for ( i=0; i<extent; i+=4 )
+            if ( i != 56 )          // exclude type string
+                swapbytes(b+i, 4);
+    }
+    long int _xDim,_yDim,_zDim;
+    long int _nDim;
+    _xDim = (long int) header->iylp;
+    _yDim = (long int) header->ixlp;
+    _zDim = (long int) 1;
+    _nDim = (long int) header->ifn + 1 ;
+
+    std::stringstream Num;
+    std::stringstream Num2;
+    if ( img_select > (long int)_nDim )
+    {
+        Num  << img_select;
+        Num2 << _nDim;
+        REPORT_ERROR((std::string)"readImagic: Image number " + Num.str() +
+                     " exceeds stack size " + Num2.str());
+    }
+
+    if( img_select > -1)
+        _nDim=1;
+    data.setDimensions( //setDimensions do not allocate data
+        _xDim,
+        _yDim,
+        _zDim,
+        _nDim );
+    replaceNsize=_nDim;
+    DataType datatype;
+
+    if ( strstr(header->type,"PACK") )
+        datatype = UChar;
+    else if ( strstr(header->type,"INTG") )
+        datatype = Short;
+    else if ( strstr(header->type,"REAL") )
+        datatype = Float;
+    else if ( strstr(header->type,"RECO") || strstr(header->type,"COMP") )
+    {
+        REPORT_ERROR("readIMAGIC: only real-space images can be read into RELION");
+    }
+
+    // Set min-max values and other statistical values
+    if ( header->sigma == 0 && header->varian != 0 )
+        header->sigma = sqrt(header->varian);
+    if ( header->densmax == 0 && header->densmin == 0 && header->sigma != 0 )
+    {
+        header->densmin = header->avdens - header->sigma;
+        header->densmax = header->avdens + header->sigma;
+    }
+
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN,(double)header->densmin);
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX,(double)header->densmax);
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG,(double)header->avdens);
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV,(double)header->sigma);
+    MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_X,(double)1.);
+    MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Y,(double)1.);
+    MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Z,(double)1.);
+    MDMainHeader.setValue(EMDL_IMAGE_DATATYPE,(int)datatype);
+
+    offset = 0;   // separate header file
+
+    unsigned long   Ndim = _nDim, j = 0;
+    if (dataflag<0)   // Don't read the individual header and the data if not necessary
+    {
+    	delete header;
+    	return 0;
+    }
+
+    // View   view;
+    char*   hend;
+
+   // Get the header information
+    int error_fseek;
+    if ( img_select > -1 )
+    	error_fseek = fseek( fhed, img_select * IMAGICSIZE, SEEK_SET );
+    else
+    	error_fseek = fseek( fhed, 0, SEEK_SET );
+
+    if (error_fseek != 0)
+    	return -1;
+
+    delete header;
+
+    int pad=0;
+    return readData(fimg, img_select, datatype, pad );
+
+}
+
+/************************************************************************
+ at Function: writeIMAGIC
+ at Description:
+ Writing an IMAGIC image format.
+ at Algorithm:
+ A file format for the IMAGIC package.
+ at Arguments:
+ Bimage*    the image structure.
+ at Returns:
+ int     error code (<0 means failure).
+**************************************************************************/
+/** Imagic Writer
+  * @ingroup Imagic
+*/
+int  writeIMAGIC(long int img_select=-1, int mode=WRITE_OVERWRITE)
+{
+    //    if ( p->transform != NoTransform )
+    //        img_convert_fourier(p, Centered);
+
+    IMAGIChead* header = new IMAGIChead;
+    long int Xdim = XSIZE(data);
+    long int Ydim = YSIZE(data);
+    long int Zdim = ZSIZE(data);
+    long int Ndim = NSIZE(data);
+
+    // fill in the file header
+    header->nhfr = 1;
+    header->npix2 = Xdim*Ydim;
+    header->npixel = header->npix2;
+    header->iylp = Xdim;
+    header->ixlp = Ydim;
+    header->ifn = Ndim - 1 ;
+
+    time_t timer;
+    time ( &timer );
+    tm* t = localtime(&timer);
+
+    header->ndate = t->tm_mday;
+    header->nmonth = t->tm_mon + 1;
+    header->nyear = t->tm_year;
+    header->nhour = t->tm_hour;
+    header->nminut = t->tm_min;
+    header->nsec = t->tm_sec;
+
+    long int  imgStart=0;
+    if (img_select != -1)
+        imgStart=img_select;
+    if (mode == WRITE_APPEND)
+        imgStart=0;
+
+    // Convert T to datatype
+    if ( typeid(T) == typeid(double) ||
+         typeid(T) == typeid(float) ||
+         typeid(T) == typeid(int) )
+        strcpy(header->type,"REAL");
+    else if ( typeid(T) == typeid(unsigned char) ||
+              typeid(T) == typeid(signed char) )
+        strcpy(header->type,"PACK");
+    else
+        REPORT_ERROR("ERROR write IMAGIC image: invalid typeid(T)");
+
+    size_t datasize, datasize_n;
+    datasize_n = Xdim*Ydim*Zdim;
+    datasize = datasize_n * gettypesize(Float);
+    double aux;
+
+    if (!MDMainHeader.isEmpty())
+    {
+
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_MIN,   aux))
+            header->densmin = (float)aux;
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_MAX,   aux))
+            header->densmax = (float)aux;
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_AVG,   aux))
+            header->avdens   = (float)aux;
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_STDDEV,aux))
+        {
+            header->sigma  = (float)aux;
+            header->varian = (float)(aux*aux);
+        }
+    }
+
+    memcpy(header->lastpr, "Xmipp", 5);
+    memcpy(header->name, filename.c_str(), 80);
+
+    /*
+     * BLOCK HEADER IF NEEDED
+     */
+    struct flock fl;
+
+    fl.l_type   = F_WRLCK;  /* F_RDLCK, F_WRLCK, F_UNLCK    */
+    fl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
+    fl.l_start  = 0;        /* Offset from l_whence         */
+    fl.l_len    = 0;        /* length, 0 = to EOF           */
+    fl.l_pid    = getpid(); /* our PID                      */
+    fcntl(fileno(fimg),       F_SETLKW, &fl); /* locked */
+    fcntl(fileno(fhed), F_SETLKW, &fl); /* locked */
+
+
+    if(mode==WRITE_APPEND)
+    {
+        fseek( fimg, 0, SEEK_END);
+        fseek( fhed, 0, SEEK_END);
+    }
+    else if(mode==WRITE_REPLACE)
+    {
+        fseek( fimg, datasize   * img_select, SEEK_SET);
+        fseek( fhed, IMAGICSIZE * img_select, SEEK_SET);
+    }
+    else //mode==WRITE_OVERWRITE
+    {
+        fseek( fimg, 0, SEEK_SET);
+        fseek( fhed, 0, SEEK_SET);
+    }
+    char* fdata = (char *) askMemory(datasize);
+
+    //Unlock
+    fl.l_type   = F_UNLCK;
+    fcntl(fileno(fimg), F_SETLK, &fl); /* unlocked */
+    fcntl(fileno(fhed), F_SETLK, &fl); /* unlocked */
+
+    freeMemory(fdata, datasize);
+
+    delete header;
+
+    return(0);
+}
+
+#endif /* RWIMAGIC_H_ */
diff --git a/src/rwMRC.h b/src/rwMRC.h
new file mode 100644
index 0000000..8897597
--- /dev/null
+++ b/src/rwMRC.h
@@ -0,0 +1,472 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/*
+        Based on rwMRC.h
+        Header file for reading and writing MRC files
+        Format: 3D crystallographic image file format for the MRC package
+        Author: Bernard Heymann
+        Created: 19990321       Modified: 20030723
+*/
+
+#ifndef RWMRC_H
+#define RWMRC_H
+
+#define MRCSIZE    1024 // Minimum size of the MRC header (when nsymbt = 0)
+
+///@defgroup MRC MRC File format
+///@ingroup ImageFormats
+
+/** MRC Old Header
+  * @ingroup MRC
+*/
+struct MRCheadold
+{          // file header for MRC data
+    int nx;              //  0   0       image size
+    int ny;              //  1   4
+    int nz;              //  2   8
+    int mode;            //  3           0=uchar,1=short,2=float
+    int nxStart;         //  4           unit cell offset
+    int nyStart;         //  5
+    int nzStart;         //  6
+    int mx;              //  7           unit cell size in voxels
+    int my;              //  8
+    int mz;              //  9
+    float a;             // 10   40      cell dimensions in A
+    float b;             // 11
+    float c;             // 12
+    float alpha;         // 13           cell angles in degrees
+    float beta;          // 14
+    float gamma;         // 15
+    int mapc;            // 16           column axis
+    int mapr;            // 17           row axis
+    int maps;            // 18           section axis
+    float amin;          // 19           minimum density value
+    float amax;          // 20   80      maximum density value
+    float amean;         // 21           average density value
+    int ispg;            // 22           space group number
+    int nsymbt;          // 23           bytes used for sym. ops. table
+    float extra[29];     // 24           user-defined info
+    float xOrigin;       // 53           phase origin in pixels
+    float yOrigin;       // 54
+    int nlabl;           // 55           number of labels used
+    char labels[10][80]; // 56-255       10 80-character labels
+} ;
+
+/** MRC Header
+  * @ingroup MRC
+*/
+struct MRChead
+{             // file header for MRC data
+    int nx;              //  0   0       image size
+    int ny;              //  1   4
+    int nz;              //  2   8
+    int mode;            //  3           0=char,1=short,2=float
+    int nxStart;         //  4           unit cell offset
+    int nyStart;         //  5
+    int nzStart;         //  6
+    int mx;              //  7           unit cell size in voxels
+    int my;              //  8
+    int mz;              //  9
+    float a;             // 10   40      cell dimensions in A
+    float b;             // 11
+    float c;             // 12
+    float alpha;         // 13           cell angles in degrees
+    float beta;          // 14
+    float gamma;         // 15
+    int mapc;            // 16           column axis
+    int mapr;            // 17           row axis
+    int maps;            // 18           section axis
+    float amin;          // 19           minimum density value
+    float amax;          // 20   80      maximum density value
+    float amean;         // 21           average density value
+    int ispg;            // 22           space group number
+    int nsymbt;          // 23           bytes used for sym. ops. table
+    float extra[25];     // 24           user-defined info
+    float xOrigin;       // 49           phase origin in pixels
+    float yOrigin;       // 50
+    float zOrigin;       // 51
+    char map[4];         // 52       identifier for map file ("MAP ")
+    char machst[4];      // 53           machine stamp
+    float arms;          // 54       RMS deviation
+    int nlabl;           // 55           number of labels used
+    char labels[800];    // 56-255       10 80-character labels
+} ;
+
+// For determination of machine stamp
+#define UNKNOWN_SYSTEM 0
+#define BIGIEEE 1
+#define LITTLEIEEE 2
+#define LITTLEVAX 3
+int systype()
+{
+    char*           test = (char *) askMemory(12);
+    int*            itest = (int *) test;
+    float*          ftest = (float *) test;
+    memcpy(test, "jbh     ", 8);
+
+    int type = UNKNOWN_SYSTEM;
+    if ( itest[0] == 1784834080 && fabs(ftest[0] - 6.84272e+25) < 1e+21 )
+    	type = BIGIEEE;
+    if ( itest[0] == 543711850 && fabs(ftest[0] - 1.96837e-19) < 1e-23 )
+    	type = LITTLEIEEE;
+
+    freeMemory(test, 12);
+
+    return type;
+}
+
+// I/O prototypes
+/** MRC Reader
+  * @ingroup MRC
+*/
+int readMRC(long int img_select, bool isStack=false)
+{
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+    printf("DEBUG readMRC: Reading MRC file\n");
+#endif
+
+    MRChead*        header = (MRChead *) askMemory(sizeof(MRChead));
+    if ( fread( header, MRCSIZE, 1, fimg ) < 1 )
+    	REPORT_ERROR("rwMRC: error in reading header ...");
+
+    // Determine byte order and swap bytes if from little-endian machine
+    swap = 0;
+    char*       b = (char *) header;
+    int         i;
+    if ( ( abs( header->mode ) > SWAPTRIG ) || ( abs(header->nx) > SWAPTRIG ) )
+    {
+#ifdef DEBUG
+        fprintf(stderr, "Warning: Swapping header byte order for 4-byte types\n");
+#endif
+
+        swap = 1;
+        int     extent = MRCSIZE - 800; // exclude labels from swapping
+        for ( i=0; i<extent; i+=4 )
+            swapbytes(b+i, 4);
+    }
+
+    // Convert VAX floating point types if necessary
+    if ( header->amin > header->amax )
+        REPORT_ERROR("readMRC: amin > max: VAX floating point conversion unsupported");
+    long int _xDim,_yDim,_zDim;
+    long int _nDim;
+    _xDim = (int) header->nx;
+    _yDim = (int) header->ny;
+    _zDim = (int) header->nz;
+    _nDim = 1;
+
+    if(isStack)
+    {
+        _nDim = (long int) _zDim;
+        _zDim = 1;
+        replaceNsize=_nDim;
+        std::stringstream Num;
+        std::stringstream Num2;
+        if ( img_select > (int)_nDim )
+        {
+            Num  << img_select;
+            Num2 << _nDim;
+            REPORT_ERROR((std::string)"readMRC: Image number " + Num.str() +
+                         " exceeds stack size " + Num2.str());
+        }
+    }
+    else
+        replaceNsize=0;
+
+    // Map the parameters
+    if (isStack && img_select==-1)
+        _zDim = 1;
+    else if(isStack && img_select!=-1)
+        _zDim = _nDim = 1;
+    else
+        _nDim = 1;
+
+    data.setDimensions(_xDim, _yDim, _zDim, _nDim);
+    long int imgStart=0;
+    long int imgEnd =_nDim;
+    if (img_select != -1)
+    {
+        imgStart=img_select;
+        imgEnd=img_select+1;
+    }
+
+    DataType datatype;
+    switch ( header->mode%5 )
+    {
+    case 0:
+        datatype = UChar; // The image2010 web page says map-mode 0 is signed, but Jude's code interpretes the data as unsigned
+        break;
+    case 1:
+        datatype = Short;
+        break;
+    case 2:
+        datatype = Float;
+        break;
+    case 3:
+    	REPORT_ERROR("readMRC: only real-space images may be read into RELION.");
+    	break;
+    case 4:
+    	REPORT_ERROR("readMRC: only real-space images may be read into RELION.");
+        break;
+    default:
+        datatype = UChar;
+        break;
+    }
+    offset = MRCSIZE + header->nsymbt;
+
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN,(double)header->amin);
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX,(double)header->amax);
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG,(double)header->amean);
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV,(double)header->arms);
+    MDMainHeader.setValue(EMDL_IMAGE_DATATYPE,(int)datatype);
+
+    if ( header->mx && header->a!=0)//ux
+        MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_X,(double)header->a/header->mx);
+    if ( header->my && header->b!=0)//yx
+        MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Y,(double)header->b/header->my);
+    if ( header->mz && header->c!=0)//zx
+        MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Z,(double)header->c/header->mz);
+
+   if (isStack && dataflag<0)   // Don't read the individual header and the data if not necessary
+   {
+	   freeMemory(header, sizeof(MRChead));
+	   return 0;
+   }
+
+    //#define DEBUG
+#ifdef DEBUG
+    MDMainHeader.write(std::cerr);
+    MD[0].write(std::cerr);
+#endif
+
+    freeMemory(header, sizeof(MRChead));
+
+    return readData(fimg, img_select, datatype, 0);
+
+}
+
+/** MRC Writer
+  * @ingroup MRC
+*/
+int writeMRC(long int img_select, bool isStack=false, int mode=WRITE_OVERWRITE)
+{
+    MRChead*        header = (MRChead *) askMemory(sizeof(MRChead));
+
+    // Map the parameters
+    strncpy(header->map, "MAP ", 4);
+    // Set CCP4 machine stamp
+    switch ( systype() )
+	{
+		case BIGIEEE:
+			header->machst[0] = header->machst[1] = 17;
+			break;
+		case LITTLEIEEE:
+			header->machst[0] = 68;
+			header->machst[1] = 65;
+			break;
+		case LITTLEVAX:
+			header->machst[0] = 34;
+			header->machst[1] = 65;
+			break;
+		case UNKNOWN_SYSTEM:
+			REPORT_ERROR("Unkown system type in writeMRC machine stamp determination.");
+			break;
+		default:
+			break;
+	}
+
+    // FIXME TO BE DONE WITH rwCCP4!!
+    //set_CCP4_machine_stamp(header->machst);
+    long int Xdim = XSIZE(data);
+    long int Ydim = YSIZE(data);
+    long int Zdim = ZSIZE(data);
+    long int Ndim = NSIZE(data);
+    long int imgStart=0;
+    long int imgEnd =Ndim;
+    if (img_select != -1)
+    {
+        imgStart=img_select;
+        imgEnd=img_select+1;
+    }
+    if (mode == WRITE_APPEND || mode==WRITE_REPLACE)
+    {
+        imgStart=0;
+        imgEnd=1;
+    }
+    header->nx = Xdim;
+    header->ny = Ydim;
+    if (isStack)
+    	header->nz = Ndim;
+    else
+    	header->nz = Zdim;
+
+    // Convert T to datatype
+    if ( typeid(T) == typeid(double) ||
+         typeid(T) == typeid(float) ||
+         typeid(T) == typeid(int) )
+        header->mode = 2;
+    else if ( typeid(T) == typeid(unsigned char) ||
+              typeid(T) == typeid(signed char) )
+        header->mode = 0;
+    else
+        REPORT_ERROR("ERROR write MRC image: invalid typeid(T)");
+
+    //Set this to zero till we decide if we want to update it
+    header->mx = header->nx;//(int) (ua/ux + 0.5);
+    header->my = header->ny;//(int) (ub/uy + 0.5);
+    header->mz = header->nz;//(int) (uc/uz + 0.5);
+    header->mapc = 1;
+    header->mapr = 2;
+    header->maps = 3;
+    double aux,aux2;
+
+    // TODO: fix this!
+    header->a = (float)0.;// ua;
+    header->b = (float)0.;// ub;
+    header->c = (float)0.;// uc;
+    header->alpha = (float)90.;
+    header->beta = (float)90.;
+    header->gamma = (float)90.;
+
+    if (!MDMainHeader.isEmpty())
+    {
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_MIN, aux))
+            header->amin  = (float)aux;
+        else
+        	header->amin  = (float)data.computeMin();
+
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_MAX, aux))
+            header->amax  = (float)aux;
+        else
+        	header->amax  = (float)data.computeMax();
+
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_AVG, aux))
+            header->amean = (float)aux;
+        else
+        	header->amean = (float)data.computeAvg();
+
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_STDDEV, aux))
+            header->arms  = (float)aux;
+        else
+        	header->arms  = (float)data.computeStddev();
+
+        if(MDMainHeader.getValue(EMDL_ORIENT_ORIGIN_X, aux))
+            header->nxStart = (int)(aux-0.5);
+
+        if (MDMainHeader.getValue(EMDL_IMAGE_SAMPLINGRATE_X,aux2))//header is init to zero
+        {
+        	header->xOrigin = (float)(aux*aux2);
+        	header->a = (float)aux2*header->nx;
+        }
+
+        if (MDMainHeader.getValue(EMDL_ORIENT_ORIGIN_Y, aux))
+            header->nyStart = (int)(aux-0.5);
+
+        if (MDMainHeader.getValue(EMDL_IMAGE_SAMPLINGRATE_Y,aux2))//header is init to zero
+        {
+         	header->yOrigin = (float)(aux*aux2);
+         	header->b = (float)aux2*header->ny;
+        }
+
+        if (MDMainHeader.getValue(EMDL_ORIENT_ORIGIN_Z, aux))
+            header->nzStart = (int)(aux-0.5);
+
+        if (MDMainHeader.getValue(EMDL_IMAGE_SAMPLINGRATE_Z,aux2))//header is init to zero
+        {
+        	header->zOrigin = (float)(aux*aux2);
+        	header->c = (float)aux2*header->nz;
+        }
+
+    }
+
+    header->nsymbt = 0;
+    header->nlabl = 10; // or zero?
+    //strncpy(header->labels, p->label.c_str(), 799);
+
+    offset = MRCSIZE + header->nsymbt;
+    size_t datasize, datasize_n;
+    datasize_n = Xdim*Ydim*Zdim;
+    datasize = datasize_n * gettypesize(Float);
+
+    //#define DEBUG
+#ifdef DEBUG
+
+    printf("DEBUG rwMRC: Offset = %ld,  Datasize_n = %ld\n", offset, datasize_n);
+#endif
+
+    // For multi-image files
+    if (mode == WRITE_APPEND && isStack)
+    {
+        header->nz = replaceNsize +1;
+    }
+    //else header-> is correct
+
+    //locking
+    struct flock fl;
+
+    fl.l_type   = F_WRLCK;  /* F_RDLCK, F_WRLCK, F_UNLCK    */
+    fl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
+    fl.l_start  = 0;        /* Offset from l_whence         */
+    fl.l_len    = 0;        /* length, 0 = to EOF           */
+    fl.l_pid    = getpid(); /* our PID                      */
+
+    //BLOCK
+    fl.l_type   = F_WRLCK;
+    fcntl(fileno(fimg), F_SETLKW, &fl); /* locked */
+
+    // Write header
+    if(mode==WRITE_OVERWRITE || mode==WRITE_APPEND)
+        fwrite( header, MRCSIZE, 1, fimg );
+    freeMemory(header, sizeof(MRChead) );
+
+    //write only once, ignore select_img
+    char* fdata = (char *) askMemory(datasize);
+    //think about writing in several chunks
+
+    if ( NSIZE(data) == 1 && mode==WRITE_OVERWRITE)
+    {
+    	castPage2Datatype(MULTIDIM_ARRAY(data), fdata, Float, datasize_n);
+        fwrite( fdata, datasize, 1, fimg );
+    }
+    else
+    {
+        if(mode==WRITE_APPEND)
+            fseek( fimg, 0, SEEK_END);
+        else if(mode==WRITE_REPLACE)
+        {
+        	fseek( fimg, offset + (datasize)*img_select, SEEK_SET);
+        }
+        for ( size_t i =imgStart; i<imgEnd; i++ )
+        {
+        	castPage2Datatype(MULTIDIM_ARRAY(data) + i*datasize_n, fdata, Float, datasize_n);
+            fwrite( fdata, datasize, 1, fimg );
+        }
+    }
+    // Unlock the file
+    fl.l_type   = F_UNLCK;
+    fcntl(fileno(fimg), F_SETLK, &fl); /* unlocked */
+
+    freeMemory(fdata, datasize);
+
+    return(0);
+}
+#endif
diff --git a/src/rwSPIDER.h b/src/rwSPIDER.h
new file mode 100644
index 0000000..07db268
--- /dev/null
+++ b/src/rwSPIDER.h
@@ -0,0 +1,427 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/*
+ Based on rwSPIDER.h
+ Header file for reading and writing SPIDER files
+ Format: 3D image file format for the SPIDER package
+ Author: Bernard Heymann
+ Created: 19990410  Modified: 20010928
+*/
+
+#ifndef RWSPIDER_H
+#define RWSPIDER_H
+
+#define SPIDERSIZE 1024 // Minimum size of the SPIDER header (variable)
+///@defgroup Spider Spider File format
+///@ingroup ImageFormats
+
+/** Spider Header
+  * @ingroup Spider
+*/
+struct SPIDERhead
+{                    // file header for SPIDER data
+    float nslice;    //  0      slices in volume (image = 1)
+    float nrow;      //  1      rows per slice
+    float irec;      //  2      # records in file (unused)
+    float nhistrec;  //  3      (obsolete)
+    float iform;     //  4      file type specifier
+    float imami;     //  5      max/min flag (=1 if calculated)
+    float fmax;      //  6      maximum
+    float fmin;      //  7      minimum
+    float av;        //  8      average
+    float sig;       //  9      standard deviation (=-1 if not calculated)
+    float ihist;     // 10      (obsolete)
+    float nsam;      // 11      pixels per row
+    float labrec;    // 12      # records in header
+    float iangle;    // 13      flag: tilt angles filled
+    float phi;       // 14      tilt angles
+    float theta;     // 15
+    float gamma;     // 16      (=psi)
+    float xoff;      // 17      translation
+    float yoff;      // 18
+    float zoff;      // 19
+    float scale;     // 20      scaling
+    float labbyt;    // 21      # bytes in header
+    float lenbyt;    // 22      record length in bytes (row length)
+    float istack;    // 23      indicates stack of images
+    float inuse;     // 24      indicates this image in stack is used (not used)
+    float maxim;     // 25      max image in stack used
+    float imgnum;    // 26      number of current image
+    float unused[2]; // 27-28     (unused)
+    float kangle;    // 29      flag: additional angles set
+    float phi1;      // 30      additional angles
+    float theta1;    // 31
+    float psi1;      // 32
+    float phi2;      // 33
+    float theta2;    // 34
+    float psi2;      // 35
+
+    double fGeo_matrix[3][3]; // x9 = 72 bytes: Geometric info
+    float fAngle1; // angle info
+
+    float fr1;
+    float fr2; // lift up cosine mask parameters
+
+    /** Fraga 23/05/97  For Radon transforms **/
+    float RTflag; // 1=RT, 2=FFT(RT)
+    float Astart;
+    float Aend;
+    float Ainc;
+    float Rsigma; // 4*7 = 28 bytes
+    float Tstart;
+    float Tend;
+    float Tinc; // 4*3 = 12, 12+28 = 40B
+
+    /** Sjors Scheres 17/12/04 **/
+    float weight; // For Maximum-Likelihood refinement
+    float flip;   // 0=no flipping operation (false), 1=flipping (true)
+
+    char fNada2[576]; // empty 700-76-40=624-40-8= 576 bytes
+
+    char cdat[12];   // 211-213   creation date
+    char ctim[8];  // 214-215   creation time
+    char ctit[160];  // 216-255   title
+} ;
+
+/************************************************************************
+ at Function: readSPIDER
+ at Description:
+ Reading a SPIDER image file format.
+ at Algorithm:
+ A 3D multi-image format used in electron microscopy.
+ Header size:    1024 bytes (not same as data offset!).
+ Data offset:    sizeof(float)*x_size*ceil(1024/x_size)
+ File format extensions:   .spi
+ Byte order determination: File type and third dimension values
+        must be less than 256*256.
+ Data type:      only float.
+ A multi-image file has a global header followed by a header and data
+ for each sub-image.
+ at Arguments:
+ Bimage* p   the image structure.
+ int img_select  image selection in multi-image file (-1 = all images).
+ at Returns:
+ int     error code (<0 means failure).
+**************************************************************************/
+/** Spider Reader
+  * @ingroup Spider
+*/
+
+int  readSPIDER(long int img_select)
+{
+#undef DEBUG
+    //#define DEBUG
+#ifdef DEBUG
+    printf("DEBUG readSPIDER: Reading Spider file\n");
+#endif
+#undef DEBUG
+
+    SPIDERhead* header = new SPIDERhead;
+    if ( fread( header, SPIDERSIZE, 1, fimg ) < 1 )
+        REPORT_ERROR("rwSPIDER: cannot allocate memory for header");
+
+    swap = 0;
+
+    // Determine byte order and swap bytes if from different-endian machine
+    char*    b = (char *) header;
+    int      i;
+    int      extent = SPIDERSIZE - 180;  // exclude char bytes from swapping
+    if ( ( fabs(header->nrow) > SWAPTRIG ) || ( fabs(header->iform) > SWAPTRIG ) ||
+         ( fabs(header->nslice) < 1 ) )
+    {
+        swap = 1;
+        for ( i=0; i<extent; i+=4 )
+            swapbytes(b+i, 4);
+    }
+
+    if(header->labbyt != header->labrec*header->lenbyt)
+        REPORT_ERROR((std::string)"Invalid Spider file:  " + filename);
+
+    offset = (int) header->labbyt;
+    DataType datatype  = Float;
+
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_MIN,(double)header->fmin);
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_MAX,(double)header->fmax);
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_AVG,(double)header->av);
+    MDMainHeader.setValue(EMDL_IMAGE_STATS_STDDEV,(double)header->sig);
+    MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_X,(double)header->scale);
+    MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Y,(double)header->scale);
+    MDMainHeader.setValue(EMDL_IMAGE_SAMPLINGRATE_Z,(double)header->scale);
+    MDMainHeader.setValue(EMDL_IMAGE_DATATYPE,(int)datatype);
+
+    bool isStack = ( header->istack > 0 );
+    long int _xDim,_yDim,_zDim;
+    long int _nDim, _nDimSet;
+    _xDim = (long int) header->nsam;
+    _yDim = (long int) header->nrow;
+    _zDim = (long int) header->nslice;
+    _nDim = 1;
+
+    if(isStack)
+    {
+        _nDim = (long int) header->maxim;
+        replaceNsize=_nDim;
+    }
+    else
+        replaceNsize=0;
+
+    /************
+     * BELOW HERE DO NOT USE HEADER BUT LOCAL VARIABLES
+     */
+
+   // Map the parameters, REad the whole object (-1) or a slide
+    // Only handle stacks of images not of volumes
+    if(!isStack)
+        _nDimSet = 1;
+    else
+    {
+        if(img_select==-1)
+            _nDimSet = _nDim;
+        else
+            _nDimSet = 1;
+    }
+
+    data.setDimensions(_xDim, _yDim, _zDim, _nDimSet);
+
+    if (isStack && dataflag<0)   // Don't read the individual header and the data if not necessary
+    {
+    	delete header;
+    	return 0;
+    }
+
+    size_t header_size = offset;
+    size_t image_size  = header_size + ZYXSIZE(data)*sizeof(float);
+    size_t pad         = 0;
+    long int imgStart=0;
+    long int imgEnd =_nDim;
+    if (img_select != -1)
+    {
+        imgStart=img_select;
+        imgEnd=img_select+1;
+    }
+
+    char*   hend;
+
+    std::stringstream Num;
+    std::stringstream Num2;
+    //image is in stack? and set right initial and final image
+    if ( isStack)
+    {
+        pad         = offset;
+        if ( img_select > _nDim )
+        {
+            Num  << img_select;
+            Num2 << _nDim;
+            REPORT_ERROR((std::string)"readSpider: Image number " + Num.str() +
+                         " exceeds stack size " + Num2.str());
+        }
+        offset += offset;
+    }
+
+    delete header;
+
+#ifdef DEBUG
+
+    std::cerr<<"DEBUG readSPIDER: header_size = "<<header_size<<" image_size = "<<image_size<<std::endl;
+    std::cerr<<"DEBUG readSPIDER: img_select= "<<img_select<<" n= "<<Ndim<<" pad = "<<pad<<std::endl;
+#endif
+    //offset should point to the begin of the data
+    return readData(fimg, img_select, datatype, pad );
+
+}
+/************************************************************************
+ at Function: writeSPIDER
+ at Description:
+ Writing a SPIDER image file format.
+ at Algorithm:
+ A 3D image format used in electron microscopy.
+ at Arguments:
+ at Returns:
+ int     error code (<0 means failure).
+**************************************************************************/
+/** Spider Writer
+  * @ingroup Spider
+*/
+int  writeSPIDER(long int select_img=-1, bool isStack=false, int mode=WRITE_OVERWRITE)
+{
+    //return(1);
+#undef DEBUG
+//#define DEBUG
+#ifdef DEBUG
+    printf("DEBUG writeSPIDER: Writing Spider file\n");
+    printf("DEBUG writeSPIDER: File %s\n", filename.c_str());
+#endif
+//#undef DEBUG
+
+    //check if we are going to add or substitute an slice
+    //in an existing stack
+    //IsStack?
+    //else
+    long int Xdim = XSIZE(data);
+    long int Ydim = YSIZE(data);
+    long int Zdim = ZSIZE(data);
+    long int Ndim = NSIZE(data);
+
+    float  lenbyt = sizeof(float)*Xdim;  // Record length (in bytes)
+    float  labrec = floor(SPIDERSIZE/lenbyt); // # header records
+    if ( fmod(SPIDERSIZE,lenbyt) != 0 )
+        labrec++;
+    float  labbyt = labrec*lenbyt;   // Size of header in bytes
+    offset = (int) labbyt;
+    SPIDERhead* header = (SPIDERhead *) askMemory((int)labbyt*sizeof(char));
+
+    // Map the parameters
+    header->lenbyt = lenbyt;     // Record length (in bytes)
+    header->labrec = labrec;     // # header records
+    header->labbyt = labbyt;     // Size of header in bytes
+
+    header->irec   = labrec + floor((ZYXSIZE(data)*sizeof(float))/lenbyt + 0.999999); // Total # records
+    header->nsam   = Xdim;
+    header->nrow   = Ydim;
+    header->nslice = Zdim;
+
+    long int  imgStart=0;
+    if (select_img != -1)
+        imgStart=select_img;
+    if (mode == WRITE_APPEND)
+        imgStart=0;
+
+#ifdef DEBUG
+    printf("DEBUG writeSPIDER: Size: %g %g %g\n", header->nsam, header->nrow, header->nslice);
+#endif
+
+    if ( Zdim < 2 )
+    	header->iform = 1;     // 2D image
+    else
+    	header->iform = 3;     // 3D volume
+    double aux;
+    bool baux;
+    header->imami = 0;//never trust max/min
+
+    if (!MDMainHeader.isEmpty())
+    {
+#ifdef DEBUG
+    	std::cerr<<"Non-empty MDMainHeader"<<std::endl;
+#endif
+    	if(MDMainHeader.getValue(EMDL_IMAGE_STATS_MIN,   aux))
+            header->fmin = (float)aux;
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_MAX,   aux))
+            header->fmax = (float)aux;
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_AVG,   aux))
+            header->av   = (float)aux;
+        if(MDMainHeader.getValue(EMDL_IMAGE_STATS_STDDEV,aux))
+            header->sig  = (float)aux;
+    }
+    // For multi-image files
+    if (Ndim > 1 || mode == WRITE_APPEND || isStack)
+    {
+        header->istack = 2;
+        header->inuse =  1;
+        header->maxim = Ndim;
+        if(mode == WRITE_APPEND)
+            header->maxim = replaceNsize +1;
+    }
+    else
+    {
+        header->istack = 0;
+        header->inuse = 0;
+        header->maxim = 1;
+    }
+
+    //else end
+    // Set time and date
+    time_t timer;
+    time ( &timer );
+    tm* t = localtime(&timer);
+    while ( t->tm_year > 100 )
+        t->tm_year -= 100;
+    sprintf(header->ctim, "%02d:%02d:%02d", t->tm_hour, t->tm_min, t->tm_sec);
+    sprintf(header->cdat, "%02d-%02d-%02d", t->tm_mday, t->tm_mon, t->tm_year);
+
+    size_t datasize, datasize_n;
+    datasize_n = Xdim*Ydim*Zdim;
+    datasize = datasize_n * gettypesize(Float);
+
+#ifdef DEBUG
+
+    printf("DEBUG writeSPIDER: Date and time: %s %s\n", header->cdat, header->ctim);
+    printf("DEBUG writeSPIDER: Text label: %s\n", header->ctit);
+    printf("DEBUG writeSPIDER: Header size: %g\n", header->labbyt);
+    printf("DEBUG writeSPIDER: Header records and record length: %g %g\n", header->labrec, header->lenbyt);
+    printf("DEBUG writeSPIDER: Data size: %ld\n", datasize);
+    printf("DEBUG writeSPIDER: Data offset: %ld\n", offset);
+    printf("DEBUG writeSPIDER: File %s\n", filename.c_str());
+#endif
+    //locking
+    struct flock fl;
+
+    fl.l_type   = F_WRLCK;  /* F_RDLCK, F_WRLCK, F_UNLCK    */
+    fl.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
+    fl.l_start  = 0;        /* Offset from l_whence         */
+    fl.l_len    = 0;        /* length, 0 = to EOF           */
+    fl.l_pid    = getpid(); /* our PID                      */
+
+
+    /*
+     * BLOCK HEADER IF NEEDED
+     */
+    fl.l_type   = F_WRLCK;
+    fcntl(fileno(fimg), F_SETLKW, &fl); /* locked */
+    if(mode==WRITE_OVERWRITE || mode==WRITE_APPEND)//header must change
+        fwrite( header, offset, 1, fimg );
+
+    char* fdata = (char *) askMemory(datasize);
+    //think about writing in several chucks
+
+    //write only once, ignore select_img
+    if ( NSIZE(data) == 1 && mode==WRITE_OVERWRITE)
+    {
+    	castPage2Datatype(MULTIDIM_ARRAY(data), fdata, Float, datasize_n);
+        fwrite( fdata, datasize, 1, fimg );
+    }
+
+    else
+    {
+        if(mode==WRITE_APPEND)
+            fseek( fimg, 0, SEEK_END);
+        else if(mode==WRITE_REPLACE)
+            fseek( fimg,offset + (offset+datasize)*select_img, SEEK_SET);
+
+        // SJORS 30Oct12: I am completely unsure whether the code below will actually work....
+        // Let's just rais an error an go out...
+        REPORT_ERROR("writeSPIDER append/replace writing of SPIDER stacks not implemented yet....");
+        //for ( size_t i=0; i<Ndim; i++ )
+        size_t i =imgStart;
+        //do not need to unlock because we are in the overwrite case
+        fwrite( header, offset, 1, fimg );
+        castPage2Datatype(MULTIDIM_ARRAY(data) + i*datasize_n, fdata, Float, datasize_n);
+        fwrite( fdata, datasize, 1, fimg );
+    }
+    //I guess I do not need to unlock since we are going to close the file
+    fl.l_type   = F_UNLCK;
+    fcntl(fileno(fimg), F_SETLK, &fl); /* unlocked */
+
+    freeMemory(fdata, datasize);
+    freeMemory(header, (int)labbyt*sizeof(char));
+
+    return(0);
+}
+#endif
+
diff --git a/src/strings.cpp b/src/strings.cpp
new file mode 100644
index 0000000..281b527
--- /dev/null
+++ b/src/strings.cpp
@@ -0,0 +1,546 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ * 
+ * Authors:     J.R. Bilbao-Castro (jrbcast at ace.ual.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include <math.h>
+#include "src/strings.h"
+#include "src/error.h"
+#include "src/macros.h"
+#include "src/gcc_version.h"
+
+std::string removeChar( const std::string& str, char character )
+{
+    std::string temp;
+
+    for( unsigned int i = 0 ; i < str.length( ) ; i++ )
+    {
+        if ( str[ i ] != character )
+            temp += str[ i ];
+    }
+
+    return temp;
+}
+
+std::string unescape( const std::string& str )
+{
+    std::string temp;
+
+    for( unsigned int i = 0 ; i < str.length( ) ; i++ )
+    {
+        char current_char = str[ i ];
+
+        if( current_char != '\n' && current_char != '\t' &&
+            current_char != '\v' && current_char != '\b' &&
+            current_char != '\r' && current_char != '\f' &&
+            current_char != '\a' )
+        {
+            temp += str[ i ];
+        }
+        else if (current_char == '\t')
+        {
+        	temp += ' ';
+        }
+    }
+
+    return temp;
+}
+
+std::string simplify( const std::string& str )
+{
+    std::string temp;
+
+    // First, unescape string
+    std::string straux = unescape( str );
+
+    // Remove spaces from the beginning
+    int pos = straux.find_first_not_of( ' ' );
+    straux.erase( 0, pos );
+
+    // Trim the rest of spaces
+    for( unsigned int i = 0 ; i < straux.length( ) ; )
+    {
+        temp += straux[ i ];
+
+        if ( straux[ i ] == ' ' )
+        {
+            while( straux[ i ] == ' ' )
+            {
+                i++;
+            }
+        }
+        else
+        {
+            i++;
+        }
+    }
+
+    // Remove space left at the end of the string
+    // if needed
+    if( temp[ temp.size( ) - 1 ] == ' ' )
+    {
+        temp.resize( temp.size() - 1 );
+    }
+
+    return temp;
+}
+
+/** Trim all spaces from the begining and the end */
+void trim(std::string& str)
+{
+    std::string::size_type pos = str.find_last_not_of(' ');
+
+    if (pos != std::string::npos)
+    {
+        str.erase(pos + 1);
+        pos = str.find_first_not_of(' ');
+        if (pos != std::string::npos)
+            str.erase(0, pos);
+    }
+    else
+        str.clear();
+}
+
+/* NOTE: not a very safe implemenation but standard c functions do not retrieve
+ * more than 6 significative digits */
+double textToDouble(const char* str, int _errno, std::string errmsg)
+{
+    double retval;
+    int ok;
+
+    if (str == NULL)
+    	REPORT_ERROR( errmsg);
+
+    ok = sscanf(str, "%lf", &retval);
+
+    if (ok)
+        return retval;
+
+    REPORT_ERROR( errmsg);
+
+    return 0;
+}
+
+float textToFloat(const char* str, int _errno, std::string errmsg)
+{
+    float retval;
+    int ok;
+
+    if (str == NULL)
+    	REPORT_ERROR( errmsg);
+
+    ok = sscanf(str, "%f", &retval);
+
+    if (ok)
+        return retval;
+
+    REPORT_ERROR( errmsg);
+
+    return 0;
+}
+
+int textToInteger(const char* str, int _errno, std::string errmsg)
+{
+    int retval;
+    int ok;
+
+    if (str == NULL)
+    	REPORT_ERROR( errmsg);
+
+    ok = sscanf(str, "%d", &retval);
+
+    if (ok)
+        return retval;
+
+    REPORT_ERROR( errmsg);
+
+    return 0;
+}
+
+long long textToLongLong(const char* str, int _errno, std::string errmsg)
+{
+    long long int retval;
+    int ok;
+
+    if (str == NULL)
+    	REPORT_ERROR( errmsg);
+
+    ok = sscanf(str, "%lld", &retval);
+
+    if (ok)
+        return retval;
+
+    REPORT_ERROR( errmsg);
+    return 0;
+}
+
+int bestPrecision(float F, int _width)
+{
+    // If it is 0
+    if (F == 0)
+        return 1;
+
+    // Otherwise
+    int exp = FLOOR(log10(ABS(F)));
+    int advised_prec;
+
+    if (exp >= 0)
+        if (exp > _width - 3)
+            advised_prec = -1;
+        else
+            advised_prec = _width - 2;
+    else
+    {
+        advised_prec = _width + (exp - 1) - 3;
+        if (advised_prec <= 0)
+            advised_prec = -1;
+    }
+
+    if (advised_prec < 0)
+        advised_prec = -1; // Choose exponential format
+
+    return advised_prec;
+}
+
+std::string floatToString(float F, int _width, int _prec)
+{
+#if GCC_VERSION < 30300
+    char aux[15];
+    std::ostrstream outs(aux, sizeof(aux));
+#else
+    std::ostringstream outs;
+#endif
+
+    outs.fill(' ');
+
+    if (_width != 0)
+        outs.width(_width);
+
+    if (_prec == 0)
+        _prec = bestPrecision(F, _width);
+
+    if (_prec == -1 && _width > 7)
+    {
+        outs.precision(_width - 7);
+        outs.setf(std::ios::scientific);
+    }
+    else
+        outs.precision(_prec);
+
+#if GCC_VERSION < 30301
+    outs << F << std::ends;
+#else
+    outs << F;
+#endif
+
+#if GCC_VERSION < 30300
+    return std::string(aux);
+#else
+    std::string retval = outs.str();
+    int i = retval.find('\0');
+
+    if (i != -1)
+        retval = retval.substr(0, i);
+
+    return retval;
+#endif
+}
+
+std::string integerToString(int I, int _width, char fill_with)
+{
+    char aux[15];
+
+    // Check width
+    int width = _width;
+    int Iaux = ABS(I);
+
+    if (SGN(I) < 0)
+        width--;
+
+    if (width == 0)
+        do
+        {
+            Iaux /= 10;
+            width++;
+        }
+        while (Iaux != 0);
+
+    // Fill the number with the fill character
+    for (int i = 0; i < width; i++)
+        aux[i] = fill_with;
+
+    // Start filling the array
+    aux[width--] = '\0';
+    Iaux = ABS(I);
+    do
+    {
+        int digit = Iaux % 10;
+        Iaux /= 10;
+        aux[width--] = '0' + digit;
+    }
+    while (Iaux != 0);
+
+    if (SGN(I) < 0)
+        return static_cast< std::string >("-")  + aux;
+    else
+    	return static_cast< std::string >(aux);
+}
+
+int textToInt(const char* str, int _errno, std::string errmsg)
+{
+    char readval;
+    int ok;
+
+    if (str == NULL)
+    	REPORT_ERROR( errmsg);
+
+    ok = sscanf(str, "%c", &readval);
+
+    if (ok)
+        return readval - 48;
+
+    REPORT_ERROR( errmsg);
+
+    return 0;
+}
+
+std::string stringToString(const std::string& str, int _width)
+{
+    if (_width == 0)
+        return str;
+
+    if (_width < str.length())
+        return str.substr(0, _width);
+
+    std::string aux = str;
+    return aux.append(_width - str.length(), ' ');
+}
+
+void checkAngle(const std::string& str)
+{
+    if (str == "rot")
+        return;
+
+    if (str == "tilt")
+        return;
+
+    if (str == "psi")
+        return;
+
+    REPORT_ERROR(
+                 static_cast< std::string >(
+                     "checkAngle: Not recognized angle type: " + str));
+}
+
+std::string removeSpaces(const std::string& _str)
+{
+    std::string retval;
+    int first = _str.find_first_not_of("\n \t");
+    int last = _str.find_last_not_of("\n \t");
+    bool after_blank = false;
+
+    for (int i = first; i <= last; i++)
+    {
+        if (_str[i] == ' ' || _str[i] == '\n' || _str[i] == '\t')
+        {
+            if (!after_blank)
+                retval += _str[i];
+
+            after_blank = true;
+        }
+        else
+        {
+            retval += _str[i];
+            after_blank = false;
+        }
+    }
+
+    return retval;
+}
+
+// Remove quotes ===========================================================
+void removeQuotes(char **_str)
+{
+    std::string retval = *_str;
+    if (retval.length() == 0)
+        return;
+    char c = retval[0];
+    if (c == '\"' || c == '\'')
+        retval = retval.substr(1, retval.length() - 1);
+    c = retval[retval.length()-1];
+    if (c == '\"' || c == '\'')
+        retval = retval.substr(0, retval.length() - 1);
+    free(*_str);
+    *_str = strdup(retval.c_str());
+}
+
+// Split a string ==========================================================
+int splitString(const std::string& input,
+                const std::string& delimiter,
+                std::vector< std::string >& results,
+                bool includeEmpties)
+{
+    results.clear();
+    int iPos = 0;
+    int newPos = -1;
+    int sizeS2 = static_cast< int >(delimiter.size());
+    int isize = static_cast< int >(input.size());
+
+    if (isize == 0 || sizeS2 == 0)
+        return 0;
+
+    std::vector< int > positions;
+    newPos = input.find(delimiter, 0);
+
+    if (newPos < 0)
+        return 0;
+
+    int numFound = 0;
+    while (newPos >= iPos)
+    {
+        numFound++;
+        positions.push_back(newPos);
+        iPos = newPos;
+        newPos = input.find(delimiter, iPos + sizeS2);
+    }
+
+    if (numFound == 0)
+        return 0;
+
+    for (int i = 0; i <= static_cast< int >(positions.size()); i++)
+    {
+        std::string s("");
+        if (i == 0)
+            s = input.substr(i, positions[i]);
+        int offset = positions[i-1] + sizeS2;
+        if (offset < isize)
+        {
+            if (i == positions.size())
+                s = input.substr(offset);
+            else if (i > 0)
+                s = input.substr(positions[i-1] + sizeS2,
+                                 positions[i] - positions[i-1] - sizeS2);
+        }
+        if (includeEmpties || s.size() > 0)
+            results.push_back(s);
+    }
+    return numFound;
+}
+
+// To lower ================================================================
+void toLower(char *_str)
+{
+    int i = 0;
+    while (_str[i] != '\0')
+    {
+        if (_str[i] >= 'A' && _str[i] <= 'Z')
+            _str[i] += 'a' -'A';
+        i++;
+    }
+}
+
+void toLower(std::string &_str)
+{
+    int i = 0;
+    while (_str[i] != '\0')
+    {
+        if (_str[i] >= 'A' && _str[i] <= 'Z')
+            _str[i] += 'a' -'A';
+        i++;
+    }
+}
+
+// Next token ==============================================================
+std::string nextToken(const std::string &str, int &i)
+{
+    std::string retval;
+    if (i >= str.length())
+        return retval;
+    int j = str.find_first_not_of(" \t\n", i);
+    if (j == -1)
+        return retval;
+    int k = str.find_first_of(" \t\n", j + 1);
+    if (k == -1)
+        k = str.length();
+    retval = str.substr(j, k - j + 1);
+    i = k + 1;
+    return retval;
+}
+
+// Get word ================================================================
+char *firstWord(char *str, int _errno, const std::string &errmsg)
+{
+    char *token;
+
+    // Get token
+    if (str != NULL)
+        token = firstToken(str);
+    else
+        token = nextToken();
+
+    // Check that there is something
+    if (token == NULL)
+    	REPORT_ERROR( errmsg);
+
+    return token;
+}
+
+// Tokenize a C++ string ===================================================
+void tokenize(const std::string& str, std::vector<std::string>& tokens,
+              const std::string& delimiters)
+{
+    tokens.clear();
+    // Skip delimiters at beginning.
+    std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
+    // Find first "non-delimiter".
+    std::string::size_type pos     = str.find_first_of(delimiters, lastPos);
+
+    while (std::string::npos != pos || std::string::npos != lastPos)
+    {
+        // Found a token, add it to the vector.
+        tokens.push_back(str.substr(lastPos, pos - lastPos));
+        // Skip delimiters.  Note the "not_of"
+        lastPos = str.find_first_not_of(delimiters, pos);
+        // Find next "non-delimiter"
+        pos = str.find_first_of(delimiters, lastPos);
+    }
+}
diff --git a/src/strings.h b/src/strings.h
new file mode 100644
index 0000000..171cd19
--- /dev/null
+++ b/src/strings.h
@@ -0,0 +1,404 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     J.R. Bilbao-Castro (jrbcast at ace.ual.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef XMIPP_STRINGS_H
+#define XMIPP_STRINGS_H
+
+#include <map>
+#include <vector>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <string.h>
+#include <stdio.h>
+
+/// @defgroup StringUtilities String utilities
+/// @ingroup DataLibrary
+//@{
+
+//@name String processing
+//@{
+
+/** Removes all occurrences of 'character' from the string no matter
+where they are */
+std::string removeChar( const std::string& str, char character );
+
+/** Removes escaped symbols ESC+n, t, v, b, r, f, and a
+ * Note that tabs are replaced by spaces.
+ * */
+std::string unescape( const std::string& str );
+
+/** Best precision for a float number.
+ *
+ * This function returns the best precision to be used in a "printf" format if
+ * this number is to fit in a given width. It returns -1 if the exponential
+ * format is advised.
+ *
+ * @code
+ * template<typename T>
+ * std::ostream& operator<<(std::ostream& out, const T& val)
+ * {
+ *     int i,j;
+ *
+ *     if (val.xdim == 0)
+ *         out << "NULL matrix" << std::endl;
+ *     else
+ *         out << std::endl;
+ *
+ *     T aux = ABSnD(val);
+ *     int prec = bestPrecision(aux.max(), 10);
+ *
+ *     for (i=STARTINGY(val); i<=FINISHINGY(val); i++)
+ *     {
+ *         for (j=STARTINGX(val); j<=FINISHINGX(val); j++)
+ *         {
+ *             out << floatToString((float) val(i,j), 10, prec) << ' ';
+ *         }
+ *         out << std::endl;
+ *     }
+ *
+ *     return out;
+ * }
+ *
+ * @endcode
+ */
+int bestPrecision(float F, int _width);
+
+/** String (char*) to double conversion.
+ *
+ * @code
+ * double key = textToDouble(firstToken(line), 1602, "Error reading key");
+ * @endcode
+ */
+double textToDouble(const char* str,
+                    int _errno = 2101,
+                    std::string errmsg = "Error in textToDouble");
+
+/** String (char*) to float conversion.
+ *
+ * @code
+ * float key = textToFloat(firstToken(line), 1602, "Error reading key");
+ * @endcode
+ */
+float textToFloat(const char* str,
+                  int _errno = 2101,
+                  std::string errmsg = "Error in textToFloat");
+
+/** String (STL) to float conversion.
+ *
+ * @code
+ * float key = textToFloat(str, 1602, "Error reading key");
+ * @endcode
+ */
+inline float textToFloat(const std::string& str,
+                         int _errno = 2101,
+                         std::string errmsg = "Error in textToFloat")
+{
+    return textToFloat(str.c_str(), _errno, errmsg);
+}
+
+/** String (char*) to integer conversion.
+ *
+ * @code
+ * int param_no = textToInteger(nextToken(), 1602, "Error reading number parameters")
+ * @endcode
+ */
+int textToInteger(const char* str,
+                  int _errno = 2102,
+                  std::string errmsg = "Error in textToInteger");
+
+/** String (STL) to integer conversion.
+ *
+ * @code
+ * int param_no = textToInteger(str, 1602, "Error reading number parameters")
+ * @endcode
+ */
+inline int textToInteger(const std::string& str,
+                         int _errno = 2102,
+                         std::string errmsg = "Error in textToInteger")
+{
+    return textToInteger(str.c_str(), _errno, errmsg);
+}
+
+/** String (char*) to long long integer conversion.
+ *
+ * @code
+ * long long param_no = textToLongLong(nextToken(), 1602, "Error reading number
+ *     parameters")
+ * @endcode
+ */
+long long textToLongLong(const char* str,
+                         int _errno = 2102,
+                         std::string errmsg = "Error in AtoL");
+
+/** Float to string conversion.
+ *
+ * If precision==0 the precision is automatically computed in such a way that
+ * the number fits the width (the exponential format might be chosen). If
+ * precision==-1 then the exponential format is forced. If width==0 then the
+ * minimum width is used.
+ *
+ * @code
+ * REPORT_ERROR(1602, "Value not recognised " + floatToString(val));
+ * @endcode
+ */
+std::string floatToString(float F, int _width = 0, int _prec = 0);
+
+/** Integer to string conversion.
+ *
+ * If width==0 then writes the number with the number of digits needed. The
+ * fill_with field indicates which is the filling character for the left
+ * positions.
+ *
+ * @code
+ * REPORT_ERROR(1602, "Error reading key " + integerToString(key));
+ * @endcode
+ */
+std::string integerToString(int I, int _width = 0, char fill_with = '0');
+
+/** Character to integer conversion.
+ *
+ * Takes a character and produces a number according to its ASCII code minus 48.
+ * For instance, ASCII=48 produces number 0, ASCII=49 produces 1, ..., ASCII=57
+ * produces 9, ASCII=58 produces 10!!, ... This is used when you have codified
+ * numbers greater than 9 in a single character.
+ *
+ * @code
+ * int param_no = textToInt(token, 1602, "Error reading number parameters");
+ * @endcode
+ */
+int textToInt(const char* str,
+              int _errno = 2103,
+              std::string errmsg = "Error in textToInt");
+
+/** String to string with given length conversion.
+ *
+ * The output string will have the information of the input one with the given
+ * width. If the width is smaller than the string length then the string is
+ * truncated and if it is greater the string is right padded with spaces. If
+ * width==0 then the same string is returned.
+ */
+std::string stringToString(const std::string& str, int _width = 0);
+
+/** Check angle.
+ *
+ * If the argument is not "rot", "tilt" nor "psi" an exception is thrown
+ */
+void checkAngle(const std::string& str);
+
+/** To lower.
+ *
+ * All characters between A-Z are brought to a-z. Result is rewritten on input
+ * string
+ */
+void toLower(char* _str);
+
+/** To lower, for STL strings.
+ */
+void toLower(std::string& _str);
+
+/** Removes white spaces from the beginning and the end of the string
+as well as escaped characters
+and simplifies the rest of groups of white spaces of the string to
+a single white space */
+std::string simplify( const std::string& str );
+
+/** Remove trailing spaces */
+void trim(std::string& str);
+
+/** Remove consecutive spaces.
+ *
+ * All consecutive spaces are replaced by a single one and starting and
+ * finishing spaces are removed
+ */
+std::string removeSpaces(const std::string& _str);
+
+/** Remove quotes.
+ *
+ * This function removes the first character if it is a double or single quote,
+ * as well as the last character. The char pointer might be moved.
+ *
+ * @code
+ * char str[10] = "\"Hello\"";
+ * (&str);
+ * @endcode
+ */
+void removeQuotes(char** _str);
+//@}
+
+/** @name Tokenization
+ *
+ * These functions allow to split a string into small pieces separated by blank
+ * spaces, giving you a pointer to the different word each time. The different
+ * elements from the string are selected using strtok, so after the application
+ * of this function to the input string, this is modified and NULL characters
+ * are introduced as delimiters of the elements. This is useful in most
+ * situations since after reading a list you might go on reading more things,
+ * but you must be aware of it. Here goes an example of doing so:
+ *
+ * @code
+ * std::cout << "Whole  line: " << line << std::endl;
+ * std::cout << "First  word: " << firstToken(line) << std::endl;
+ * std::cout << "Second word: " << nextToken() << std::endl;
+ * std::cout << "Third  word: " << nextToken() << std::endl;
+ * ...
+ * @endcode
+ *
+ * When there are no more words, both functions return a NULL pointer. Here we
+ * make a distinction between tokens (words that might be empty) and words
+ * (words that cannot be empty, if they are then an exception or an exit error
+ * is thrown).
+ *
+ * For STL there is another way. You supply a string object and a vector of
+ * strings is returned with all the elements
+ */
+//@{
+/** Split a STL string given some delimiter.
+ *
+ * Returns a the number of tokens found. The tokens are in the variable results.
+ */
+int splitString(const std::string& input,
+                const std::string& delimiter,
+                std::vector< std::string >& results,
+                bool includeEmpties = false);
+
+/** Returns first token (char*).
+ *
+ * @code
+ * char line[80];
+ *
+ * std::cout << "First  word: " << firstToken(line) << std::endl;
+ * @endcode
+ */
+inline char* firstToken(const char* str)
+{
+    return strtok((char*) str, " \t\n");
+}
+
+/** Returns first token (STL).
+ *
+ * @code
+ * std::string line;
+ *
+ * std::cout << "First  word: " << firstToken(line) << std::endl;
+ * @endcode
+ */
+inline char* firstToken(const std::string& str)
+{
+    return strtok((char*) str.c_str(), " \t\n");
+}
+
+/** Returns next token.
+ *
+ * This functions returns the next word of the line we have given last as
+ * parameter to firstToken.
+ *
+ * @code
+ * char line[80];
+ * ...
+ * firstToken(line);
+ * std::cout << "Second  word: " << nextToken(line) << std::endl;
+ *
+ * stf::string line;
+ * ...
+ * firstToken(line);
+ * std::cout << "Second  word: " << nextToken(line) << std::endl;
+ * @endcode
+ */
+inline char* nextToken()
+{
+    return strtok((char*) NULL, " \t\n");
+}
+
+/** Returns next token.
+ *
+ * It reads from position i. Returns (in i) the following position to search on.
+ * When there are no more tokens. It returns "".
+ */
+std::string nextToken(const std::string& str, int& i);
+
+/** Get non empty string (char*).
+ *
+ * This function returns the first word found in the given line disregarding the
+ * leading blanks. If no word is found then an exception or an exit error is
+ * produced. After calling this function the first blank character after the
+ * word is substituted by a NULL character (as it uses the function firstToken.
+ * Further word readings should use the function read_nextWord
+ */
+char* firstWord(char* str,
+                int _errno = 2106,
+                const std::string & errmsg = "first word: String not found");
+
+/** Get non empty string (STL).
+ *
+ * Same as the previous function but for STL strings
+ */
+inline char* firstWord(std::string& str,
+                       int _errno = 2106,
+                       std::string errmsg = "first word: String not found")
+{
+    // FIXME C-style cast
+    return firstWord((char*) str.c_str(), _errno, errmsg);
+}
+
+/** Get next non empty string.
+ *
+ * This is the same as the nextToken, but an exception is thrown or an exit
+ * error produced if the word is empty
+ */
+inline char* nextWord(int _errno = 2106,
+                      std::string errmsg = "next word: String not found")
+{
+    return firstWord((char*) NULL, _errno, errmsg);
+}
+
+/** Tokenize a string and return a list of tokens
+ *
+ */
+void tokenize(const std::string& str,
+              std::vector< std::string >& tokens,
+              const std::string& delimiters = " \t");
+//@}
+//@}
+#endif
diff --git a/src/symmetries.cpp b/src/symmetries.cpp
new file mode 100644
index 0000000..6c2d443
--- /dev/null
+++ b/src/symmetries.cpp
@@ -0,0 +1,921 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include <stdio.h>
+
+#include "src/symmetries.h"
+
+// Read Symmetry file ======================================================
+// crystal symmetry matices from http://cci.lbl.gov/asu_gallery/
+int SymList::read_sym_file(FileName fn_sym)
+{
+    int i, j;
+    FILE *fpoii;
+    char line[80];
+    char *auxstr;
+    double ang_incr, rot_ang;
+    int  fold;
+    Matrix2D<double> L(4, 4), R(4, 4);
+    Matrix1D<double> axis(3);
+    int pgGroup = 0, pgOrder = 0;
+    std::vector<std::string> fileContent;
+
+    //check if reserved word
+
+    // Open file ---------------------------------------------------------
+    if ((fpoii = fopen(fn_sym.c_str(), "r")) == NULL)
+    {
+        //check if reserved word and return group and order
+        if (isSymmetryGroup(fn_sym, pgGroup, pgOrder))
+        {
+        	fill_symmetry_class(fn_sym, pgGroup, pgOrder, fileContent);
+        }
+        else
+            REPORT_ERROR((std::string)"SymList::read_sym_file:Can't open file: "
+                     + " or do not recognize symmetry group" + fn_sym);
+    }
+    else
+    {
+        while (fgets(line, 79, fpoii) != NULL)
+        {
+            if (line[0] == ';' || line[0] == '#' || line[0] == '\0')
+            	continue;
+			fileContent.push_back(line);
+        }
+        fclose(fpoii);
+    }
+
+    // Count the number of symmetries ------------------------------------
+    true_symNo = 0;
+    // count number of axis and mirror planes. It will help to identify
+    // the crystallographic symmetry
+
+    int no_axis, no_mirror_planes, no_inversion_points;
+    no_axis = no_mirror_planes = no_inversion_points = 0;
+
+    for (int n=0; n<fileContent.size(); n++)
+    {
+    	strcpy(line,fileContent[n].c_str());
+        auxstr = firstToken(line);
+        if (auxstr == NULL)
+        {
+            std::cout << line;
+            std::cout << "Wrong line in symmetry file, the line is skipped\n";
+            continue;
+        }
+        if (strcmp(auxstr, "rot_axis") == 0)
+        {
+            auxstr = nextToken();
+            fold = textToInteger(auxstr);
+            true_symNo += (fold - 1);
+            no_axis++;
+        }
+        else if (strcmp(auxstr, "mirror_plane") == 0)
+        {
+            true_symNo++;
+            no_mirror_planes++;
+        }
+        else if (strcmp(auxstr, "inversion") == 0)
+        {
+            true_symNo += 1;
+            no_inversion_points = 1;
+        }
+    }
+    // Ask for memory
+    __L.resize(4*true_symNo, 4);
+    __R.resize(4*true_symNo, 4);
+    __chain_length.resize(true_symNo);
+    __chain_length.initConstant(1);
+
+    // Read symmetry parameters
+    i = 0;
+    for (int n=0; n<fileContent.size(); n++)
+    {
+        strcpy(line,fileContent[n].c_str());
+        auxstr = firstToken(line);
+        // Rotational axis ---------------------------------------------------
+        if (strcmp(auxstr, "rot_axis") == 0)
+        {
+            auxstr = nextToken();
+            fold = textToInteger(auxstr);
+            auxstr = nextToken();
+            XX(axis) = textToDouble(auxstr);
+            auxstr = nextToken();
+            YY(axis) = textToDouble(auxstr);
+            auxstr = nextToken();
+            ZZ(axis) = textToDouble(auxstr);
+            ang_incr = 360. / fold;
+            L.initIdentity();
+            for (j = 1, rot_ang = ang_incr; j < fold; j++, rot_ang += ang_incr)
+            {
+                rotation3DMatrix(rot_ang, axis, R);
+                R.setSmallValuesToZero();
+                set_matrices(i++, L, R.transpose());
+            }
+            __sym_elements++;
+            // inversion ------------------------------------------------------
+        }
+        else if (strcmp(auxstr, "inversion") == 0)
+        {
+            L.initIdentity();
+            L(2, 2) = -1;
+            R.initIdentity();
+            R(0, 0) = -1.;
+            R(1, 1) = -1.;
+            R(2, 2) = -1.;
+            set_matrices(i++, L, R);
+            __sym_elements++;
+            // mirror plane -------------------------------------------------------------
+        }
+        else if (strcmp(auxstr, "mirror_plane") == 0)
+        {
+            auxstr = nextToken();
+            XX(axis) = textToFloat(auxstr);
+            auxstr = nextToken();
+            YY(axis) = textToFloat(auxstr);
+            auxstr = nextToken();
+            ZZ(axis) = textToFloat(auxstr);
+            L.initIdentity();
+            L(2, 2) = -1;
+            Matrix2D<double> A;
+            alignWithZ(axis,A);
+            A = A.transpose();
+            R = A * L * A.inv();
+            L.initIdentity();
+            set_matrices(i++, L, R);
+            __sym_elements++;
+        }
+    }
+
+    compute_subgroup();
+
+    return pgGroup;
+}
+
+// Get matrix ==============================================================
+void SymList::get_matrices(int i, Matrix2D<double> &L, Matrix2D<double> &R)
+const
+{
+    int k, l;
+    L.initZeros(4, 4);
+    R.initZeros(4, 4);
+    for (k = 4 * i; k < 4*i + 4; k++)
+        for (l = 0; l < 4; l++)
+        {
+            L(k - 4*i, l) = __L(k, l);
+            R(k - 4*i, l) = __R(k, l);
+        }
+}
+
+// Set matrix ==============================================================
+void SymList::set_matrices(int i, const Matrix2D<double> &L,
+                           const Matrix2D<double> &R)
+{
+    int k, l;
+    for (k = 4 * i; k < 4*i + 4; k++)
+        for (l = 0; l < 4; l++)
+        {
+            __L(k, l) = L(k - 4 * i, l);
+            __R(k, l) = R(k - 4 * i, l);
+        }
+}
+
+// Add matrix ==============================================================
+void SymList::add_matrices(const Matrix2D<double> &L, const Matrix2D<double> &R,
+                           int chain_length)
+{
+    if (MAT_XSIZE(L) != 4 || MAT_YSIZE(L) != 4 || MAT_XSIZE(R) != 4 || MAT_YSIZE(R) != 4)
+        REPORT_ERROR( "SymList::add_matrix: Transformation matrix is not 4x4");
+    if (TrueSymsNo() == SymsNo())
+    {
+        __L.resize(MAT_YSIZE(__L) + 4, 4);
+        __R.resize(MAT_YSIZE(__R) + 4, 4);
+        __chain_length.resize(__chain_length.size() + 1);
+    }
+
+    set_matrices(true_symNo, L, R);
+    __chain_length(__chain_length.size() - 1) = chain_length;
+    true_symNo++;
+}
+
+// Compute subgroup ========================================================
+bool found_not_tried(const Matrix2D<int> &tried, int &i, int &j,
+                     int true_symNo)
+{
+    i = j = 0;
+    int n = 0;
+    while (n != MAT_YSIZE(tried))
+    {
+        if (tried(i, j) == 0 && !(i >= true_symNo && j >= true_symNo))
+            return true;
+        if (i != n)
+        {
+            // Move downwards
+            i++;
+        }
+        else
+        {
+            // Move leftwards
+            j--;
+            if (j == -1)
+            {
+                n++;
+                j = n;
+                i = 0;
+            }
+        }
+    }
+    return false;
+}
+
+//#define DEBUG
+void SymList::compute_subgroup()
+{
+    Matrix2D<double> I(4, 4);
+    I.initIdentity();
+    Matrix2D<double> L1(4, 4), R1(4, 4), L2(4, 4), R2(4, 4), newL(4, 4), newR(4, 4);
+    Matrix2D<int>    tried(true_symNo, true_symNo);
+    int i, j;
+    int new_chain_length;
+    while (found_not_tried(tried, i, j, true_symNo))
+    {
+        tried(i, j) = 1;
+
+        get_matrices(i, L1, R1);
+        get_matrices(j, L2, R2);
+        newL = L1 * L2;
+        newR = R1 * R2;
+        new_chain_length = __chain_length(i) + __chain_length(j);
+        Matrix2D<double> newR3 = newR;
+        newR3.resize(3,3);
+        if (newL.isIdentity() && newR3.isIdentity()) continue;
+
+        // Try to find it in current ones
+        bool found;
+        found = false;
+        for (int l = 0; l < SymsNo(); l++)
+        {
+        	get_matrices(l, L1, R1);
+            if (newL.equal(L1) && newR.equal(R1))
+            {
+                found = true;
+                break;
+            }
+        }
+
+        if (!found)
+        {
+//#define DEBUG
+#ifdef DEBUG
+           std::cout << "Matrix size " << tried.Xdim() << " "
+            << "trying " << i << " " << j << " "
+            << "chain length=" << new_chain_length << std::endl;
+            std::cout << "Result R Sh\n" << newR;
+#endif
+#undef DEBUG
+            newR.setSmallValuesToZero();
+            newL.setSmallValuesToZero();
+            add_matrices(newL, newR, new_chain_length);
+            tried.resize(MAT_YSIZE(tried) + 1, MAT_XSIZE(tried) + 1);
+        }
+    }
+}
+
+/** translate string fn_sym to symmetry group, return false
+    is translation is not possible. See URL
+    http://xmipp.cnb.uam.es/twiki/bin/view/Xmipp/Symmetry
+    for details  */
+bool SymList::isSymmetryGroup(FileName fn_sym, int &pgGroup, int &pgOrder)
+{
+   char G1,G2,G3,G4;
+   char auxChar[3];
+   //each case check lenght, check first letter, second, is number
+   //Non a point group
+
+   //remove path
+   FileName fn_sym_tmp;
+   fn_sym_tmp=fn_sym.removeDirectories();
+   int mySize=fn_sym_tmp.size();
+   bool return_true;
+   return_true=false;
+   auxChar[2]='\0';
+   //size maybe 4 because n maybe a 2 digit number
+   if(mySize>4 || mySize<1)
+   {
+      pgGroup=-1;
+      pgOrder=-1;
+      return false;
+   }
+   //get the group character by character
+   G1=toupper((fn_sym_tmp.c_str())[0]);
+   G2=toupper((fn_sym_tmp.c_str())[1]);
+   if (mySize > 2)
+   {   G3=toupper((fn_sym_tmp.c_str())[2]);
+       if(mySize > 3)
+           G4=toupper((fn_sym.c_str())[3]);
+   }
+   else
+       G4='\0';
+   //CN
+   if (mySize==2 && G1=='C' && isdigit(G2))
+   {
+       pgGroup=pg_CN;
+       pgOrder=int(G2)-48;
+       return_true=true;
+   }
+   if (mySize==3 && G1=='C' && isdigit(G2) && isdigit(G3))
+   {
+       pgGroup=pg_CN;
+       auxChar[0]=G2;
+       auxChar[1]=G3;
+       pgOrder=atoi(auxChar);
+       return_true=true;
+   }
+   //CI
+   else if (mySize==2 && G1=='C' && G2=='I')
+   {
+       pgGroup=pg_CI;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //CS
+   else if (mySize==2 && G1=='C' && G2=='S')
+   {
+       pgGroup=pg_CS;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //CNH
+   else if (mySize==3 && G1=='C' && isdigit(G2) && G3=='H')
+   {
+       pgGroup=pg_CNH;
+       pgOrder=int(G2)-48;
+       return_true=true;
+   }
+   else if (mySize==4 && G1=='C' && isdigit(G2) && isdigit(G3) && G4=='H')
+   {
+       pgGroup=pg_CNH;
+       auxChar[0]=G2;
+       auxChar[1]=G3;
+       pgOrder=atoi(auxChar);
+       return_true=true;
+   }
+   //CNV
+   else if (mySize==3 && G1=='C' && isdigit(G2) && G3=='V')
+   {
+       pgGroup=pg_CNV;
+       pgOrder=int(G2)-48;
+       return_true=true;
+   }
+   else if (mySize==4 && G1=='C' && isdigit(G2) && isdigit(G3) && G4=='V')
+   {
+       pgGroup=pg_CNV;
+       auxChar[0]=G2;
+       auxChar[1]=G3;
+       pgOrder=atoi(auxChar);
+       return_true=true;
+   }
+   //SN
+   else if (mySize==2 && G1=='S' && isdigit(G2) )
+   {
+       pgGroup=pg_SN;
+       pgOrder=int(G2)-48;
+       return_true=true;
+   }
+   else if (mySize==3 && G1=='S' && isdigit(G2) && isdigit(G3) )
+   {
+       pgGroup=pg_SN;
+       auxChar[0]=G2;
+       auxChar[1]=G3;
+       pgOrder=atoi(auxChar);
+       return_true=true;
+   }
+   //DN
+   else if (mySize==2 && G1=='D' && isdigit(G2) )
+   {
+       pgGroup=pg_DN;
+       pgOrder=int(G2)-48;
+       return_true=true;
+   }
+   if (mySize==3 && G1=='D' && isdigit(G2) && isdigit(G3))
+   {
+       pgGroup=pg_DN;
+       auxChar[0]=G2;
+       auxChar[1]=G3;
+       pgOrder=atoi(auxChar);
+       return_true=true;
+   }
+   //DNV
+   else if (mySize==3 && G1=='D' && isdigit(G2) && G3=='V')
+   {
+       pgGroup=pg_DNV;
+       pgOrder=int(G2)-48;
+       return_true=true;
+   }
+   else if (mySize==4 && G1=='D' && isdigit(G2) && isdigit(G3) && G4=='V')
+   {
+       pgGroup=pg_DNV;
+       auxChar[0]=G2;
+       auxChar[1]=G3;
+       pgOrder=atoi(auxChar);
+       return_true=true;
+   }
+   //DNH
+   else if (mySize==3 && G1=='D' && isdigit(G2) && G3=='H')
+   {
+       pgGroup=pg_DNH;
+       pgOrder=int(G2)-48;
+       return_true=true;
+   }
+   else if (mySize==4 && G1=='D' && isdigit(G2) && isdigit(G3) && G4=='H')
+   {
+       pgGroup=pg_DNH;
+       auxChar[0]=G2;
+       auxChar[1]=G3;
+       pgOrder=atoi(auxChar);
+       return_true=true;
+   }
+   //T
+   else if (mySize==1 && G1=='T')
+   {
+       pgGroup=pg_T;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //TD
+   else if (mySize==2 && G1=='T' && G2=='D')
+   {
+       pgGroup=pg_TD;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //TH
+   else if (mySize==2 && G1=='T' && G2=='H')
+   {
+       pgGroup=pg_TH;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //O
+   else if (mySize==1 && G1=='O')
+   {
+       pgGroup=pg_O;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //OH
+   else if (mySize==2 && G1=='O'&& G2=='H')
+   {
+       pgGroup=pg_OH;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I
+   else if (mySize==1 && G1=='I')
+   {
+       pgGroup=pg_I;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I1
+   else if (mySize==2 && G1=='I'&& G2=='1')
+   {
+       pgGroup=pg_I1;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I2
+   else if (mySize==2 && G1=='I'&& G2=='2')
+   {
+       pgGroup=pg_I2;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I3
+   else if (mySize==2 && G1=='I'&& G2=='3')
+   {
+       pgGroup=pg_I3;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I4
+   else if (mySize==2 && G1=='I'&& G2=='4')
+   {
+       pgGroup=pg_I4;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I5
+   else if (mySize==2 && G1=='I'&& G2=='5')
+   {
+       pgGroup=pg_I5;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //IH
+   else if (mySize==2 && G1=='I'&& G2=='H')
+   {
+       pgGroup=pg_IH;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I1H
+   else if (mySize==3 && G1=='I'&& G2=='1'&& G3=='H')
+   {
+       pgGroup=pg_I1H;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I2H
+   else if (mySize==3 && G1=='I'&& G2=='2'&& G3=='H')
+   {
+       pgGroup=pg_I2H;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I3H
+   else if (mySize==3 && G1=='I'&& G2=='3'&& G3=='H')
+   {
+       pgGroup=pg_I3H;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I4H
+   else if (mySize==3 && G1=='I'&& G2=='4'&& G3=='H')
+   {
+       pgGroup=pg_I4H;
+       pgOrder=-1;
+       return_true=true;
+   }
+   //I5H
+   else if (mySize==3 && G1=='I'&& G2=='5'&& G3=='H')
+   {
+       pgGroup=pg_I5H;
+       pgOrder=-1;
+       return_true=true;
+   }
+//#define DEBUG7
+#ifdef DEBUG7
+std::cerr << "pgGroup" << pgGroup << " pgOrder " << pgOrder << std::endl;
+#endif
+#undef DEBUG7
+
+   return return_true;
+}
+void SymList::fill_symmetry_class(const FileName symmetry, int pgGroup, int pgOrder,
+   std::vector<std::string> &fileContent)
+{
+
+	fileContent.clear();
+	if (pgGroup == pg_CN)
+    {
+    	fileContent.push_back("rot_axis " + integerToString(pgOrder) + " 0 0 1");
+    }
+    else if (pgGroup == pg_CI)
+    {
+    	fileContent.push_back("inversion ");
+    }
+    else if (pgGroup == pg_CS)
+    {
+    	fileContent.push_back("mirror_plane 0 0 1");
+    }
+    else if (pgGroup == pg_CNV)
+    {
+    	fileContent.push_back("rot_axis " + integerToString(pgOrder) + " 0 0 1");
+    	fileContent.push_back("mirror_plane 0 1 0");
+    }
+    else if (pgGroup == pg_CNH)
+    {
+    	fileContent.push_back("rot_axis " + integerToString(pgOrder) + " 0 0 1");
+    	fileContent.push_back("mirror_plane 0 0 1");
+    }
+    else if (pgGroup == pg_SN)
+    {
+        int order = pgOrder / 2;
+		if(2*order != pgOrder)
+		{
+				std::cerr << "ERROR: order for SN group must be even" << std::endl;
+				exit(0);
+		}
+        fileContent.push_back("rot_axis " + integerToString(order) + " 0 0 1");
+        fileContent.push_back("inversion ");
+    }
+    else if (pgGroup == pg_DN)
+    {
+
+    	fileContent.push_back("rot_axis " + integerToString(pgOrder) + " 0 0 1");
+    	fileContent.push_back("rot_axis 2 1 0 0");
+    }
+    else if (pgGroup == pg_DNV)
+    {
+    	fileContent.push_back("rot_axis " + integerToString(pgOrder) + " 0 0 1");
+        fileContent.push_back("rot_axis 2 1 0 0");
+        fileContent.push_back("mirror_plane 1 0 0");
+    }
+    else if (pgGroup == pg_DNH)
+    {
+        fileContent.push_back("rot_axis " + integerToString(pgOrder) + " 0 0 1");
+        fileContent.push_back("rot_axis 2 1 0 0");
+        fileContent.push_back("mirror_plane 0 0 1");
+    }
+    else if (pgGroup == pg_T)
+    {
+        fileContent.push_back("rot_axis 3  0. 0. 1.");
+        fileContent.push_back("rot_axis 2 0. 0.816496 0.577350");
+    }
+    else if (pgGroup == pg_TD)
+    {
+        fileContent.push_back("rot_axis 3  0. 0. 1.");
+        fileContent.push_back("rot_axis 2 0. 0.816496 0.577350");
+        fileContent.push_back("mirror_plane 1.4142136 2.4494897 0.0000000");
+    }
+    else if (pgGroup == pg_TH)
+    {
+        fileContent.push_back("rot_axis 3  0. 0. 1.");
+        fileContent.push_back("rot_axis 2 0. -0.816496 -0.577350");
+        fileContent.push_back("inversion");
+    }
+    else if (pgGroup == pg_O)
+    {
+        fileContent.push_back("rot_axis 3  .5773502  .5773502 .5773502");
+        fileContent.push_back("rot_axis 4 0 0 1");
+    }
+    else if (pgGroup == pg_OH)
+    {
+        fileContent.push_back("rot_axis 3  .5773502  .5773502 .5773502");
+        fileContent.push_back("rot_axis 4 0 0 1");
+        fileContent.push_back("mirror_plane 0 1 1");
+    }
+    else if (pgGroup == pg_I || pgGroup == pg_I2)
+    {
+        fileContent.push_back("rot_axis 2  0 0 1");
+        fileContent.push_back("rot_axis 5  0.525731114  0 0.850650807");
+        fileContent.push_back("rot_axis 3  0 0.356822076 0.934172364");
+    }
+    else if (pgGroup == pg_I1)
+    {
+        fileContent.push_back("rot_axis 2  1  	   0	       0");
+        fileContent.push_back("rot_axis 5 0.85065080702670 0 -0.5257311142635");
+        fileContent.push_back("rot_axis 3 0.9341723640 0.3568220765 0");
+    }
+    else if (pgGroup == pg_I3)
+    {
+        fileContent.push_back("rot_axis 2  -0.5257311143 0 0.8506508070");
+        fileContent.push_back("rot_axis 5  0. 0. 1.");
+        fileContent.push_back("rot_axis 3  -0.4911234778630044, 0.3568220764705179, 0.7946544753759428");
+    }
+    else if (pgGroup == pg_I4)
+    {
+        fileContent.push_back("rot_axis 2  0.5257311143 0 0.8506508070");
+        fileContent.push_back("rot_axis 5  0.8944271932547096 0 0.4472135909903704");
+        fileContent.push_back("rot_axis 3  0.4911234778630044 0.3568220764705179 0.7946544753759428");
+    }
+    else if (pgGroup == pg_I5)
+    {
+        std::cerr << "ERROR: Symmetry pg_I5 not implemented" << std::endl;
+        exit(0);
+    }
+    else if (pgGroup == pg_IH || pgGroup == pg_I2H)
+    {
+        fileContent.push_back("rot_axis 2  0 0 1");
+        fileContent.push_back("rot_axis 5  0.525731114  0 0.850650807");
+        fileContent.push_back("rot_axis 3  0 0.356822076 0.934172364");
+        fileContent.push_back("mirror_plane 1 0 0");
+    }
+    else if (pgGroup == pg_I1H)
+    {
+        fileContent.push_back("rot_axis 2  1  	   0	       0");
+        fileContent.push_back("rot_axis 5 0.85065080702670 0 -0.5257311142635");
+        fileContent.push_back("rot_axis 3 0.9341723640 0.3568220765 0");
+        fileContent.push_back("mirror_plane 0 0 -1");
+    }
+    else if (pgGroup == pg_I3H)
+    {
+        fileContent.push_back("rot_axis 2  -0.5257311143 0 0.8506508070");
+        fileContent.push_back("rot_axis 5  0. 0. 1.");
+        fileContent.push_back("rot_axis 3  -0.4911234778630044, 0.3568220764705179, 0.7946544753759428");
+        fileContent.push_back("mirror_plane 0.850650807 0  0.525731114");
+    }
+    else if (pgGroup == pg_I4H)
+    {
+        fileContent.push_back("rot_axis 2  0.5257311143 0 0.8506508070");
+        fileContent.push_back("rot_axis 5  0.8944271932547096 0 0.4472135909903704");
+        fileContent.push_back("rot_axis 3  0.4911234778630044 0.3568220764705179 0.7946544753759428");
+        fileContent.push_back("mirror_plane 0.850650807 0 -0.525731114");
+    }
+    else if (pgGroup == pg_I5H)
+    {
+        std::cerr << "ERROR: Symmetry pg_I5H not implemented" << std::endl;
+        exit(0);
+    }
+    else
+    {
+        std::cerr << "ERROR: Symmetry " << symmetry  << "is not known" << std::endl;
+        exit(0);
+    }
+
+//#define DEBUG5
+#ifdef DEBUG5
+    for (int n=0; n<fileContent.size(); n++)
+    	std::cerr << fileContent[n] << std::endl;
+	std::cerr << "fileContent.size()" << fileContent.size() << std::endl;
+#endif
+#undef DEBUG5
+}
+
+void SymList::writeDefinition(std::ostream &outstream, FileName fn_sym)
+{
+	read_sym_file(fn_sym);
+	Matrix2D<double> L(3,3), R(3,3);
+	outstream << " ++++ Using symmetry group " << fn_sym << ", with the following " << SymsNo()+1 << " transformation matrices:"<< std::endl;
+    R.initIdentity();
+    outstream << " R(1)= " << R;
+	for (int isym = 0; isym < SymsNo(); isym++)
+    {
+        get_matrices(isym, L, R);
+        R.resize(3, 3);
+        L.resize(3, 3);
+        if (!L.isIdentity())
+        	outstream << " L("<< isym+2<<")= "<<L;
+        outstream << " R("<< isym+2<<")= "<<R;
+    }
+
+}
+
+double SymList::non_redundant_ewald_sphere(int pgGroup, int pgOrder)
+{
+    if (pgGroup == pg_CN)
+    {
+        return 4.*PI/pgOrder;
+    }
+    else if (pgGroup == pg_CI)
+    {
+        return 4.*PI/2.;
+    }
+    else if (pgGroup == pg_CS)
+    {
+        return 4.*PI/2.;
+    }
+    else if (pgGroup == pg_CNV)
+    {
+        return 4.*PI/pgOrder/2;
+    }
+    else if (pgGroup == pg_CNH)
+    {
+        return 4.*PI/pgOrder/2;
+    }
+    else if (pgGroup == pg_SN)
+    {
+        return 4.*PI/pgOrder;
+    }
+    else if (pgGroup == pg_DN)
+    {
+        return 4.*PI/pgOrder/2;
+    }
+    else if (pgGroup == pg_DNV)
+    {
+        return 4.*PI/pgOrder/4;
+    }
+    else if (pgGroup == pg_DNH)
+    {
+        return 4.*PI/pgOrder/4;
+    }
+    else if (pgGroup == pg_T)
+    {
+        return 4.*PI/12;
+    }
+    else if (pgGroup == pg_TD)
+    {
+        return 4.*PI/24;
+    }
+    else if (pgGroup == pg_TH)
+    {
+        return 4.*PI/24;
+    }
+    else if (pgGroup == pg_O)
+    {
+        return 4.*PI/24;
+    }
+    else if (pgGroup == pg_OH)
+    {
+        return 4.*PI/48;
+    }
+    else if (pgGroup == pg_I || pgGroup == pg_I2)
+    {
+        return 4.*PI/60;
+    }
+    else if (pgGroup == pg_I1)
+    {
+        return 4.*PI/60;
+    }
+    else if (pgGroup == pg_I3)
+    {
+        return 4.*PI/60;
+    }
+    else if (pgGroup == pg_I4)
+    {
+        return 4.*PI/60;
+    }
+    else if (pgGroup == pg_I5)
+    {
+        return 4.*PI/60;
+    }
+    else if (pgGroup == pg_IH || pgGroup == pg_I2H)
+    {
+        return 4.*PI/120;
+    }
+    else if (pgGroup == pg_I1H)
+    {
+        return 4.*PI/120;
+    }
+    else if (pgGroup == pg_I3H)
+    {
+        return 4.*PI/120;
+    }
+    else if (pgGroup == pg_I4H)
+    {
+        return 4.*PI/120;
+    }
+    else if (pgGroup == pg_I5H)
+    {
+        return 4.*PI/120;
+    }
+    else
+    {
+        std::cerr << "ERROR: Symmetry group, order=" << pgGroup
+                                                     << " "
+                                                     <<  pgOrder
+                                                     << "is not known"
+                                                     << std::endl;
+        exit(0);
+    }
+}
+
+void symmetriseMap(MultidimArray<double> &img, FileName &fn_sym, bool do_wrap)
+{
+
+	if (img.getDim() != 3)
+		REPORT_ERROR("symmetriseMap ERROR: symmetriseMap can only be run on 3D maps!");
+
+	img.setXmippOrigin();
+
+	SymList SL;
+	SL.read_sym_file(fn_sym);
+
+	Matrix2D<double> L(4, 4), R(4, 4); // A matrix from the list
+    MultidimArray<double> sum, aux;
+    sum = img;
+    aux.resize(img);
+
+	for (int isym = 0; isym < SL.SymsNo(); isym++)
+    {
+        SL.get_matrices(isym, L, R);
+        applyGeometry(img, aux, R, IS_INV, do_wrap);
+        sum += aux;
+    }
+
+	// Overwrite the input
+	img = sum / (SL.SymsNo() + 1);
+
+}
diff --git a/src/symmetries.h b/src/symmetries.h
new file mode 100644
index 0000000..e0174dd
--- /dev/null
+++ b/src/symmetries.h
@@ -0,0 +1,272 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+/* ------------------------------------------------------------------------- */
+/* SYMMETRIES                                                                */
+/* ------------------------------------------------------------------------- */
+#ifndef _SYMMETRIES_HH
+#define _SYMMETRIES_HH
+
+#include "src/matrix1d.h"
+#include "src/matrix2d.h"
+#include "src/euler.h"
+#include "src/funcs.h"
+#include "src/args.h"
+
+/**@defgroup SymmetryLists Symmetry handling
+   @ingroup DataLibrary
+    The symmetry lists are, simply, lists of 2D matrices. It's the way of
+    taking symmetry into account in the reconstruction programs. The
+    symmetry list must contain matrices which express equivalent views to
+    the actual one due to the underlying volume symmetry. The identity matrix
+    is not within the list. You know that symmetry matrices should form
+    a subgroup, when reading a file the subgroup is automatically computed
+    and, when you add or remove a new matrix, the subgroup must be
+    manually computed.
+*/
+//@{
+//point group symmetries
+#define pg_CI  200
+#define pg_CS  201
+#define pg_CN  202
+#define pg_CNV 203
+#define pg_CNH 204
+#define pg_SN  205
+#define pg_DN  206
+#define pg_DNV 207
+#define pg_DNH 208
+#define pg_T   209
+#define pg_TD  210
+#define pg_TH  211
+#define pg_O   212
+#define pg_OH  213
+#define pg_I   214  //default xmipp icosahedaral symmetry
+#define pg_IH  215
+
+#define pg_I1   216 //no crowther 222
+#define pg_I2   217 //crowther 222-> default in xmipp
+#define pg_I3   218 //52 as used by spider
+#define pg_I4   219 //another 52
+#define pg_I5   220 //another another 52 (used by EMBL-matfb)
+
+#define pg_I1H  221 //no crowther 222, + mirror plane
+#define pg_I2H  222 //crowther 222-> default in xmipp+ mirror plane
+#define pg_I3H  223 //52 as used by spider+ mirror plane
+#define pg_I4H  224 //another 52+ mirror plane
+#define pg_I5H  225 //another another 52 (used by EMBL-matfb)+ mirror plane
+
+/** Number of an image in the reconstruction list.
+    This macro returns the index of a symmetry image (after the symmetry matrix
+    number sym_no) within a list where the first images are true images and the
+    last ones, the symmetrized copies (all copies of a same image are
+    together). The total number of real images is numIMG, and i is the index
+    within this first numIMG images of the image we want to symmetrize The
+    first image in the list is the number 0 */
+#define SYMINDEX(SL, sym_no, i, numIMG) \
+    numIMG+SL.__L.mdimy/4*i+sym_no
+
+/** Symmetry List class.
+    Internally the symmetry list class is implemented as a single 2D matrix,
+    where every 4 rows (remember that in 3D the geometrical transformation
+    matrices are 4x4) comprise a symmetry matrix. Access, and ways to modify
+    the symmetry list are supplied. Remind that any symmetry is expressed
+    in terms of two matrices L and R, so that any Euler matrix must be
+    transformed by L*Euler*R resulting into a new perspective of the volume
+    which is equivalent to the original one.
+
+    The typical use of the symmetry lists is to read the symmetry file, and
+    do nothing else but reading matrices from it.
+
+    The symmetry file format is
+    @code
+    #This is a comment
+    # The following line is a 6-fold rotational symmetry axis along Z-axis.
+    # The fold is the number of times that the volume can be rotated along
+    # the symmetry axis giving the same view from different view points.
+    # the structure for the rotational axis is
+    # rot_axis      <fold> <X0> <Y0> <Z0>
+    # mirror_plane         <X0> <Y0> <Z0>
+    rot_axis      6 0 0 1
+    mirror_plane    0 0 1
+    @endcode
+*/
+class SymList
+{
+public:
+    // L and R matrices
+    Matrix2D<double> __L, __R;
+    Matrix1D<int>    __chain_length;
+
+    // As the symmetry elements form a subgroup, this is the number of
+    // true symmetry elements belonging to the list, the rest of
+    // the list are simply the elements to fill the subgroup
+    int true_symNo;
+
+    // Number of Axis, mirrors, ...
+    int              __sym_elements;
+
+public:
+    /** Create an empty list.
+        The 2D matrices are 0x0.
+        \\ Ex: SymList SL; */
+    SymList()
+    {
+        __sym_elements = true_symNo = 0;
+    }
+
+    /** translate string fn_sym to symmetry group, return false
+        is translation is not possible. See
+        http://xmipp.cnb.uam.es/twiki/bin/view/Xmipp/Symmetry
+         for details. It also fill the symmetry information  */
+    bool isSymmetryGroup(FileName fn_sym, int &pgGroup, int &pgOrder);
+
+    /** fill fileContect with symmetry information*/
+    void fill_symmetry_class(const FileName symmetry, int pgGroup, int pgOrder,
+                             std::vector<std::string> &fileContent);
+
+
+    /** Create Symmetry List from a Symmetry file.
+        All the subgroup elements are computed automatically.
+        \\ Ex: SymList SL("sym.txt"); */
+    SymList(const FileName& fn_sym)
+    {
+        read_sym_file(fn_sym);
+    }
+
+    /** Get matrices from the symmetry list.
+        The number of matrices inside the list is given by SymsNo.
+        This function return the 4x4 transformation matrices associated to
+        the one in the list which occupies the position 'i'. The matrix
+        numbering within the list starts at 0. The output transformation
+        matrices is given as a pointer to gain speed.
+        \\ Ex:
+        @code
+           for (i=0; i<SL.SymsNo; i++) {
+               SL.get_matrices(i,L,R);
+               ...
+           }
+        @endcode */
+    void get_matrices(int i, Matrix2D<double> &L, Matrix2D<double> &R) const;
+
+    /** Set a couple of matrices in the symmetry list.
+        The number of matrices inside the list is given by SymsNo.
+        This function sets the 4x4 transformation matrices associated to
+        the one in the list which occupies the position 'i'. The matrix
+        numbering within the list starts at 0.
+        \\ Ex:
+        @code
+           for (i=0; i<SL.SymsNo; i++) {
+               SL.set_matrix(i,L,R);
+               ...
+           }
+        @endcode */
+    void set_matrices(int i, const Matrix2D<double> &L, const Matrix2D<double> &R);
+
+    /** Read a symmetry file into a symmetry list.
+        The former symmetry list is overwritten with the new one. All the
+        subgroup members are added to the list. If the accuracy is negative
+        then the subgroup is not generated. return symmetry group
+        \\ Ex: SL.read_sym_file("sym.txt");*/
+    int read_sym_file(FileName fn_sym);
+
+    /** Add symmetry matrices to the symmetry list.
+        The given matrix must specify a point of view equivalent to the
+        actual point of view. The matrices are added to the subgroup generator
+        but the subgroup is not updated, you must do it manually using
+        compute_subgroup. What is more, the subgroup after the insertion
+        is corrupted.
+
+        The chain length is the number of single matrices multiplication of
+        which the inserted one is compound.*/
+    void add_matrices(const Matrix2D<double> &L, const Matrix2D<double> &R,
+                      int chain_length);
+
+    /** Compute subgroup for this structure.
+        After adding or setting a matrix, the subgroup information
+        is lost, you must recalculate it using this function. The different
+        matrices are multiplied until no more different matrices are produced.
+        The accuracy is used in order to compare when two matrix elements are
+        the same.
+
+        So far, all the shifts associated to generated matrices are set to 0*/
+    void compute_subgroup();
+
+    /** Number of symmetry matrices inside the structure.
+        This is the number of all the matrices inside the subgroup.
+        \\ Ex:
+        @code
+           for (i=0; i<SL.SymsNo; i++) {
+               SL.get_matrix(i,A);
+               ...
+           }
+        @endcode */
+    int SymsNo() const
+    {
+        return MAT_YSIZE(__L) / 4;
+    }
+
+    /** Number of symmetry matrices which generated the structure.
+        This is the number of the matrices which generated the structure,
+        notice that it should be always less or equal to the total number
+        of matrices in the subgroup. */
+    int TrueSymsNo() const
+    {
+        return true_symNo;
+    }
+
+    /** Write the symmetry definition (plus all rotation matrices) to ostream
+     *
+     */
+    void writeDefinition(std::ostream &outstream, FileName fn_sym);
+
+    /** Return the area of the non redundant part of the Ewald sphere
+    */
+    double  non_redundant_ewald_sphere(int pgGroup, int pgOrder);
+};
+
+
+// Symmetrise a 3D map according to the specified symmetry
+void symmetriseMap(MultidimArray<double> &img, FileName &fn_sym, bool do_wrap = false);
+
+//@}
+#endif
diff --git a/src/tabfuncs.cpp b/src/tabfuncs.cpp
new file mode 100644
index 0000000..5c690cb
--- /dev/null
+++ b/src/tabfuncs.cpp
@@ -0,0 +1,122 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+#include "src/tabfuncs.h"
+
+void TabSine::initialise(const int _nr_elem)
+{
+	sampling = 2 * PI / (double) _nr_elem;
+	TabSine::fillTable(_nr_elem);
+}
+//Pre-calculate table values
+void TabSine::fillTable(const int _nr_elem)
+{
+	tabulatedValues.resize(_nr_elem);
+	for (int i = 0; i < _nr_elem; i++)
+	{
+		double xx = (double) i * sampling;
+		tabulatedValues(i) = sin(xx);
+	}
+}
+// Value access
+double TabSine::operator()(double val) const
+{
+	int idx = (int)( ABS(val) / sampling);
+	double retval = DIRECT_A1D_ELEM(tabulatedValues, idx % XSIZE(tabulatedValues));
+	return (val < 0 ) ? -retval : retval;
+}
+
+void TabCosine::initialise(const int _nr_elem)
+{
+	sampling = 2 * PI / (double) _nr_elem;
+	TabCosine::fillTable();
+}
+//Pre-calculate table values
+void TabCosine::fillTable(const int _nr_elem)
+{
+	tabulatedValues.resize(_nr_elem);
+	for (int i = 0; i < _nr_elem; i++)
+	{
+		double xx = (double) i * sampling;
+		tabulatedValues(i) = cos(xx);
+	}
+}
+// Value access
+double TabCosine::operator()(double val) const
+{
+	int idx = (int)( ABS(val) / sampling);
+	return DIRECT_A1D_ELEM(tabulatedValues, idx % XSIZE(tabulatedValues));
+}
+
+void TabBlob::initialise(double _radius, double _alpha, int _order, const int _nr_elem)
+{
+	radius = _radius;
+	alpha = _alpha;
+	order = _order;
+	sampling = radius / _nr_elem;
+	TabBlob::fillTable(_nr_elem);
+}
+//Pre-calculate table values
+void TabBlob::fillTable(const int _nr_elem)
+{
+	tabulatedValues.resize(_nr_elem);
+	for (int i = 0; i < _nr_elem; i++)
+	{
+		double xx = (double) i * sampling;
+		tabulatedValues(i) = kaiser_value(xx, radius, alpha, order);
+	}
+}
+// Value access
+double TabBlob::operator()(double val) const
+{
+	int idx = (int)( ABS(val) / sampling);
+	if (idx >= XSIZE(tabulatedValues))
+		return 0.;
+	else
+		return DIRECT_A1D_ELEM(tabulatedValues, idx);
+}
+
+void TabFtBlob::initialise(double _radius, double _alpha, int _order, const int _nr_elem)
+{
+	radius = _radius;
+	alpha = _alpha;
+	order = _order;
+	sampling = 0.5 / (double)_nr_elem;
+	TabFtBlob::fillTable(_nr_elem);
+}
+//Pre-calculate table values
+void TabFtBlob::fillTable(const int _nr_elem)
+{
+	tabulatedValues.resize(_nr_elem);
+	for (int i = 0; i < _nr_elem; i++)
+	{
+		double xx = (double) i * sampling;
+		tabulatedValues(i) = kaiser_Fourier_value(xx, radius, alpha, order);
+	}
+}
+// Value access
+double TabFtBlob::operator()(double val) const
+{
+	int idx = (int)( ABS(val) / sampling);
+	if (idx >= XSIZE(tabulatedValues))
+		return 0.;
+	else
+		return DIRECT_A1D_ELEM(tabulatedValues, idx);
+}
+
diff --git a/src/tabfuncs.h b/src/tabfuncs.h
new file mode 100644
index 0000000..82d7646
--- /dev/null
+++ b/src/tabfuncs.h
@@ -0,0 +1,154 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef TABFUNCS_H_
+#define TABFUNCS_H_
+
+#include "src/multidim_array.h"
+#include "src/funcs.h"
+
+// Class to tabulate some functions
+class TabFunction
+{
+
+protected:
+	MultidimArray<double> tabulatedValues;
+	double  sampling;
+public:
+	// Empty constructor
+	TabFunction() {}
+
+	// Destructor
+    virtual ~TabFunction()
+    {
+    	tabulatedValues.clear();
+    }
+
+    /** Copy constructor
+     *
+     * The created TabFunction is a perfect copy of the input array but with a
+     * different memory assignment.
+     */
+    TabFunction(const TabFunction& op)
+    {
+    	tabulatedValues.clear();
+    	*this = op;
+    }
+
+	/** Assignment.
+     *
+     * You can build as complex assignment expressions as you like. Multiple
+     * assignment is allowed.
+     */
+    TabFunction& operator=(const TabFunction& op)
+    {
+        if (&op != this)
+        {
+         	// Projector stuff (is this necessary in C++?)
+        	tabulatedValues = op.tabulatedValues;
+        	sampling = op.sampling;
+        }
+        return *this;
+    }
+
+
+};
+
+class TabSine : public TabFunction
+{
+public:
+	// Empty constructor
+	TabSine() {}
+
+	// Constructor (with parameters)
+	void initialise(const int _nr_elem = 5000);
+
+	//Pre-calculate table values
+	void fillTable(const int _nr_elem = 5000);
+
+	// Value access
+	double operator()(double val) const;
+
+};
+
+class TabCosine : public TabFunction
+{
+public:
+	// Empty constructor
+	TabCosine() {}
+
+	void initialise(const int _nr_elem = 5000);
+
+	//Pre-calculate table values
+	void fillTable(const int _nr_elem = 5000);
+
+	// Value access
+	double operator()(double val) const;
+
+};
+
+class TabBlob : public TabFunction
+{
+
+private:
+	double radius;
+	double alpha;
+	int order;
+
+public:
+	// Empty constructor
+	TabBlob() {}
+
+	// Constructor (with parameters)
+	void initialise(double _radius, double _alpha, int _order, const int _nr_elem = 10000);
+
+	//Pre-calculate table values
+	void fillTable(const int _nr_elem = 5000);
+
+	// Value access
+	double operator()(double val) const;
+
+};
+
+class TabFtBlob : public TabFunction
+{
+
+private:
+	double radius;
+	double alpha;
+	int order;
+
+public:
+	// Empty constructor
+	TabFtBlob() {}
+
+	 // Constructor (with parameters)
+	void initialise(double _radius, double _alpha, int _order, const int _nr_elem = 10000);
+
+	//Pre-calculate table values
+	void fillTable(const int _nr_elem = 5000);
+
+	// Value access
+	double operator()(double val) const;
+
+};
+
+
+#endif /* TABFUNCS_H_ */
diff --git a/src/time.cpp b/src/time.cpp
new file mode 100644
index 0000000..3fb7ae0
--- /dev/null
+++ b/src/time.cpp
@@ -0,0 +1,239 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#include "src/time.h"
+
+/* Time managing ----------------------------------------------------------- */
+// A global ................................................................
+int XmippTICKS;
+
+// Time configuration ......................................................
+// The clock frequency for each machine must be known
+void time_config()
+{
+    XmippTICKS = sysconf(_SC_CLK_TCK);
+}
+
+// Annotate actual time ....................................................
+void annotate_time(TimeStamp *time)
+{
+    times(time);
+}
+
+// Acumulative time
+void acum_time(TimeStamp *orig, TimeStamp *dest)
+{
+    TimeStamp now;
+    times(&now);
+    (*dest).tms_utime += (*dest).tms_utime + (now.tms_utime - (*orig).tms_utime);
+    (*dest).tms_stime += (*dest).tms_stime + (now.tms_utime - (*orig).tms_utime);
+}
+
+// Show elapsed time since last annotation .................................
+void print_elapsed_time(TimeStamp &time, bool _IN_SECS)
+{
+    TimeStamp now;
+    times(&now);
+    float userTime = now.tms_utime - time.tms_utime;
+    float sysTime = now.tms_stime - time.tms_stime;
+    if (_IN_SECS)
+    {
+        userTime /= XmippTICKS;
+        sysTime /= XmippTICKS;
+    }
+    std::cout << "Elapsed time: User(" << userTime << ") System(" << sysTime
+    << ")\n";
+}
+
+// Calculate elapsed time since last annotation .............................
+float elapsed_time(TimeStamp &time, bool _IN_SECS)
+{
+    TimeStamp now;
+    times(&now);
+    float userTime = now.tms_utime - time.tms_utime;
+    float sysTime = now.tms_stime - time.tms_stime;
+    if (_IN_SECS)
+    {
+        userTime /= XmippTICKS;
+        sysTime /= XmippTICKS;
+    }
+    return userTime + sysTime;
+}
+
+// Compute the predicted time left .........................................
+float time_to_go(TimeStamp &time, float fraction_done)
+{
+    TimeStamp now;
+    times(&now);
+    float totalTime = (now.tms_utime - time.tms_utime +
+                       now.tms_stime - time.tms_stime) / XmippTICKS;
+    return totalTime*(1 - fraction_done) / fraction_done;
+}
+
+// Show a message with the time it is produced .............................
+void TimeMessage(const std::string & message)
+{
+    struct tm *T;
+    time_t     seconds;
+
+    if (time(&seconds) < 0)
+        seconds = 0;
+    T = localtime(&seconds);
+
+    printf("%2d:%2d:%2d (day=%2d) =>%s ", T->tm_hour,
+           T->tm_min, T->tm_sec, T->tm_mday, message.c_str());
+}
+
+// Init progress bar
+void init_progress_bar(long total)
+{
+    progress_bar(-(total));
+}
+
+// Show a bar with the progress in time ....................................
+// When the input is negative then we are setting the progress bar, this
+// will be the total of elements to process. Afterwards the call to this
+// routine must be in ascending order, ie, 0, 1, 2, ... No. elements
+void progress_bar(long rlen)
+{
+    static time_t startt, prevt;
+    time_t currt;
+    static long totlen;
+    long t1, t2;
+    int min, i, hour;
+    float h1, h2, m1, m2;
+
+    if (rlen == 0)
+        return;
+    currt = time(NULL);
+
+    if (rlen < 0)
+    {
+        totlen = -rlen;
+        prevt = startt = currt;
+        fprintf(stdout, "000/??? sec ");
+        fprintf(stdout, "~~(,_,\">");
+        for (i = 1; i < 10; i++)
+            fprintf(stdout, "      ");
+        fprintf(stdout, "    [oo]");
+        fflush(stdout);
+    }
+    else if (totlen > 0)
+    {
+        t1 = currt - startt;               // Elapsed time
+        t2 = (long)(t1 * (float)totlen / rlen); // Total time
+
+        hour = 0;
+        min = 0;
+        if (t2 > 60)
+        {
+            m1 = (float)t1 / 60.0;
+            m2 = (float)t2 / 60.0;
+            min = 1;
+            if (m2 > 60)
+            {
+                h1 = (float)m1 / 60.0;
+                h2 = (float)m2 / 60.0;
+                hour = 1;
+                min = 0;
+            }
+            else
+                hour = 0;
+        }
+        else
+            min = 0;
+
+        if (hour)
+            fprintf(stdout, "\r%3.2f/%3.2f %s ", h1, h2, "hrs");
+        else if (min)
+            fprintf(stdout, "\r%3.2f/%3.2f %s ", m1, m2, "min");
+        else
+            fprintf(stdout, "\r%4u/%4u %s ", (int)t1, (int)t2, "sec");
+
+        i = (int)(60 * (1 - (float)(totlen - rlen) / totlen));
+        while (i--)
+            fprintf(stdout, ".");
+        fprintf(stdout, "~~(,_,\">");
+        if (rlen == totlen)
+        {
+            fprintf(stdout, "\n");
+            totlen = 0;
+        }
+        fflush(stdout);
+        prevt = currt;
+    }
+}
+
+
+
+void Timer::clear()
+{
+	start_times.clear();
+	counts.clear();
+	times.clear();
+	tags.clear();
+}
+
+void Timer::initZero()
+{
+	for (int i = 0; i < counts.size(); i++)
+	{
+		counts[i] = 0;
+		times[i] = 0;
+	}
+}
+
+int Timer::setNew(const std::string tag)
+{
+	start_times.push_back(end_time);
+	counts.push_back(0);
+	times.push_back(0);
+	tags.push_back(tag);
+	return start_times.size() - 1;
+}
+
+void Timer::tic(int timer)
+{
+	gettimeofday(&(start_times[timer]), NULL);
+	counts[timer]++;
+}
+
+int Timer::toc(int timer)
+{
+	gettimeofday(&end_time, NULL);
+	times[timer] += (end_time.tv_sec - start_times[timer].tv_sec) * 1000000 +
+				   (end_time.tv_usec - start_times[timer].tv_usec);
+}
+
+void Timer::printTimes(bool doClear)
+{
+	for (int i = 0; i < tags.size(); i++)
+	{
+		if (counts[i] > 0)
+		{
+			std::cout.width(35);
+			std::cout << std::left << tags[i] << ": " << times[i]/1000000<< " sec (" << times[i] / counts[i] << " microsec/operation)"<<std::endl;
+		}
+	}
+	if (doClear)
+		Timer::clear();
+	else
+		Timer::initZero();
+}
diff --git a/src/time.h b/src/time.h
new file mode 100644
index 0000000..2e1fa37
--- /dev/null
+++ b/src/time.h
@@ -0,0 +1,284 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+
+#ifndef TIME_H_
+#define TIME_H_
+
+#include <sys/time.h>
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include <cstdio>
+#include <string>
+#include <climits>
+#include <vector>
+#include <typeinfo>
+
+// For timing functions
+// Uncomment next line timing functions are giving problems in your system
+//#define _NO_TIME
+#ifndef _NO_TIME
+#include <unistd.h>
+#include <sys/times.h>
+#ifdef _IRIX65
+#include <sys/types.h>
+#include <time.h>
+#endif
+#endif
+
+/** @name Time managing
+ *
+ * These functions are used to make time measures of the algorithms. If you know
+ * the total amount of work to do then some estimation can be done about how
+ * much time is left before finishing. The time functions are very machine
+ * dependent, we've tried to accomodate the compilation for several machines,
+ * but if still programs do not work, you may configure Xmipp to avoid these
+ * time measurements, functions are then substituted by null functions doing
+ * nothing.
+ *
+ * @code
+ * // Variable declaration
+ * TimeStamp t0;
+ *
+ * // Beginning of the program
+ * time_config();
+ * ...
+ *
+ * annotate_time(&t0);
+ * // Part to be measured
+ * ...
+ *
+ * // End of part to be measured
+ * print_elapsed_time(t0);
+ * @endcode
+ *
+ * While for an estimation of time to go you can make it in two ways:  one
+ * analytical, and another graphical.
+ *
+ * Analytical:
+ *
+ * @code
+ * // Variable declaration
+ * TimeStamp t0;
+ * float to_go;
+ *
+ * // Beginning of the program
+ * time_config();
+ * ...
+ *
+ * annotate_time(&t0);
+ * // Part to be measured
+ * for (int i=0; i<60; i++)
+ * {
+ *     ...
+ *     // Compute the time to go with the fraction of work already done
+ *     to_go = time_to_go(t0, (float) (i + 1) / 60);
+ *     std::cout << "I think you will be here " << to_go << "seconds more\n";
+ * }
+ * @endcode
+ *
+ * Graphical:
+ * @code
+ * // Beginning of the program
+ * time_config();
+ * ...
+ *
+ * // Init the progress bar with the total amount of work to do
+ * // It is very important that there is no print out to stdout but
+ * // the progress bar
+ * init_progress_bar(60);
+ *
+ * // Part to be measured
+ * for (int i=0; i<60; i++)
+ * {
+ *     ...
+ *     progress_bar(i+1);
+ * }
+ *
+ * // In this case the following call is useless since it has been
+ * // already done in the loop, but there are cases where a final call
+ * // with the total amount of work is not performed and although the
+ * // whole task has been finished it seems that it hasn't as the
+ * // progress bar hasn't been called with the final work but with
+ * // a quantity a little smaller.
+ * progress_bar(60);
+ * @endcode
+ *
+ */
+//@{
+typedef struct tms TimeStamp; // Renaming of the time structure
+/** Read the system clock frequency
+ *
+ * This operation is needed only once in a program always we want to have a time
+ * measure, or an estimation of remaining time.
+ *
+ * @code
+ * time_config();
+ * @endcode
+ *
+ */
+void time_config();
+/** Annotate actual time
+ *
+ * This annotation is used later to compute the elapsed time.
+ *
+ * @code
+ * TimeStamp t0;
+ * annotate_time(&t0);
+ * @endcode
+ *
+ */
+void annotate_time(TimeStamp* time);
+/** Acumulate time
+ *
+ * Initially dest_time should be set to orig time. Then you acumulate succesive
+ * times calling this function (Destination time=destination_time + (now -
+ * original time)) and finally the elapsed time is the dest time minus the first
+ * one (the one which initiliazed the dest time.
+ *
+ */
+void acum_time(TimeStamp* orig, TimeStamp* dest);
+/** Compute elapsed time since a given annotation
+ *
+ * Given an annotation of time, this function computes the time elapsed since
+ * then in seconds. The annotation is not modified. Usually the time is shown in
+ * seconds, but you might specify to show it in clock ticks setting the variable
+ * _IN_SECS to FALSE.
+ *
+ * @code
+ * TimeStamp t0;
+ * annotate_time(&t0);
+ * ...;
+ * float elapsed = elapsed_time(t0);
+ *
+ * TimeStamp t0;
+ * annotate_time(&t0);
+ * ...;
+ * float elapsed = elapsed_time(t0, FALSE);
+ * @endcode
+ *
+ */
+float elapsed_time(TimeStamp& time, bool _IN_SECS = true);
+/** Show on screen the elapsed time since a given annotation
+ *
+ * The format of the printing is "Elapsed time: User(13) System(1)" that means
+ * that the user has used 13 seconds and the system 1, a total of 14 seconds
+ * since the last annotation in this TimeStamp variable.
+ *
+ * @code
+ * TimeStamp t0;
+ * annotate_time(&t0);
+ * ...;
+ * print_elapsed_time(t0);
+ * @endcode
+ *
+ * Usually the time is shown in seconds, but you might specify to show it in
+ * clock ticks setting the variable _IN_SECS to FALSE.
+ *
+ */
+void print_elapsed_time(TimeStamp& time, bool _IN_SECS = true);
+/** Returns the estimated time left to finish
+ *
+ * To make this estimation the starting time must have been annotated before and
+ * the fraction of the total amount of work must be estimated by the programmer.
+ * See Time managing for an example.
+ *
+ */
+float time_to_go(TimeStamp& time, float fraction_done);
+/** Initialise the progress bar
+ *
+ * The progress bar is initialised to count for a total amount of work. For
+ * instance, if we are to do something 60 times, the progress bar should be
+ * initialised to that value. At the same time the bar is printed with the
+ * initial guess of time left (ie, nothing "0000/????"). The number before the
+ * slash is the elapsed time since initialisation of the progress bar, while the
+ * second number is the estimation of total time that this task will take. See
+ * Time managing for a more detailed example.
+ *
+ * @code
+ * init_progress_bar(60);
+ * @endcode
+ */
+void init_progress_bar(long total);
+/** Update progress bar
+ *
+ * With this function you can change the already done amount of work, if
+ * something is to be done 60 times and now we have already done 13 then we
+ * could tell this to the progress bar with
+ *
+ * @code
+ * progress_bar(13);
+ * @endcode
+ *
+ * The information that this thing was to be done 60 times was given at the
+ * initialisation of the progress bar. It is very important that during the use
+ * of the progress bar, nobody prints anything to stdout as it is being used by
+ * the progress bar. At the end you could make a call to progress_bar with the
+ * total amount of work just to make sure that the printout is pretty enough.
+ */
+void progress_bar(long act_time);
+
+
+/* Class to do some profiling
+ *
+ */
+class Timer
+{
+public:
+    ///Start times for all individual timers
+    std::vector<timeval> start_times;
+
+    // General end time
+    timeval end_time;
+
+    // How many times has each tic/toc been called.
+    std::vector<int> counts;
+
+    // Total number of microseconds
+    std::vector< long int> times;
+
+    // Labels
+    std::vector<std::string> tags;
+
+    Timer()
+    {
+        clear();
+    }
+
+    ~Timer()
+    {
+        clear();
+    }
+
+    void clear();
+
+    void initZero();
+
+    int setNew(const std::string tag);
+
+    void tic(int timer);
+
+    int toc(int timer);
+
+    void printTimes(bool doClear);
+};
+
+
+#endif /* TIME_H_ */
diff --git a/src/transformations.cpp b/src/transformations.cpp
new file mode 100644
index 0000000..2a8baca
--- /dev/null
+++ b/src/transformations.cpp
@@ -0,0 +1,223 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *              Sjors H.W. Scheres
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#include "src/transformations.h"
+
+/* Rotation 2D ------------------------------------------------------------- */
+void rotation2DMatrix(double ang, Matrix2D< double > &result, bool homogeneous)
+{
+    double cosine, sine;
+
+    ang = DEG2RAD(ang);
+    cosine = cos(ang);
+    sine = sin(ang);
+
+    if (homogeneous)
+    {
+        if (MAT_XSIZE(result)!=3 || MAT_YSIZE(result)!=3)
+            result.resize(3,3);
+        MAT_ELEM(result,0, 2) = 0;
+        MAT_ELEM(result,1, 2) = 0;
+        MAT_ELEM(result,2, 0) = 0;
+        MAT_ELEM(result,2, 1) = 0;
+        MAT_ELEM(result,2, 2) = 1;
+    }
+    else
+        if (MAT_XSIZE(result)!=2 || MAT_YSIZE(result)!=2)
+            result.resize(2,2);
+
+    MAT_ELEM(result,0, 0) = cosine;
+    MAT_ELEM(result,0, 1) = -sine;
+
+    MAT_ELEM(result,1, 0) = sine;
+    MAT_ELEM(result,1, 1) = cosine;
+}
+
+/* Translation 2D ---------------------------------------------------------- */
+void translation2DMatrix(const Matrix1D<double> &v,
+                         Matrix2D< double > &result)
+{
+    if (VEC_XSIZE(v) != 2)
+        REPORT_ERROR("Translation2D_matrix: vector is not in R2");
+
+    result.initIdentity(3);
+    MAT_ELEM(result,0, 2) = XX(v);
+    MAT_ELEM(result,1, 2) = YY(v);
+}
+
+/* Rotation 3D around the system axes -------------------------------------- */
+void rotation3DMatrix(double ang, char axis, Matrix2D< double > &result,
+                      bool homogeneous)
+{
+    if (homogeneous)
+    {
+        result.initZeros(4,4);
+        MAT_ELEM(result,3, 3) = 1;
+    }
+    else
+        result.initZeros(3,3);
+
+    double cosine, sine;
+    ang = DEG2RAD(ang);
+    cosine = cos(ang);
+    sine = sin(ang);
+
+    result.initZeros();
+    switch (axis)
+    {
+    case 'Z':
+        MAT_ELEM(result,0, 0) = cosine;
+        MAT_ELEM(result,0, 1) = -sine;
+        MAT_ELEM(result,1, 0) = sine;
+        MAT_ELEM(result,1, 1) = cosine;
+        MAT_ELEM(result,2, 2) = 1;
+        break;
+    case 'Y':
+        MAT_ELEM(result,0, 0) = cosine;
+        MAT_ELEM(result,0, 2) = -sine;
+        MAT_ELEM(result,2, 0) = sine;
+        MAT_ELEM(result,2, 2) = cosine;
+        MAT_ELEM(result,1, 1) = 1;
+        break;
+    case 'X':
+        MAT_ELEM(result,1, 1) = cosine;
+        MAT_ELEM(result,1, 2) = -sine;
+        MAT_ELEM(result,2, 1) = sine;
+        MAT_ELEM(result,2, 2) = cosine;
+        MAT_ELEM(result,0, 0) = 1;
+        break;
+    default:
+        REPORT_ERROR("rotation3DMatrix: Unknown axis");
+    }
+}
+
+/* Align a vector with Z axis */
+void alignWithZ(const Matrix1D<double> &axis, Matrix2D<double>& result,
+                bool homogeneous)
+{
+    if (axis.size() != 3)
+        REPORT_ERROR("alignWithZ: Axis is not in R3");
+    if (homogeneous)
+    {
+        result.initZeros(4,4);
+        MAT_ELEM(result,3, 3) = 1;
+    }
+    else
+        result.initZeros(3,3);
+    Matrix1D<double>  Axis(axis);
+    Axis.selfNormalize();
+
+    // Compute length of the projection on YZ plane
+    double proj_mod = sqrt(YY(Axis) * YY(Axis) + ZZ(Axis) * ZZ(Axis));
+    if (proj_mod > XMIPP_EQUAL_ACCURACY)
+    {   // proj_mod!=0
+        // Build Matrix result, which makes the turning axis coincident with Z
+        MAT_ELEM(result,0, 0) = proj_mod;
+        MAT_ELEM(result,0, 1) = -XX(Axis) * YY(Axis) / proj_mod;
+        MAT_ELEM(result,0, 2) = -XX(Axis) * ZZ(Axis) / proj_mod;
+        MAT_ELEM(result,1, 0) = 0;
+        MAT_ELEM(result,1, 1) = ZZ(Axis) / proj_mod;
+        MAT_ELEM(result,1, 2) = -YY(Axis) / proj_mod;
+        MAT_ELEM(result,2, 0) = XX(Axis);
+        MAT_ELEM(result,2, 1) = YY(Axis);
+        MAT_ELEM(result,2, 2) = ZZ(Axis);
+    }
+    else
+    {
+        // I know that the Axis is the X axis
+        MAT_ELEM(result,0, 0) = 0;
+        MAT_ELEM(result,0, 1) = 0;
+        MAT_ELEM(result,0, 2) = -1;
+        MAT_ELEM(result,1, 0) = 0;
+        MAT_ELEM(result,1, 1) = 1;
+        MAT_ELEM(result,1, 2) = 0;
+        MAT_ELEM(result,2, 0) = 1;
+        MAT_ELEM(result,2, 1) = 0;
+        MAT_ELEM(result,2, 2) = 0;
+    }
+}
+
+/* Rotation 3D around any axis -------------------------------------------- */
+void rotation3DMatrix(double ang, const Matrix1D<double> &axis,
+                      Matrix2D<double> &result, bool homogeneous)
+{
+    // Compute a matrix which makes the turning axis coincident with Z
+    // And turn around this axis
+    Matrix2D<double> A,R;
+    alignWithZ(axis,A,homogeneous);
+    rotation3DMatrix(ang, 'Z', R, homogeneous);
+    result=A.transpose() * R * A;
+}
+
+/* Translation 3D ---------------------------------------------------------- */
+void translation3DMatrix(const Matrix1D<double> &v, Matrix2D<double> &result)
+{
+    if (VEC_XSIZE(v) != 3)
+        REPORT_ERROR("Translation3D_matrix: vector is not in R3");
+
+    result.initIdentity(4);
+    MAT_ELEM(result,0, 3) = XX(v);
+    MAT_ELEM(result,1, 3) = YY(v);
+    MAT_ELEM(result,2, 3) = ZZ(v);
+}
+
+/* Scale 3D ---------------------------------------------------------------- */
+void scale3DMatrix(const Matrix1D<double> &sc, Matrix2D<double>& result,
+                   bool homogeneous)
+{
+    if (VEC_XSIZE(sc) != 3)
+        REPORT_ERROR("Scale3D_matrix: vector is not in R3");
+
+    if (homogeneous)
+    {
+        result.initZeros(4,4);
+        MAT_ELEM(result,3, 3) = 1;
+    }
+    else
+        result.initZeros(3,3);
+    MAT_ELEM(result,0, 0) = XX(sc);
+    MAT_ELEM(result,1, 1) = YY(sc);
+    MAT_ELEM(result,2, 2) = ZZ(sc);
+}
diff --git a/src/transformations.h b/src/transformations.h
new file mode 100644
index 0000000..11d37a9
--- /dev/null
+++ b/src/transformations.h
@@ -0,0 +1,960 @@
+/***************************************************************************
+ *
+ * Author: "Sjors H.W. Scheres"
+ * MRC Laboratory of Molecular Biology
+ *
+ * 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.
+ *
+ * This complete copyright notice must be included in any revised version of the
+ * source code. Additional authorship citations may be added, but existing
+ * author citations must be preserved.
+ ***************************************************************************/
+/***************************************************************************
+ *
+ * Authors:     Carlos Oscar S. Sorzano (coss at cnb.csic.es)
+ *              Sjors H.W. Scheres
+ *
+ * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
+ *
+ * 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
+ *
+ *  All comments concerning this program package may be sent to the
+ *  e-mail address 'xmipp at cnb.csic.es'
+ ***************************************************************************/
+
+#ifndef TRANSFORMATIONS_H
+#define TRANSFORMATIONS_H
+
+#include "src/multidim_array.h"
+#include "src/euler.h"
+
+
+#define IS_INV true
+#define IS_NOT_INV false
+#define DONT_WRAP false
+#define WRAP true
+#ifndef DBL_EPSILON
+#define DBL_EPSILON 1e-50
+#endif
+
+/// @defgroup GeometricalTransformations Geometrical transformations
+/// @ingroup DataLibrary
+//@{
+/** Creates a rotational matrix (3x3) for images
+ * @ingroup GeometricalTransformations
+ *
+ * The rotation angle is in degrees.
+ * m must have been already resized to 3x3
+ *
+ * @code
+ *  rotation2DMatrix(60,m);
+ * @endcode
+ */
+void rotation2DMatrix(double ang, Matrix2D< double > &m, bool homogeneous=true);
+
+/** Creates a translational matrix (3x3) for images
+ * @ingroup GeometricalTransformations
+ *
+ * The shift is given as a R2 vector (shift_X, shift_Y). An exception is thrown
+ * if the displacement is not a R2 vector.
+ *
+ * @code
+ * // Displacement of 1 pixel to the right
+ * m = translation2DMatrix(vectorR2(1, 0));
+ * @endcode
+ */
+void translation2DMatrix(const Matrix1D< double > &v, Matrix2D< double > &m);
+
+/** Creates a rotational matrix (4x4) for volumes around system axis
+ * @ingroup GeometricalTransformations
+ *
+ * The rotation angle is in degrees, and the rotational axis is either 'X', 'Y'
+ * or 'Z'. An exception is thrown if the axis given is not one of these.
+ *
+ * The returned matrices are respectively alpha degrees around Z
+ *
+ * @code
+ * [ cos(A) -sin(A)     0   ]
+ * [ sin(A)  cos(A)     0   ]
+ * [   0       0        1   ]
+ * @endcode
+ *
+ * alpha degrees around Y
+ * @code
+ * [ cos(A)    0    -sin(A) ]
+ * [   0       1       0    ]
+ * [ sin(A)    0     cos(A) ]
+ * @endcode
+ *
+ * alpha degrees around X
+ * @code
+ * [   1       0       0    ]
+ * [   0     cos(A) -sin(A) ]
+ * [   0     sin(A)  cos(A) ]
+ * @endcode
+ *
+ * @code
+ * m = rotation3DMatrix(60, 'X');
+ * @endcode
+ */
+void rotation3DMatrix(double ang, char axis, Matrix2D< double > &m,
+		bool homogeneous=true);
+
+/** Creates a rotational matrix (4x4) for volumes around any axis
+ * @ingroup GeometricalTransformations
+ *
+ * The rotation angle is in degrees, and the rotational axis is given as a R3
+ * vector. An exception is thrown if the axis is not a R3 vector. The axis needs
+ * not to be unitary.
+ *
+ * @code
+ * m = rotation3DMatrix(60, vectorR3(1, 1, 1));
+ * @endcode
+ */
+void rotation3DMatrix(double ang, const Matrix1D< double >& axis, Matrix2D< double > &m,
+		bool homogeneous=true);
+
+/** Matrix which transforms the given axis into Z
+ * @ingroup GeometricalTransformations
+ *
+ * A geometrical transformation matrix (4x4) is returned such that the given
+ * axis is rotated until it is aligned with the Z axis. This is very useful in
+ * order to produce rotational matrices, for instance, around any axis.
+ *
+ * @code
+ * Matrix2D< double > A = alignWithZ(axis);
+ * return A.transpose() * rotation3DMatrix(ang, 'Z') * A;
+ * @endcode
+ *
+ * The returned matrix is such that A*axis=Z, where Z and axis are column
+ * vectors.
+ */
+void alignWithZ(const Matrix1D< double >& axis, Matrix2D< double > &m, bool homogeneous=true);
+
+/** Creates a translational matrix (4x4) for volumes
+ * @ingroup GeometricalTransformations
+ *
+ * The shift is given as a R3 vector (shift_X, shift_Y, shift_Z). An exception
+ * is thrown if the displacement is not a R3 vector.
+ *
+ * @code
+ * // Displacement of 2 pixels down
+ * m = translation3DMatrix(vectorR3(0, 0, 2));
+ * @endcode
+ */
+void translation3DMatrix(const Matrix1D< double >& v, Matrix2D< double > &m);
+
+/** Creates a scaling matrix (4x4) for volumes
+ * @ingroup GeometricalTransformations
+ *
+ * The scaling factors for the different axis must be given as a vector. So
+ * that, XX(sc)=scale for X axis, YY(sc)=...
+ */
+void scale3DMatrix(const Matrix1D< double >& sc, Matrix2D< double > &m,
+		bool homogeneous=true);
+
+/** Applies a geometrical transformation.
+ * @ingroup GeometricalTransformations
+ *
+ * Any geometrical transformation defined by the matrix A (double (4x4)!!
+ * ie, in homogeneous R3 coordinates) is applied to the volume V1.
+ * The result is stored in V2 (it cannot be the same as the input volume).
+ * An exception is thrown if the transformation matrix is not 4x4.
+ *
+ * Structure of the transformation matrix: It should have the following
+ * components
+ *
+ * r11 r12 r13 x
+ * r21 r22 r23 y
+ * r31 r32 r33 z
+ * 0   0   0   1
+ *
+ * where (x,y,z) is the translation desired, and Rij are the components of
+ * the rotation matrix R. If you want to apply a scaling factor to the
+ * transformation, then multiply r11, r22 and r33 by it.
+ *
+ * The result volume (with ndim=1) is resized to the same
+ * dimensions as V1 if V2 is empty (0x0) at the beginning, if it
+ * is not, ie, if V2 has got some size then only those values in
+ * the volume are filled, this is very useful for resizing the
+ * volume, then you manually resize the output volume to the
+ * desired size and then call this routine.
+ *
+ * The relationship between the output coordinates and the input ones are
+ *
+ * @code
+ * out = A * in
+ * (x, y, z) = A * (x', y', z')
+ * @endcode
+ *
+ * This function works independently from the logical indexing of each
+ * matrix, it sets the logical center and the physical center of the image
+ * and work with these 2 coordinate spaces. At the end the original logical
+ * indexing of each matrix is kept.
+ *
+ * The procedure followed goes from coordinates in the output volume
+ * to the ones in the input one, so the inverse of the A matrix is
+ * needed. There is a flag telling if the given matrix is already
+ * the inverse one or the normal one. If it is the normal one internally
+ * the matrix is inversed. If you are to do many "rotations" then
+ * some time is spent in inverting the matrix. Normally the matrix is the
+ * normal one.
+ *
+ * There is something else to tell about the geometrical tranformation.
+ * The value of the voxel in the output volume is computed via
+ * bilinear interpolation in the input volume. If any of the voxels
+ * participating in the interpolation falls outside the input volume,
+ * then automatically the corresponding output voxel is set to 0, unless
+ * that the wrap flag has been set to 1. In this case if the voxel
+ * falls out by the right hand then it is "wrapped" and the corresponding
+ * voxel in the left hand is used. The same is appliable to top-bottom.
+ * Usually wrap mode is off. Wrap mode is interesting for translations
+ * but not for rotations, for example.
+ *
+ * The inverse mode and wrapping mode should be taken by default by the
+ * routine, g++ seems to have problems with template functions outside
+ * a class with default parameters. So, I'm sorry, you will have to
+ * put them always. The usual combination is
+ *
+ * applyGeometry(..., IS_NOT_INV, DONT_WRAP).
+ *
+ * Although you can also use the constants IS_INV, or WRAP.
+ *
+ * @code
+ * Matrix2D< double > A(4,4);
+ * A.initIdentity;
+ * applyGeometry(V2, A, V1);
+ * @endcode
+ */
+template<typename T>
+void applyGeometry(const MultidimArray<T>& V1,
+                   MultidimArray<T>& V2,
+                   const Matrix2D< double > A,
+                   bool inv,
+                   bool wrap,
+                   T outside = 0)
+{
+
+    if (&V1 == &V2)
+        REPORT_ERROR("ApplyGeometry: Input array cannot be the same as output array");
+
+    if ( V1.getDim()==2 && ((MAT_XSIZE(A) != 3) || (MAT_YSIZE(A) != 3)) )
+        REPORT_ERROR("ApplyGeometry: 2D transformation matrix is not 3x3");
+
+    if ( V1.getDim()==3 && ((MAT_XSIZE(A) != 4) || (MAT_YSIZE(A) != 4)) )
+        REPORT_ERROR("ApplyGeometry: 3D transformation matrix is not 4x4");
+
+    if (A.isIdentity())
+    {
+        V2=V1;
+        return;
+    }
+
+    if (XSIZE(V1) == 0)
+    {
+        V2.clear();
+        return;
+    }
+
+    Matrix2D<double> Ainv;
+    const Matrix2D<double> * Aptr=&A;
+    if (!inv)
+    {
+        Ainv = A.inv();
+        Aptr=&Ainv;
+    }
+    const Matrix2D<double> &Aref=*Aptr;
+
+    // For scalings the output matrix is resized outside to the final
+    // size instead of being resized inside the routine with the
+    // same size as the input matrix
+    if (XSIZE(V2) == 0)
+        V2.resize(V1);
+
+    if (V1.getDim() == 2)
+    {
+        // 2D transformation
+
+        int m1, n1, m2, n2;
+        double x, y, xp, yp;
+        double minxp, minyp, maxxp, maxyp;
+        int cen_x, cen_y, cen_xp, cen_yp;
+        double wx, wy;
+        int Xdim, Ydim;
+
+        // Find center and limits of image
+        cen_y  = (int)(YSIZE(V2) / 2);
+        cen_x  = (int)(XSIZE(V2) / 2);
+        cen_yp = (int)(YSIZE(V1) / 2);
+        cen_xp = (int)(XSIZE(V1) / 2);
+        minxp  = -cen_xp;
+        minyp  = -cen_yp;
+        maxxp  = XSIZE(V1) - cen_xp - 1;
+        maxyp  = YSIZE(V1) - cen_yp - 1;
+        Xdim   = XSIZE(V1);
+        Ydim   = YSIZE(V1);
+
+        // Now we go from the output image to the input image, ie, for any pixel
+        // in the output image we calculate which are the corresponding ones in
+        // the original image, make an interpolation with them and put this value
+        // at the output pixel
+
+#ifdef DEBUG_APPLYGEO
+        std::cout << "A\n" << Aref << std::endl
+        << "(cen_x ,cen_y )=(" << cen_x  << "," << cen_y  << ")\n"
+        << "(cen_xp,cen_yp)=(" << cen_xp << "," << cen_yp << ")\n"
+        << "(min_xp,min_yp)=(" << minxp  << "," << minyp  << ")\n"
+        << "(max_xp,max_yp)=(" << maxxp  << "," << maxyp  << ")\n";
+#endif
+
+        for (int i = 0; i < YSIZE(V2); i++)
+        {
+            // Calculate position of the beginning of the row in the output image
+            x = -cen_x;
+            y = i - cen_y;
+
+            // Calculate this position in the input image according to the
+            // geometrical transformation
+            // they are related by
+            // coords_output(=x,y) = A * coords_input (=xp,yp)
+            xp = x * Aref(0, 0) + y * Aref(0, 1) + Aref(0, 2);
+            yp = x * Aref(1, 0) + y * Aref(1, 1) + Aref(1, 2);
+
+            for (int j = 0; j < XSIZE(V2); j++)
+            {
+                bool interp;
+                T tmp;
+
+#ifdef DEBUG_APPLYGEO
+
+                std::cout << "Computing (" << i << "," << j << ")\n";
+                std::cout << "   (y, x) =(" << y << "," << x << ")\n"
+                << "   before wrapping (y',x')=(" << yp << "," << xp << ") "
+                << std::endl;
+#endif
+                // If the point is outside the image, apply a periodic extension
+                // of the image, what exits by one side enters by the other
+                interp = true;
+                if (wrap)
+                {
+                    if (xp < minxp - XMIPP_EQUAL_ACCURACY ||
+                        xp > maxxp + XMIPP_EQUAL_ACCURACY)
+                        xp = realWRAP(xp, minxp - 0.5, maxxp + 0.5);
+
+                    if (yp < minyp - XMIPP_EQUAL_ACCURACY ||
+                        yp > maxyp + XMIPP_EQUAL_ACCURACY)
+
+                        yp = realWRAP(yp, minyp - 0.5, maxyp + 0.5);
+                }
+                else
+                {
+                    if (xp < minxp - XMIPP_EQUAL_ACCURACY ||
+                        xp > maxxp + XMIPP_EQUAL_ACCURACY)
+                        interp = false;
+
+                    if (yp < minyp - XMIPP_EQUAL_ACCURACY ||
+                        yp > maxyp + XMIPP_EQUAL_ACCURACY)
+                        interp = false;
+                }
+
+#ifdef DEBUG_APPLYGEO
+                std::cout << "   after wrapping (y',x')=(" << yp << "," << xp << ") "
+                << std::endl;
+                std::cout << "   Interp = " << interp << std::endl;
+                // The following line sounds dangerous...
+                //x++;
+#endif
+
+                if (interp)
+                {
+                        // Linear interpolation
+
+                        // Calculate the integer position in input image, be careful
+                        // that it is not the nearest but the one at the top left corner
+                        // of the interpolation square. Ie, (0.7,0.7) would give (0,0)
+                        // Calculate also weights for point m1+1,n1+1
+                        wx = xp + cen_xp;
+                        m1 = (int) wx;
+                        wx = wx - m1;
+                        m2 = m1 + 1;
+                        wy = yp + cen_yp;
+                        n1 = (int) wy;
+                        wy = wy - n1;
+                        n2 = n1 + 1;
+
+                        // m2 and n2 can be out by 1 so wrap must be check here
+                        if (wrap)
+                        {
+                            if (m2 >= Xdim)
+                                m2 = 0;
+                            if (n2 >= Ydim)
+                                n2 = 0;
+                        }
+
+#ifdef DEBUG_APPLYGEO
+                        std::cout << "   From (" << n1 << "," << m1 << ") and ("
+                        << n2 << "," << m2 << ")\n";
+                        std::cout << "   wx= " << wx << " wy= " << wy << std::endl;
+#endif
+
+                        // Perform interpolation
+                        // if wx == 0 means that the rightest point is useless for this
+                        // interpolation, and even it might not be defined if m1=xdim-1
+                        // The same can be said for wy.
+                        tmp  = (T)((1 - wy) * (1 - wx) * DIRECT_A2D_ELEM(V1, n1, m1));
+
+                        if (wx != 0 && m2 < V1.xdim)
+                            tmp += (T)((1 - wy) * wx * DIRECT_A2D_ELEM(V1, n1, m2));
+
+                        if (wy != 0 && n2 < V1.ydim)
+                        {
+                            tmp += (T)(wy * (1 - wx) * DIRECT_A2D_ELEM(V1, n2, m1));
+
+                            if (wx != 0 && m2 < V1.xdim)
+                                tmp += (T)(wy * wx * DIRECT_A2D_ELEM(V1, n2, m2));
+                        }
+
+                        dAij(V2, i, j) = tmp;
+#ifdef DEBUG_APPYGEO
+                    std::cout << "   val= " << dAij(V2, i, j) << std::endl;
+#endif
+
+                } // if interp
+                else
+                	dAij(V2, i, j) = outside;
+
+                // Compute new point inside input image
+                xp += Aref(0, 0);
+                yp += Aref(1, 0);
+            }
+        }
+    }
+    else
+    {
+        // 3D transformation
+
+        int m1, n1, o1, m2, n2, o2;
+        double x, y, z, xp, yp, zp;
+        double minxp, minyp, maxxp, maxyp, minzp, maxzp;
+        int cen_x, cen_y, cen_z, cen_xp, cen_yp, cen_zp;
+        double wx, wy, wz;
+
+        // Find center of MultidimArray
+        cen_z = (int)(V2.zdim / 2);
+        cen_y = (int)(V2.ydim / 2);
+        cen_x = (int)(V2.xdim / 2);
+        cen_zp = (int)(V1.zdim / 2);
+        cen_yp = (int)(V1.ydim / 2);
+        cen_xp = (int)(V1.xdim / 2);
+        minxp = -cen_xp;
+        minyp = -cen_yp;
+        minzp = -cen_zp;
+        maxxp = V1.xdim - cen_xp - 1;
+        maxyp = V1.ydim - cen_yp - 1;
+        maxzp = V1.zdim - cen_zp - 1;
+
+#ifdef DEBUG
+
+        std::cout << "Geometry 2 center=("
+        << cen_z  << "," << cen_y  << "," << cen_x  << ")\n"
+        << "Geometry 1 center=("
+        << cen_zp << "," << cen_yp << "," << cen_xp << ")\n"
+        << "           min=("
+        << minzp  << "," << minyp  << "," << minxp  << ")\n"
+        << "           max=("
+        << maxzp  << "," << maxyp  << "," << maxxp  << ")\n"
+        ;
+#endif
+
+        // Now we go from the output MultidimArray to the input MultidimArray, ie, for any
+        // voxel in the output MultidimArray we calculate which are the corresponding
+        // ones in the original MultidimArray, make an interpolation with them and put
+        // this value at the output voxel
+
+        // V2 is not initialised to 0 because all its pixels are rewritten
+        for (int k = 0; k < V2.zdim; k++)
+            for (int i = 0; i < V2.ydim; i++)
+            {
+                // Calculate position of the beginning of the row in the output
+                // MultidimArray
+                x = -cen_x;
+                y = i - cen_y;
+                z = k - cen_z;
+
+                // Calculate this position in the input image according to the
+                // geometrical transformation they are related by
+                // coords_output(=x,y) = A * coords_input (=xp,yp)
+                xp = x * Aref(0, 0) + y * Aref(0, 1) + z * Aref(0, 2) + Aref(0, 3);
+                yp = x * Aref(1, 0) + y * Aref(1, 1) + z * Aref(1, 2) + Aref(1, 3);
+                zp = x * Aref(2, 0) + y * Aref(2, 1) + z * Aref(2, 2) + Aref(2, 3);
+
+                for (int j = 0; j < V2.xdim; j++)
+                {
+                    bool interp;
+                    T tmp;
+
+#ifdef DEBUG
+
+                    bool show_debug = false;
+                    if ((i == 0 && j == 0 && k == 0) ||
+                        (i == V2.ydim - 1 && j == V2.xdim - 1 && k == V2.zdim - 1))
+                        show_debug = true;
+
+                    if (show_debug)
+                        std::cout << "(x,y,z)-->(xp,yp,zp)= "
+                        << "(" << x  << "," << y  << "," << z  << ") "
+                        << "(" << xp << "," << yp << "," << zp << ")\n";
+#endif
+
+                    // If the point is outside the volume, apply a periodic
+                    // extension of the volume, what exits by one side enters by
+                    // the other
+                    interp  = true;
+                    if (wrap)
+                    {
+                        if (xp < minxp - XMIPP_EQUAL_ACCURACY ||
+                            xp > maxxp + XMIPP_EQUAL_ACCURACY)
+                            xp = realWRAP(xp, minxp - 0.5, maxxp + 0.5);
+
+                        if (yp < minyp - XMIPP_EQUAL_ACCURACY ||
+                            yp > maxyp + XMIPP_EQUAL_ACCURACY)
+                            yp = realWRAP(yp, minyp - 0.5, maxyp + 0.5);
+
+                        if (zp < minzp - XMIPP_EQUAL_ACCURACY ||
+                            zp > maxzp + XMIPP_EQUAL_ACCURACY)
+                            zp = realWRAP(zp, minzp - 0.5, maxzp + 0.5);
+                    }
+                    else
+                    {
+                        if (xp < minxp - XMIPP_EQUAL_ACCURACY ||
+                            xp > maxxp + XMIPP_EQUAL_ACCURACY)
+                            interp = false;
+
+                        if (yp < minyp - XMIPP_EQUAL_ACCURACY ||
+                            yp > maxyp + XMIPP_EQUAL_ACCURACY)
+                            interp = false;
+
+                        if (zp < minzp - XMIPP_EQUAL_ACCURACY ||
+                            zp > maxzp + XMIPP_EQUAL_ACCURACY)
+                            interp = false;
+                    }
+
+                    if (interp)
+                    {
+
+                            // Linear interpolation
+
+                            // Calculate the integer position in input volume, be
+                            // careful that it is not the nearest but the one at the
+                            // top left corner of the interpolation square. Ie,
+                            // (0.7,0.7) would give (0,0)
+                            // Calculate also weights for point m1+1,n1+1
+                            wx = xp + cen_xp;
+                            m1 = (int) wx;
+                            wx = wx - m1;
+                            m2 = m1 + 1;
+                            wy = yp + cen_yp;
+                            n1 = (int) wy;
+                            wy = wy - n1;
+                            n2 = n1 + 1;
+                            wz = zp + cen_zp;
+                            o1 = (int) wz;
+                            wz = wz - o1;
+                            o2 = o1 + 1;
+
+#ifdef DEBUG
+
+                            if (show_debug)
+                            {
+                                std::cout << "After wrapping(xp,yp,zp)= "
+                                << "(" << xp << "," << yp << "," << zp << ")\n";
+                                std::cout << "(m1,n1,o1)-->(m2,n2,o2)="
+                                << "(" << m1 << "," << n1 << "," << o1 << ") "
+                                << "(" << m2 << "," << n2 << "," << o2 << ")\n";
+                                std::cout << "(wx,wy,wz)="
+                                << "(" << wx << "," << wy << "," << wz << ")\n";
+                            }
+#endif
+
+                            // Perform interpolation
+                            // if wx == 0 means that the rightest point is useless for
+                            // this interpolation, and even it might not be defined if
+                            // m1=xdim-1
+                            // The same can be said for wy.
+                            tmp  = (T)((1 - wz) * (1 - wy) * (1 - wx) * DIRECT_A3D_ELEM(V1, o1, n1, m1));
+
+                            if (wx != 0 && m2 < V1.xdim)
+                                tmp += (T)((1 - wz) * (1 - wy) * wx * DIRECT_A3D_ELEM(V1, o1, n1, m2));
+
+                            if (wy != 0 && n2 < V1.ydim)
+                            {
+                                tmp += (T)((1 - wz) * wy * (1 - wx) * DIRECT_A3D_ELEM(V1, o1, n2, m1));
+                                if (wx != 0 && m2 < V1.xdim)
+                                    tmp += (T)((1 - wz) * wy * wx * DIRECT_A3D_ELEM(V1, o1, n2, m2));
+                            }
+
+                            if (wz != 0 && o2 < V1.zdim)
+                            {
+                                tmp += (T)(wz * (1 - wy) * (1 - wx) * DIRECT_A3D_ELEM(V1, o2, n1, m1));
+                                if (wx != 0 && m2 < V1.xdim)
+                                    tmp += (T)(wz * (1 - wy) * wx * DIRECT_A3D_ELEM(V1, o2, n1, m2));
+                                if (wy != 0 && n2 < V1.ydim)
+                                {
+                                    tmp += (T)(wz * wy * (1 - wx) * DIRECT_A3D_ELEM(V1, o2, n2, m1));
+                                    if (wx != 0 && m2 < V1.xdim)
+                                        tmp += (T)(wz * wy * wx * DIRECT_A3D_ELEM(V1, o2, n2, m2));
+                                }
+                            }
+
+#ifdef DEBUG
+                            if (show_debug)
+                                std::cout <<
+                                "tmp1=" << DIRECT_A3D_ELEM(V1, o1, n1, m1) << " "
+                                << (T)((1 - wz) *(1 - wy) *(1 - wx) * DIRECT_A3D_ELEM(V1, o1, n1, m1))
+                                << std::endl <<
+                                "tmp2=" << DIRECT_A3D_ELEM(V1, o1, n1, m2) << " "
+                                << (T)((1 - wz) *(1 - wy) * wx * DIRECT_A3D_ELEM(V1, o1, n1, m2))
+                                << std::endl <<
+                                "tmp3=" << DIRECT_A3D_ELEM(V1, o1, n2, m1) << " "
+                                << (T)((1 - wz) * wy *(1 - wx) * DIRECT_A3D_ELEM(V1, o1, n2, m1))
+                                << std::endl <<
+                                "tmp4=" << DIRECT_A3D_ELEM(V1, o1, n2, m2) << " "
+                                << (T)((1 - wz) * wy * wx * DIRECT_A3D_ELEM(V1, o2, n1, m1))
+                                << std::endl <<
+                                "tmp6=" << DIRECT_A3D_ELEM(V1, o2, n1, m2) << " "
+                                << (T)(wz * (1 - wy) * wx * DIRECT_A3D_ELEM(V1, o2, n1, m2))
+                                << std::endl <<
+                                "tmp7=" << DIRECT_A3D_ELEM(V1, o2, n2, m1) << " "
+                                << (T)(wz * wy *(1 - wx) * DIRECT_A3D_ELEM(V1, o2, n2, m1))
+                                << std::endl <<
+                                "tmp8=" << DIRECT_A3D_ELEM(V1, o2, n2, m2) << " "
+                                << (T)(wz * wy * wx * DIRECT_A3D_ELEM(V1, o2, n2, m2))
+                                << std::endl <<
+                                "tmp= " << tmp << std::endl;
+#endif
+
+                            dAkij(V2 , k, i, j) = tmp;
+                    }
+                    else
+                        dAkij(V2, k, i, j) = outside;
+
+                    // Compute new point inside input image
+                    xp += Aref(0, 0);
+                    yp += Aref(1, 0);
+                    zp += Aref(2, 0);
+                }
+            }
+    }
+}
+
+/** Applies a geometrical transformation and overwrites the input matrix.
+ * @ingroup GeometricalTransformations
+ *
+ * The same as the previous function, but input array is overwritten
+ */
+template<typename T>
+void selfApplyGeometry(MultidimArray<T>& V1,
+                       const Matrix2D< double > A, bool inv,
+                       bool wrap, T outside = 0)
+{
+    MultidimArray<T> aux = V1;
+    V1.initZeros();
+    applyGeometry(aux, V1, A, inv, wrap, outside);
+}
+
+/** Rotate an array around a given system axis.
+ * @ingroup GeometricalTransformations
+ *
+ * The rotation angle is in degrees, and the rotational axis is either
+ * 'X', 'Y' or 'Z' for 3D arrays and only 'Z' for 2D arrays. An
+ * exception is thrown if the axis given is not one of these.
+ *
+ * @code
+ * rotate(Vin, Vout, 60);
+ * @endcode
+ */
+template<typename T>
+void rotate(const MultidimArray<T>& V1,
+            MultidimArray<T>& V2,
+            double ang, char axis = 'Z',
+            bool wrap = DONT_WRAP, T outside = 0)
+{
+    Matrix2D< double > tmp;
+    if (V1.getDim()==2)
+    {
+        rotation2DMatrix(ang,tmp);
+    }
+    else if (V1.getDim()==3)
+    {
+        rotation3DMatrix(ang, axis, tmp);
+    }
+    else
+        REPORT_ERROR("rotate ERROR: rotate only valid for 2D or 3D arrays");
+
+    applyGeometry(V1, V2, tmp, IS_NOT_INV, wrap, outside);
+}
+
+/** Rotate an array around a given system axis.
+ * @ingroup GeometricalTransformations
+ *
+ * The same as the previous function, but input array is overwritten
+ */
+template<typename T>
+void selfRotate(MultidimArray<T>& V1,
+                double ang, char axis = 'Z',
+                bool wrap = DONT_WRAP, T outside = 0)
+{
+    MultidimArray<T> aux = V1;
+    rotate(aux, V1, ang, axis, wrap, outside);
+}
+
+/** Translate a array.
+ * @ingroup GeometricalTransformations
+ *
+ * The shift is given as a R2 or R3 vector (shift_X, shift_Y, shift_Z) for 2D and 3D arrays, respectively.
+ * An exception is thrown if the displacement is not a R3 vector.
+ *
+ * @code
+ * // Displacement of 2 pixels down
+ * V2 = V1.translate(vectorR3(0, 0, 2));
+ * @endcode
+ */
+template<typename T>
+void translate(const MultidimArray<T> &V1,
+               MultidimArray<T> &V2,
+               const Matrix1D< double >& v,
+               bool wrap = WRAP, T outside = 0)
+{
+    Matrix2D< double > tmp;
+    if (V1.getDim()==2)
+        translation2DMatrix(v, tmp);
+    else if (V1.getDim()==3)
+        translation3DMatrix(v, tmp);
+    else
+        REPORT_ERROR("translate ERROR: translate only valid for 2D or 3D arrays");
+
+    applyGeometry(V1, V2, tmp, IS_NOT_INV, wrap, outside);
+}
+
+/** Translate an array.
+ * @ingroup GeometricalTransformations
+ *
+ * The same as the previous function, but input array is overwritten
+ */
+template<typename T>
+void selfTranslate(MultidimArray<T>& V1,
+                   const Matrix1D< double >& v,
+                   bool wrap = WRAP, T outside = 0)
+{
+    MultidimArray<T> aux = V1;
+    translate(aux, V1, v, wrap, outside);
+}
+
+/** Translate center of mass to center
+ * @ingroup GeometricalTransformations
+ *
+ * If the input has very high values, it is better to rescale it to be
+ * between 0 and 1.
+ */
+template<typename T>
+void translateCenterOfMassToCenter(const MultidimArray<T> &V1,
+                                   MultidimArray<T> &V2,
+                                   bool wrap = WRAP)
+{
+    V2 = V1;
+    V2.setXmippOrigin();
+    Matrix1D< double > center;
+    V2.centerOfMass(center);
+    center *= -1;
+    translate(V1, V2, center, wrap, 0.);
+}
+
+/** Translate center of mass to center
+ * @ingroup GeometricalTransformations
+ *
+ * The same as the previous function, but input array is overwritten
+ */
+template<typename T>
+void selfTranslateCenterOfMassToCenter(MultidimArray<T> &V1,
+                                       bool wrap = WRAP)
+{
+    MultidimArray<T> aux = V1;
+    translateCenterOfMassToCenter(aux, V1, wrap);
+}
+
+/** Scales to a new size.
+ * @ingroup GeometricalTransformations
+ *
+ * The volume is scaled (resampled) to fill a new size. It is not the
+ * same as "window" in this same class. The size can be larger or smaller
+ * than the actual one.
+ *
+ * @code
+ * scaleToSize(Vin, Vout, 128, 128, 128);
+ * @endcode
+ */
+template<typename T>
+void scaleToSize(const MultidimArray<T> &V1,
+                 MultidimArray<T> &V2,
+                 int Xdim, int Ydim, int Zdim = 1)
+{
+
+    Matrix2D< double > tmp;
+    if (V1.getDim()==2)
+    {
+        tmp.initIdentity(3);
+        tmp(0, 0) = (double) Xdim / (double) XSIZE(V1);
+        tmp(1, 1) = (double) Ydim / (double) YSIZE(V1);
+        V2.resize(1, 1, Ydim, Xdim);
+    }
+    else if (V1.getDim()==3)
+    {
+        tmp.initIdentity(4);
+        tmp(0, 0) = (double) Xdim / (double) XSIZE(V1);
+        tmp(1, 1) = (double) Ydim / (double) YSIZE(V1);
+        tmp(2, 2) = (double) Zdim / (double) ZSIZE(V1);
+        V2.resize(1, Zdim, Ydim, Xdim);
+    }
+    else
+        REPORT_ERROR("scaleToSize ERROR: scaleToSize only valid for 2D or 3D arrays");
+
+    applyGeometry(V1, V2, tmp, IS_NOT_INV, WRAP, (T)0);
+}
+
+/** Scales to a new size.
+ * @ingroup GeometricalTransformations
+ *
+ * The same as the previous function, but input array is overwritten
+ */
+template<typename T>
+void selfScaleToSize(MultidimArray<T> &V1,
+                     int Xdim, int Ydim, int Zdim = 1)
+{
+    MultidimArray<T> aux = V1;
+    scaleToSize(aux, V1, Xdim, Ydim, Zdim);
+}
+
+/** Does a radial average of a 2D/3D image, around the voxel where is the origin.
+ * @ingroup GeometricalTransformations
+ *
+ * A vector radial_mean is returned where:
+ * - the first element is the mean of the voxels whose
+ *   distance to the origin is (0-1),
+ * - the second element is the mean of the voxels
+ *   whose distance to the origin is (1-2)
+ * - and so on.
+ *
+ * A second vector radial_count is returned containing the number of voxels
+ * over which each radial average was calculated.
+ *
+ * Sjors nov2003: if rounding=true, element=round(distance);
+ * - so the first element is the mean of the voxels whose distance to the
+ *   origin is (0.5-1.5),
+ * - the second element is the mean of the voxels whose distance to the origin
+ *   is (1.5-2.5)
+ * - and so on.
+ */
+template<typename T>
+void radialAverage(const MultidimArray< T >& m,
+                   Matrix1D< int >& center_of_rot,
+                   MultidimArray< T >& radial_mean,
+                   MultidimArray< int >& radial_count,
+                   const bool& rounding = false)
+{
+    Matrix1D< double > idx(3);
+
+    // If center_of_rot was written for 2D image
+    if (center_of_rot.size() < 3)
+        center_of_rot.resize(3);
+
+    // First determine the maximum distance that one should expect, to set the
+    // dimension of the radial average vector
+    MultidimArray< int > distances(8);
+
+    double z = STARTINGZ(m) - ZZ(center_of_rot);
+    double y = STARTINGY(m) - YY(center_of_rot);
+    double x = STARTINGX(m) - XX(center_of_rot);
+
+    distances(0) = (int) floor(sqrt(x * x + y * y + z * z));
+    x = FINISHINGX(m) - XX(center_of_rot);
+
+    distances(1) = (int) floor(sqrt(x * x + y * y + z * z));
+    y = FINISHINGY(m) - YY(center_of_rot);
+
+    distances(2) = (int) floor(sqrt(x * x + y * y + z * z));
+    x = STARTINGX(m) - XX(center_of_rot);
+
+    distances(3) = (int) floor(sqrt(x * x + y * y + z * z));
+    z = FINISHINGZ(m) - ZZ(center_of_rot);
+
+    distances(4) = (int) floor(sqrt(x * x + y * y + z * z));
+    x = FINISHINGX(m) - XX(center_of_rot);
+
+    distances(5) = (int) floor(sqrt(x * x + y * y + z * z));
+    y = STARTINGY(m) - YY(center_of_rot);
+
+    distances(6) = (int) floor(sqrt(x * x + y * y + z * z));
+    x = STARTINGX(m) - XX(center_of_rot);
+
+    distances(7) = (int) floor(sqrt(x * x + y * y + z * z));
+
+    int dim = (int) CEIL(distances.computeMax()) + 1;
+    if (rounding)
+        dim++;
+
+    // Define the vectors
+    radial_mean.resize(dim);
+    radial_mean.initZeros();
+    radial_count.resize(dim);
+    radial_count.initZeros();
+
+    // Perform the radial sum and count pixels that contribute to every
+    // distance
+    FOR_ALL_ELEMENTS_IN_ARRAY3D(m)
+    {
+        ZZ(idx) = k - ZZ(center_of_rot);
+        YY(idx) = i - YY(center_of_rot);
+        XX(idx) = j - XX(center_of_rot);
+
+        // Determine distance to the center
+        int distance;
+        if (rounding)
+            distance = (int) ROUND(idx.module());
+        else
+            distance = (int) floor(idx.module());
+
+        // Sum te value to the pixels with the same distance
+        radial_mean(distance) += A3D_ELEM(m, k, i, j);
+
+        // Count the pixel
+        radial_count(distance)++;
+    }
+
+    // Perform the mean
+    FOR_ALL_ELEMENTS_IN_ARRAY1D(radial_mean)
+    radial_mean(i) /= (T) radial_count(i);
+}
+
+//@}
+#endif

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



More information about the debian-med-commit mailing list