diff --git a/TODO b/TODO
index 9aeb738485dc723e09bd5f297fdbbd3ca9ddb164..0e607aecfaaf7f92032cb2fd3f9c9b849b64a1f2 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,6 @@
 ==== BUGS ====
 
-ctest -j4 fails
+ctest -j4 fails [not confirmed on l2, aug17]
 
 ==== New functionality ====
 
@@ -13,7 +13,7 @@ convolution with function
 - with TOFTOF model
 
 
-==== Improve extant functcionality ====
+==== Improve extant functionality ====
 
 coord name algebra
 
@@ -29,8 +29,6 @@ dp: output for #spec>1 is obfuscated
 
 fs: for curve-calling-external-program (cc ecr or similar)
 
-gp: version 'gp!' <filename> ?
-
 mfj: remove redundant doc lines
 
 oi: wenn mehrere Files mit rank=2, automatisch in einen File packen
@@ -41,13 +39,11 @@ oi: wenn mehrere Files mit rank=2, automatisch in einen File packen
 Register all commands;
 transform within-command dialogs into command options
 
-
 (this replaces the following "dialog generics":)
   - restore ask callback help for lists (prompt for list, not for string)
   - restore help on "?" (e.g. expression help for 'md')
   - default for plot range
 
-
 refactor func+op registration so that registered object can be const
 (assemble typed function list prior to registration)
 
@@ -87,7 +83,6 @@ history:
 - save every input at once (from history to logging ...)
 
 
-
 ==== WISHLIST ====
 
 customization
@@ -99,16 +94,6 @@ allow ad-hoc addition of fit functions
 (plugin ? distinguish from opr-functions ?)
 - plot accessible Q-E-space
 
-distribution
-- include wupscat, wupsbb
-- rewrite wupscat in bash instead of ruby
-
-
-==== PROJECTS ====
-
-
-2d plots using pm3d # was ist das ?
-
 
 ==== WAITING FOR CLUE ====
 
diff --git a/arch/gcode/c3.ps b/arch/gcode/c3.ps
new file mode 100644
index 0000000000000000000000000000000000000000..a67bf6f174565ae9d938a1e7227c826d09afe3cf
--- /dev/null
+++ b/arch/gcode/c3.ps
@@ -0,0 +1,14 @@
+WuGdict11a begin
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Next frame: customizable plot setup
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%  Clear frame:
+
+Resets
+BoxBackground
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Mark "ecu", end of the customization section
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/pub/share/g3.ps b/arch/gcode/g3.ps
similarity index 98%
rename from pub/share/g3.ps
rename to arch/gcode/g3.ps
index a4737749391c18b1fa035a8fd75308908345766a..768bdd2ce216fccebd780930542c818f361cec42 100644
--- a/pub/share/g3.ps
+++ b/arch/gcode/g3.ps
@@ -11,7 +11,7 @@ iFrame 0 eq
 10 dup autolabel defsiz
 1 dup geld stdred
 2 -11 setnewpage newpage
-1 1 13 -14 setpagegrid
+2 4 13 -14 setpagegrid
 
 2 8 24 abcset % usage: {(text)} abc
 /EndFrame { nextFrame end } def
diff --git a/pub/share/wups11a.ps b/arch/gcode/wups11a.ps
similarity index 97%
rename from pub/share/wups11a.ps
rename to arch/gcode/wups11a.ps
index ea61fb86749d98700e8a1ed82cf48ae3e262d74d..4897bf5f685b8544619c08fcc120643e42dfad80 100644
--- a/pub/share/wups11a.ps
+++ b/arch/gcode/wups11a.ps
@@ -171,6 +171,20 @@ WuGdict11a begin
       wyd
       } bind def
    } def
+/hSetCoord { % log min max | -
+   /whmax x def
+   /whmin x def
+   /whlog x 0 eq not def
+   % prepare conversion world coord -> frame coord
+   /whdel whmax whmin whlog { div log } { sub } ifelse def
+   /whd { % dx(world) | dx(frame)
+      whlog { log } if whdel div 10 mul
+      } bind def
+   /wh { % x(world) | x(frame)
+      whmin whlog { div } { sub } ifelse
+      whd
+      } bind def
+   } def
 
 % pair conversion
 /wxy { % x,y(world) -> x,y(frame)
@@ -391,7 +405,7 @@ WuGdict11a begin
       /Encoding MyEncoding def
       currentdict
       end
-   definefont % define as NewFont
+   definefont pop % define as NewFont
    } def
 
 % we assume that image scripts are Latin1 encoded
@@ -1244,6 +1258,16 @@ WuGdict11a begin
 } def
 
 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  2D plots                                                                 %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/t2d {
+    icCol
+    { fill } execRectangle3
+    black
+} def
+
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%  List                                                                     %%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1413,7 +1437,21 @@ WuGdict11a begin
          grestore
       grestore
    } def
-/execRectangle2 { % xl xh yl yh {proc} | -
+/execRectangle3 { % xl xh yl yh {proc} | -
+   5 1 roll
+   gsave
+   ym /qqyh x def
+   ym /qqyl x def
+   xm /qqxh x def
+   xm /qqxl x def
+   np
+   qqxl qqyl mv
+   qqxh qqyl li
+   qqxh qqyh li
+   qqxl qqyh li
+   cp exec grestore
+   } def
+/execRectangle2 { % xl xh yl yh {proc} | - OBSOLETE, BOGUS (duplicate xm|ym operations)
    5 1 roll
    gsave
    ym /qqyh x def
@@ -1605,14 +1643,7 @@ WuGdict11a begin
           supsc (-1) endsc (\)) showif } bind def
 /inGHzr { showif (\(GHz) (-1) sp (\)) showif } def
 
-%% home-made Angstr is obsolete; use \305 (more reliable than Ã…)
-/Angstr {
-   showif
-   (A) .5 1.23 {
-      currentpoint fontheight .1 mul setline np
-      fontheight .14 mul 0 360 arc st ()
-   } build
-} bind def
+/Angstr { showif (\305) showif } bind def
 /Angr { showif (\305) supsc (-1) endsc } bind def
 /inAngr { showif (\() Angr (\)) showif } bind def
 /Angrr { showif (\305) supsc (-2) endsc } bind def
diff --git a/distrib/core/HOWTO b/distrib/core/HOWTO
index 2a9204550f8b5268a12da253439ab9817e36b3a7..470c97f4ea7a4c2251d12c312b5ae2a156b742c3 100755
--- a/distrib/core/HOWTO
+++ b/distrib/core/HOWTO
@@ -1,17 +1,13 @@
 cd /G/f2
-
-### merge devel into master
-# git rebase -i HEAD~99 # correct commit messages; do not go past last tag or branch from master
 git checkout master
 git pull origin master
 git merge --no-ff devel
-git push origin master
 
-### prepare
+git push origin master
 vi pub/CMakeLists.txt # increment version number, remove "post-"
+
 vi pub/CHANGELOG
 
-### purge
 rm -r /G/f2/pub/build
 rm -r /G/f2/pub/qtbuild
 cd /G/f2/pub
@@ -19,18 +15,16 @@ rm *~
 rm */*~
 rm */*/*~
 rm */Doxyfile.bak
-
-### pack
 export V=2.  # 2.<major>.<minor><bugfix>
+
 export A=frida$V
 cd /tmp
 rm $A
 slink /G/f2/pub $A
 tar czvfh ~/data/tgz/$A.tgz $A/*
 dl ~/data/tgz/frida2.* # CHECK size
-rm $A
 
-### update git
+rm $A
 cd /G/f2
 kcom -m "This is release $V"
 kush
@@ -38,10 +32,10 @@ k tag v$V # Yes! Our IT wants version tags to start with "v".
 # to delete erroneous tag: git tag -d $X; git push origin :refs/tags/$X
 kush --tags
 
-### upload tgz
-
 ssh wuttke@a mv /www/apps/src/frida/frida2.* /www/apps/src/frida/old/
+
 scp ~/data/tgz/$A.tgz wuttke@a:/www/apps/src/frida/
+
 scp /G/f2/pub/CHANGELOG wuttke@a:/www/apps/src/frida/frida2-CHANGELOG
 
 ### advertise
@@ -54,16 +48,15 @@ git checkout devel
 git rebase master
 cd /G/f2/pub
 vi CMakeLists.txt # version becomes "post-<release>"
+
 kcom -m "Starting post-$V"
 kush
-
-### rebuild
 cd /G/f2/pub
 mkdir build
 cd build
 cmake ..
 m -j7
-ctest
+ctest -j7
 mi
 
 ### upload man page (if changed)
diff --git a/pub/CHANGELOG b/pub/CHANGELOG
index eb061f0e28b779f3278a664351bcde31476fb644..bc6ee9e62591ae88f3de2340ba0a4077781e1510 100644
--- a/pub/CHANGELOG
+++ b/pub/CHANGELOG
@@ -1,3 +1,62 @@
+- use plot.Y.force in 2d plotting
+- use wx, wy, wh in setting ticks and tacks for easier editing of PS file
+- correct ticks and tacks for small log range
+- correct handling of Z in oixy
+- pertinent error message when calling 'a' before 'p'
+
+Release 2.4.0b of 21apr17:
+
+- Modified functionality:
+  - sqrt, ln, lg return NaN outside their definition range
+  - sqrt0, ln0, lg0 return 0 outside the definition range of the standard functions
+- Bug fix:
+  - detection of dy==0 for fit weighing was inverted
+
+Release 2.4.0a of 24mar17:
+
+- Consolidated graphics definitions wups17a
+- Practicable 2D plotting
+- Bug fixes:
+  - Reactivated possibility to overwrite when saving files (now fs! instead of fso)
+  - Correct handling of i-dependent indices (-> test oxy_idep)
+- Code cleanup:
+  - Decoupled plot window administration from the actual plotting
+  - Removed save_y08
+  - Hard-coded debug facility in node.cpp
+
+Release 2.3.6c of 17mar17:
+
+- New command dv to display list of defined variables
+- Experimental code for 2d plots
+
+Release 2.3.6b of 14mar17:
+
+- Replaced experimental/filesystem by boost/filesystem for compilation under gcc4.8
+
+Release 2.3.6a of 13mar17:
+
+- Bug fixes:
+  - Restored ability to load files from outside the current working directory
+  - Correct handling of dy (or absence thereof) in ftv
+- New functionality:
+  - Frida main program now has command-line options -b, -h, --version
+  - Command crp to restrict plot range
+  - New integral operations firstwith, lastwith
+- Improved functionality:
+  - In binning (mpa, msa), computation of sampling error is now optional
+  - Commands gp, gf, gp!, gf!, gfa to create/overwrite/append graphic file
+  - Integral operations now return integers when appropriate
+  - Cleaner implementation of refined curve plotting
+- Code cleanup:
+  - fname_divide replaced by functions from std::experimental::filesystem
+
+Release 2.3.5a of 01feb17:
+
+- CMake machinery now uses variables like ${library_name}_LIBRARY
+- Renamed libfrida -> libfridacore, libtrivia -> libfridatrivia
+- Fully relying on implicit library dependencies (frida -> libfridacore -> libfridatrivia -> GSL)
+- Ensure termination of functional tests by including the one-line script "exit(1)"
+
 Release 2.3.4d of 28jan17:
 
 - mpgi,mpgr now using NOlo::j2j for spectrum correspondence
diff --git a/pub/CMakeLists.txt b/pub/CMakeLists.txt
index 775fe7744ef47d16fa4b2c92ef3c9f88ef75c6e6..332629dbc8077824b83bd4ecc4feb98c5c37e5df 100644
--- a/pub/CMakeLists.txt
+++ b/pub/CMakeLists.txt
@@ -8,7 +8,7 @@ set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
 
 project(Frida)
 
-set(Frida_VERSION 2.3.4d)
+set(Frida_VERSION post-2.4.0b)
 
 include(CTest) # equivalent to "enable_testing() ???
 add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND}) # => 'make check' is an alias for 'ctest'
@@ -22,10 +22,12 @@ configure_file(${CMAKE_SOURCE_DIR}/cmake/scripts/CTestCustom.cmake.in
 #option(FRIDA_MAN "Build a user manual" OFF)
 #option(BUILD_DEBIAN "Build a debian package" OFF)
 
+set(destination_lib ${CMAKE_INSTALL_PREFIX}/lib)
+
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 -pedantic -Wall -Wno-sign-compare -Wno-unused-result -Wno-parentheses  -Wno-unknown-pragmas -Werror")
 # to use C99 _Complex, add -fext-numeric-literals to CXX_FLAGS
 
-find_package(Boost REQUIRED) # used header-only modules: format algorithm
+find_package(Boost REQUIRED filesystem)
 find_package(BISON REQUIRED)
 find_package(FLEX REQUIRED)
 find_package(Readline REQUIRED)
@@ -37,7 +39,6 @@ find_package(Cerf REQUIRED)
 find_package(LMFit REQUIRED)
 find_package(Gnuplot REQUIRED)
 
-add_subdirectory(ThirdParty/googletest)
 add_subdirectory(readplus)
 add_subdirectory(trivia)
 add_subdirectory(plot)
@@ -45,6 +46,8 @@ add_subdirectory(lib)
 add_subdirectory(src)
 add_subdirectory(share)
 add_subdirectory(man)
+
+add_subdirectory(ThirdParty/googletest)
 add_subdirectory(utest) # unit tests
 add_subdirectory(ftest) # functional tests (run Frida with given script)
 
diff --git a/pub/ThirdParty/tclap/Arg.h b/pub/ThirdParty/tclap/Arg.h
new file mode 100644
index 0000000000000000000000000000000000000000..b28eef117c633f5e4108775cf9466a22402a9d07
--- /dev/null
+++ b/pub/ThirdParty/tclap/Arg.h
@@ -0,0 +1,692 @@
+// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
+
+/******************************************************************************
+ *
+ *  file:  Arg.h
+ *
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno .
+ *  All rights reverved.
+ *
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ *  DEALINGS IN THE SOFTWARE.
+ *
+ *****************************************************************************/
+
+
+#ifndef TCLAP_ARGUMENT_H
+#define TCLAP_ARGUMENT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#define HAVE_SSTREAM
+#endif
+
+#include <string>
+#include <vector>
+#include <list>
+#include <iostream>
+#include <iomanip>
+#include <cstdio>
+
+#if defined(HAVE_SSTREAM)
+#include <sstream>
+typedef std::istringstream istringstream;
+#elif defined(HAVE_STRSTREAM)
+#include <strstream>
+typedef std::istrstream istringstream;
+#else
+#error "Need a stringstream (sstream or strstream) to compile!"
+#endif
+
+#include <tclap/ArgException.h>
+#include <tclap/Visitor.h>
+#include <tclap/CmdLineInterface.h>
+#include <tclap/ArgTraits.h>
+#include <tclap/StandardTraits.h>
+
+namespace TCLAP {
+
+/**
+ * A virtual base class that defines the essential data for all arguments.
+ * This class, or one of its existing children, must be subclassed to do
+ * anything.
+ */
+class Arg
+{
+	private:
+		/**
+		 * Prevent accidental copying.
+		 */
+		Arg(const Arg& rhs);
+
+		/**
+		 * Prevent accidental copying.
+		 */
+		Arg& operator=(const Arg& rhs);
+
+		/**
+		 * Indicates whether the rest of the arguments should be ignored.
+		 */
+		static bool& ignoreRestRef() { static bool ign = false; return ign; }
+
+		/**
+		 * The delimiter that separates an argument flag/name from the
+		 * value.
+		 */
+		static char& delimiterRef() { static char delim = ' '; return delim; }
+
+	protected:
+
+		/**
+		 * The single char flag used to identify the argument.
+		 * This value (preceded by a dash {-}), can be used to identify
+		 * an argument on the command line.  The _flag can be blank,
+		 * in fact this is how unlabeled args work.  Unlabeled args must
+		 * override appropriate functions to get correct handling. Note
+		 * that the _flag does NOT include the dash as part of the flag.
+		 */
+		std::string _flag;
+
+		/**
+		 * A single work namd indentifying the argument.
+		 * This value (preceded by two dashed {--}) can also be used
+		 * to identify an argument on the command line.  Note that the
+		 * _name does NOT include the two dashes as part of the _name. The
+		 * _name cannot be blank.
+		 */
+		std::string _name;
+
+		/**
+		 * Description of the argument.
+		 */
+		std::string _description;
+
+		/**
+		 * Indicating whether the argument is required.
+		 */
+		bool _required;
+
+		/**
+		 * Label to be used in usage description.  Normally set to
+		 * "required", but can be changed when necessary.
+		 */
+		std::string _requireLabel;
+
+		/**
+		 * Indicates whether a value is required for the argument.
+		 * Note that the value may be required but the argument/value
+		 * combination may not be, as specified by _required.
+		 */
+		bool _valueRequired;
+
+		/**
+		 * Indicates whether the argument has been set.
+		 * Indicates that a value on the command line has matched the
+		 * name/flag of this argument and the values have been set accordingly.
+		 */
+		bool _alreadySet;
+
+		/**
+		 * A pointer to a vistitor object.
+		 * The visitor allows special handling to occur as soon as the
+		 * argument is matched.  This defaults to NULL and should not
+		 * be used unless absolutely necessary.
+		 */
+		Visitor* _visitor;
+
+		/**
+		 * Whether this argument can be ignored, if desired.
+		 */
+		bool _ignoreable;
+
+		/**
+		 * Indicates that the arg was set as part of an XOR and not on the
+		 * command line.
+		 */
+		bool _xorSet;
+
+		bool _acceptsMultipleValues;
+
+		/**
+		 * Performs the special handling described by the Vistitor.
+		 */
+		void _checkWithVisitor() const;
+
+		/**
+		 * Primary constructor. YOU (yes you) should NEVER construct an Arg
+		 * directly, this is a base class that is extended by various children
+		 * that are meant to be used.  Use SwitchArg, ValueArg, MultiArg,
+		 * UnlabeledValueArg, or UnlabeledMultiArg instead.
+		 *
+		 * \param flag - The flag identifying the argument.
+		 * \param name - The name identifying the argument.
+		 * \param desc - The description of the argument, used in the usage.
+		 * \param req - Whether the argument is required.
+		 * \param valreq - Whether the a value is required for the argument.
+		 * \param v - The visitor checked by the argument. Defaults to NULL.
+		 */
+ 		Arg( const std::string& flag,
+			 const std::string& name,
+			 const std::string& desc,
+			 bool req,
+			 bool valreq,
+			 Visitor* v = NULL );
+
+	public:
+		/**
+		 * Destructor.
+		 */
+		virtual ~Arg();
+
+		/**
+		 * Adds this to the specified list of Args.
+		 * \param argList - The list to add this to.
+		 */
+		virtual void addToList( std::list<Arg*>& argList ) const;
+
+		/**
+		 * Begin ignoring arguments since the "--" argument was specified.
+		 */
+		static void beginIgnoring() { ignoreRestRef() = true; }
+
+		/**
+		 * Whether to ignore the rest.
+		 */
+		static bool ignoreRest() { return ignoreRestRef(); }
+
+		/**
+		 * The delimiter that separates an argument flag/name from the
+		 * value.
+		 */
+		static char delimiter() { return delimiterRef(); }
+
+		/**
+		 * The char used as a place holder when SwitchArgs are combined.
+		 * Currently set to the bell char (ASCII 7).
+		 */
+		static char blankChar() { return (char)7; }
+
+		/**
+		 * The char that indicates the beginning of a flag.  Defaults to '-', but
+		 * clients can define TCLAP_FLAGSTARTCHAR to override.
+		 */
+#ifndef TCLAP_FLAGSTARTCHAR
+#define TCLAP_FLAGSTARTCHAR '-'
+#endif
+		static char flagStartChar() { return TCLAP_FLAGSTARTCHAR; }
+
+		/**
+		 * The sting that indicates the beginning of a flag.  Defaults to "-", but
+		 * clients can define TCLAP_FLAGSTARTSTRING to override. Should be the same
+		 * as TCLAP_FLAGSTARTCHAR.
+		 */
+#ifndef TCLAP_FLAGSTARTSTRING
+#define TCLAP_FLAGSTARTSTRING "-"
+#endif
+		static const std::string flagStartString() { return TCLAP_FLAGSTARTSTRING; }
+
+		/**
+		 * The sting that indicates the beginning of a name.  Defaults to "--", but
+		 *  clients can define TCLAP_NAMESTARTSTRING to override.
+		 */
+#ifndef TCLAP_NAMESTARTSTRING
+#define TCLAP_NAMESTARTSTRING "--"
+#endif
+		static const std::string nameStartString() { return TCLAP_NAMESTARTSTRING; }
+
+		/**
+		 * The name used to identify the ignore rest argument.
+		 */
+		static const std::string ignoreNameString() { return "ignore_rest"; }
+
+		/**
+		 * Sets the delimiter for all arguments.
+		 * \param c - The character that delimits flags/names from values.
+		 */
+		static void setDelimiter( char c ) { delimiterRef() = c; }
+
+		/**
+		 * Pure virtual method meant to handle the parsing and value assignment
+		 * of the string on the command line.
+		 * \param i - Pointer the the current argument in the list.
+		 * \param args - Mutable list of strings. What is
+		 * passed in from main.
+		 */
+		virtual bool processArg(int *i, std::vector<std::string>& args) = 0;
+
+		/**
+		 * Operator ==.
+		 * Equality operator. Must be virtual to handle unlabeled args.
+		 * \param a - The Arg to be compared to this.
+		 */
+		virtual bool operator==(const Arg& a) const;
+
+		/**
+		 * Returns the argument flag.
+		 */
+		const std::string& getFlag() const;
+
+		/**
+		 * Returns the argument name.
+		 */
+		const std::string& getName() const;
+
+		/**
+		 * Returns the argument description.
+		 */
+		std::string getDescription() const;
+
+		/**
+		 * Indicates whether the argument is required.
+		 */
+		virtual bool isRequired() const;
+
+		/**
+		 * Sets _required to true. This is used by the XorHandler.
+		 * You really have no reason to ever use it.
+		 */
+		void forceRequired();
+
+		/**
+		 * Sets the _alreadySet value to true.  This is used by the XorHandler.
+		 * You really have no reason to ever use it.
+		 */
+		void xorSet();
+
+		/**
+		 * Indicates whether a value must be specified for argument.
+		 */
+		bool isValueRequired() const;
+
+		/**
+		 * Indicates whether the argument has already been set.  Only true
+		 * if the arg has been matched on the command line.
+		 */
+		bool isSet() const;
+
+		/**
+		 * Indicates whether the argument can be ignored, if desired.
+		 */
+		bool isIgnoreable() const;
+
+		/**
+		 * A method that tests whether a string matches this argument.
+		 * This is generally called by the processArg() method.  This
+		 * method could be re-implemented by a child to change how
+		 * arguments are specified on the command line.
+		 * \param s - The string to be compared to the flag/name to determine
+		 * whether the arg matches.
+		 */
+		virtual bool argMatches( const std::string& s ) const;
+
+		/**
+		 * Returns a simple string representation of the argument.
+		 * Primarily for debugging.
+		 */
+		virtual std::string toString() const;
+
+		/**
+		 * Returns a short ID for the usage.
+		 * \param valueId - The value used in the id.
+		 */
+		virtual std::string shortID( const std::string& valueId = "val" ) const;
+
+		/**
+		 * Returns a long ID for the usage.
+		 * \param valueId - The value used in the id.
+		 */
+		virtual std::string longID( const std::string& valueId = "val" ) const;
+
+		/**
+		 * Trims a value off of the flag.
+		 * \param flag - The string from which the flag and value will be
+		 * trimmed. Contains the flag once the value has been trimmed.
+		 * \param value - Where the value trimmed from the string will
+		 * be stored.
+		 */
+		virtual void trimFlag( std::string& flag, std::string& value ) const;
+
+		/**
+		 * Checks whether a given string has blank chars, indicating that
+		 * it is a combined SwitchArg.  If so, return true, otherwise return
+		 * false.
+		 * \param s - string to be checked.
+		 */
+		bool _hasBlanks( const std::string& s ) const;
+
+		/**
+		 * Sets the requireLabel. Used by XorHandler.  You shouldn't ever
+		 * use this.
+		 * \param s - Set the requireLabel to this value.
+		 */
+		void setRequireLabel( const std::string& s );
+
+		/**
+		 * Used for MultiArgs and XorHandler to determine whether args
+		 * can still be set.
+		 */
+		virtual bool allowMore();
+
+		/**
+		 * Use by output classes to determine whether an Arg accepts
+		 * multiple values.
+		 */
+		virtual bool acceptsMultipleValues();
+
+		/**
+		 * Clears the Arg object and allows it to be reused by new
+		 * command lines.
+		 */
+		 virtual void reset();
+};
+
+/**
+ * Typedef of an Arg list iterator.
+ */
+typedef std::list<Arg*>::iterator ArgListIterator;
+
+/**
+ * Typedef of an Arg vector iterator.
+ */
+typedef std::vector<Arg*>::iterator ArgVectorIterator;
+
+/**
+ * Typedef of a Visitor list iterator.
+ */
+typedef std::list<Visitor*>::iterator VisitorListIterator;
+
+/*
+ * Extract a value of type T from it's string representation contained
+ * in strVal. The ValueLike parameter used to select the correct
+ * specialization of ExtractValue depending on the value traits of T.
+ * ValueLike traits use operator>> to assign the value from strVal.
+ */
+template<typename T> void
+ExtractValue(T &destVal, const std::string& strVal, ValueLike vl)
+{
+    static_cast<void>(vl); // Avoid warning about unused vl
+    std::istringstream is(strVal);
+
+    int valuesRead = 0;
+    while ( is.good() ) {
+	if ( is.peek() != EOF )
+#ifdef TCLAP_SETBASE_ZERO
+	    is >> std::setbase(0) >> destVal;
+#else
+	    is >> destVal;
+#endif
+	else
+	    break;
+
+	valuesRead++;
+    }
+
+    if ( is.fail() )
+	throw( ArgParseException("Couldn't read argument value "
+				 "from string '" + strVal + "'"));
+
+
+    if ( valuesRead > 1 )
+	throw( ArgParseException("More than one valid value parsed from "
+				 "string '" + strVal + "'"));
+
+}
+
+/*
+ * Extract a value of type T from it's string representation contained
+ * in strVal. The ValueLike parameter used to select the correct
+ * specialization of ExtractValue depending on the value traits of T.
+ * StringLike uses assignment (operator=) to assign from strVal.
+ */
+template<typename T> void
+ExtractValue(T &destVal, const std::string& strVal, StringLike sl)
+{
+    static_cast<void>(sl); // Avoid warning about unused sl
+    SetString(destVal, strVal);
+}
+
+//////////////////////////////////////////////////////////////////////
+//BEGIN Arg.cpp
+//////////////////////////////////////////////////////////////////////
+
+inline Arg::Arg(const std::string& flag,
+         const std::string& name,
+         const std::string& desc,
+         bool req,
+         bool valreq,
+         Visitor* v) :
+  _flag(flag),
+  _name(name),
+  _description(desc),
+  _required(req),
+  _requireLabel("required"),
+  _valueRequired(valreq),
+  _alreadySet(false),
+  _visitor( v ),
+  _ignoreable(true),
+  _xorSet(false),
+  _acceptsMultipleValues(false)
+{
+	if ( _flag.length() > 1 )
+		throw(SpecificationException(
+				"Argument flag can only be one character long", toString() ) );
+
+	if ( _name != ignoreNameString() &&
+		 ( _flag == Arg::flagStartString() ||
+		   _flag == Arg::nameStartString() ||
+		   _flag == " " ) )
+		throw(SpecificationException("Argument flag cannot be either '" +
+							Arg::flagStartString() + "' or '" +
+							Arg::nameStartString() + "' or a space.",
+							toString() ) );
+
+	if ( ( _name.substr( 0, Arg::flagStartString().length() ) == Arg::flagStartString() ) ||
+		 ( _name.substr( 0, Arg::nameStartString().length() ) == Arg::nameStartString() ) ||
+		 ( _name.find( " ", 0 ) != std::string::npos ) )
+		throw(SpecificationException("Argument name begin with either '" +
+							Arg::flagStartString() + "' or '" +
+							Arg::nameStartString() + "' or space.",
+							toString() ) );
+
+}
+
+inline Arg::~Arg() { }
+
+inline std::string Arg::shortID( const std::string& valueId ) const
+{
+	std::string id = "";
+
+	if ( _flag != "" )
+		id = Arg::flagStartString() + _flag;
+	else
+		id = Arg::nameStartString() + _name;
+
+	if ( _valueRequired )
+		id += std::string( 1, Arg::delimiter() ) + "<" + valueId  + ">";
+
+	if ( !_required )
+		id = "[" + id + "]";
+
+	return id;
+}
+
+inline std::string Arg::longID( const std::string& valueId ) const
+{
+	std::string id = "";
+
+	if ( _flag != "" )
+	{
+		id += Arg::flagStartString() + _flag;
+
+		if ( _valueRequired )
+			id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">";
+
+		id += ",  ";
+	}
+
+	id += Arg::nameStartString() + _name;
+
+	if ( _valueRequired )
+		id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">";
+
+	return id;
+
+}
+
+inline bool Arg::operator==(const Arg& a) const
+{
+	if ( ( _flag != "" && _flag == a._flag ) || _name == a._name)
+		return true;
+	else
+		return false;
+}
+
+inline std::string Arg::getDescription() const
+{
+	std::string desc = "";
+	if ( _required )
+		desc = "(" + _requireLabel + ")  ";
+
+//	if ( _valueRequired )
+//		desc += "(value required)  ";
+
+	desc += _description;
+	return desc;
+}
+
+inline const std::string& Arg::getFlag() const { return _flag; }
+
+inline const std::string& Arg::getName() const { return _name; }
+
+inline bool Arg::isRequired() const { return _required; }
+
+inline bool Arg::isValueRequired() const { return _valueRequired; }
+
+inline bool Arg::isSet() const
+{
+	if ( _alreadySet && !_xorSet )
+		return true;
+	else
+		return false;
+}
+
+inline bool Arg::isIgnoreable() const { return _ignoreable; }
+
+inline void Arg::setRequireLabel( const std::string& s)
+{
+	_requireLabel = s;
+}
+
+inline bool Arg::argMatches( const std::string& argFlag ) const
+{
+	if ( ( argFlag == Arg::flagStartString() + _flag && _flag != "" ) ||
+	       argFlag == Arg::nameStartString() + _name )
+		return true;
+	else
+		return false;
+}
+
+inline std::string Arg::toString() const
+{
+	std::string s = "";
+
+	if ( _flag != "" )
+		s += Arg::flagStartString() + _flag + " ";
+
+	s += "(" + Arg::nameStartString() + _name + ")";
+
+	return s;
+}
+
+inline void Arg::_checkWithVisitor() const
+{
+	if ( _visitor != NULL )
+		_visitor->visit();
+}
+
+/**
+ * Implementation of trimFlag.
+ */
+inline void Arg::trimFlag(std::string& flag, std::string& value) const
+{
+	int stop = 0;
+	for ( int i = 0; static_cast<unsigned int>(i) < flag.length(); i++ )
+		if ( flag[i] == Arg::delimiter() )
+		{
+			stop = i;
+			break;
+		}
+
+	if ( stop > 1 )
+	{
+		value = flag.substr(stop+1);
+		flag = flag.substr(0,stop);
+	}
+
+}
+
+/**
+ * Implementation of _hasBlanks.
+ */
+inline bool Arg::_hasBlanks( const std::string& s ) const
+{
+	for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
+		if ( s[i] == Arg::blankChar() )
+			return true;
+
+	return false;
+}
+
+inline void Arg::forceRequired()
+{
+	_required = true;
+}
+
+inline void Arg::xorSet()
+{
+	_alreadySet = true;
+	_xorSet = true;
+}
+
+/**
+ * Overridden by Args that need to added to the end of the list.
+ */
+inline void Arg::addToList( std::list<Arg*>& argList ) const
+{
+	argList.push_front( const_cast<Arg*>(this) );
+}
+
+inline bool Arg::allowMore()
+{
+	return false;
+}
+
+inline bool Arg::acceptsMultipleValues()
+{
+	return _acceptsMultipleValues;
+}
+
+inline void Arg::reset()
+{
+	_xorSet = false;
+	_alreadySet = false;
+}
+
+//////////////////////////////////////////////////////////////////////
+//END Arg.cpp
+//////////////////////////////////////////////////////////////////////
+
+} //namespace TCLAP
+
+#endif
+
diff --git a/pub/ThirdParty/tclap/ArgException.h b/pub/ThirdParty/tclap/ArgException.h
new file mode 100644
index 0000000000000000000000000000000000000000..3411aa9543fe3643053ab2aff7c8994b3a900327
--- /dev/null
+++ b/pub/ThirdParty/tclap/ArgException.h
@@ -0,0 +1,200 @@
+// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
+
+/****************************************************************************** 
+ * 
+ *  file:  ArgException.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+
+#ifndef TCLAP_ARG_EXCEPTION_H
+#define TCLAP_ARG_EXCEPTION_H
+
+#include <string>
+#include <exception>
+
+namespace TCLAP {
+
+/**
+ * A simple class that defines and argument exception.  Should be caught
+ * whenever a CmdLine is created and parsed.
+ */
+class ArgException : public std::exception
+{
+	public:
+	
+		/**
+		 * Constructor.
+		 * \param text - The text of the exception.
+		 * \param id - The text identifying the argument source.
+		 * \param td - Text describing the type of ArgException it is.
+		 * of the exception.
+		 */
+		ArgException( const std::string& text = "undefined exception", 
+					  const std::string& id = "undefined",
+					  const std::string& td = "Generic ArgException")
+			: std::exception(), 
+			  _errorText(text), 
+			  _argId( id ), 
+			  _typeDescription(td)
+		{ } 
+		
+		/**
+		 * Destructor.
+		 */
+		virtual ~ArgException() throw() { }
+
+		/**
+		 * Returns the error text.
+		 */
+		std::string error() const { return ( _errorText ); }
+
+		/**
+		 * Returns the argument id.
+		 */
+		std::string argId() const  
+		{ 
+			if ( _argId == "undefined" )
+				return " ";
+			else
+				return ( "Argument: " + _argId ); 
+		}
+
+		/**
+		 * Returns the arg id and error text. 
+		 */
+		const char* what() const throw() 
+		{
+			static std::string ex; 
+			ex = _argId + " -- " + _errorText;
+			return ex.c_str();
+		}
+
+		/**
+		 * Returns the type of the exception.  Used to explain and distinguish
+		 * between different child exceptions.
+		 */
+		std::string typeDescription() const
+		{
+			return _typeDescription; 
+		}
+
+
+	private:
+
+		/**
+		 * The text of the exception message.
+		 */
+		std::string _errorText;
+
+		/**
+		 * The argument related to this exception.
+		 */
+		std::string _argId;
+
+		/**
+		 * Describes the type of the exception.  Used to distinguish
+		 * between different child exceptions.
+		 */
+		std::string _typeDescription;
+
+};
+
+/**
+ * Thrown from within the child Arg classes when it fails to properly
+ * parse the argument it has been passed.
+ */
+class ArgParseException : public ArgException
+{ 
+	public:
+		/**
+		 * Constructor.
+		 * \param text - The text of the exception.
+		 * \param id - The text identifying the argument source 
+		 * of the exception.
+		 */
+		ArgParseException( const std::string& text = "undefined exception", 
+					       const std::string& id = "undefined" )
+			: ArgException( text, 
+			                id, 
+							std::string( "Exception found while parsing " ) + 
+							std::string( "the value the Arg has been passed." ))
+			{ }
+};
+
+/**
+ * Thrown from CmdLine when the arguments on the command line are not
+ * properly specified, e.g. too many arguments, required argument missing, etc.
+ */
+class CmdLineParseException : public ArgException
+{
+	public:
+		/**
+		 * Constructor.
+		 * \param text - The text of the exception.
+		 * \param id - The text identifying the argument source 
+		 * of the exception.
+		 */
+		CmdLineParseException( const std::string& text = "undefined exception", 
+					           const std::string& id = "undefined" )
+			: ArgException( text, 
+			                id,
+							std::string( "Exception found when the values ") +
+							std::string( "on the command line do not meet ") +
+							std::string( "the requirements of the defined ") +
+							std::string( "Args." ))
+		{ }
+};
+
+/**
+ * Thrown from Arg and CmdLine when an Arg is improperly specified, e.g. 
+ * same flag as another Arg, same name, etc.
+ */
+class SpecificationException : public ArgException
+{
+	public:
+		/**
+		 * Constructor.
+		 * \param text - The text of the exception.
+		 * \param id - The text identifying the argument source 
+		 * of the exception.
+		 */
+		SpecificationException( const std::string& text = "undefined exception",
+					            const std::string& id = "undefined" )
+			: ArgException( text, 
+			                id,
+							std::string("Exception found when an Arg object ")+
+							std::string("is improperly defined by the ") +
+							std::string("developer." )) 
+		{ }
+
+};
+
+class ExitException {
+public:
+	ExitException(int estat) : _estat(estat) {}
+
+	int getExitStatus() const { return _estat; }
+
+private:
+	int _estat;
+};
+
+} // namespace TCLAP
+
+#endif
+
diff --git a/pub/ThirdParty/tclap/ArgTraits.h b/pub/ThirdParty/tclap/ArgTraits.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b2c18f70c68200b431794eb6bec28927b6ec9aa
--- /dev/null
+++ b/pub/ThirdParty/tclap/ArgTraits.h
@@ -0,0 +1,87 @@
+// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
+
+/******************************************************************************
+ *
+ *  file:  ArgTraits.h
+ *
+ *  Copyright (c) 2007, Daniel Aarno, Michael E. Smoot .
+ *  All rights reverved.
+ *
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ *  DEALINGS IN THE SOFTWARE.
+ *
+ *****************************************************************************/
+
+// This is an internal tclap file, you should probably not have to
+// include this directly
+
+#ifndef TCLAP_ARGTRAITS_H
+#define TCLAP_ARGTRAITS_H
+
+namespace TCLAP {
+
+// We use two empty structs to get compile type specialization
+// function to work
+
+/**
+ * A value like argument value type is a value that can be set using
+ * operator>>. This is the default value type.
+ */
+struct ValueLike {
+    typedef ValueLike ValueCategory;
+	virtual ~ValueLike() {}
+};
+
+/**
+ * A string like argument value type is a value that can be set using
+ * operator=(string). Usefull if the value type contains spaces which
+ * will be broken up into individual tokens by operator>>.
+ */
+struct StringLike {
+	virtual ~StringLike() {}
+};
+
+/**
+ * A class can inherit from this object to make it have string like
+ * traits. This is a compile time thing and does not add any overhead
+ * to the inherenting class.
+ */
+struct StringLikeTrait {
+    typedef StringLike ValueCategory;
+	virtual ~StringLikeTrait() {}
+};
+
+/**
+ * A class can inherit from this object to make it have value like
+ * traits. This is a compile time thing and does not add any overhead
+ * to the inherenting class.
+ */
+struct ValueLikeTrait {
+    typedef ValueLike ValueCategory;
+	virtual ~ValueLikeTrait() {}
+};
+
+/**
+ * Arg traits are used to get compile type specialization when parsing
+ * argument values. Using an ArgTraits you can specify the way that
+ * values gets assigned to any particular type during parsing. The two
+ * supported types are StringLike and ValueLike.
+ */
+template<typename T>
+struct ArgTraits {
+    typedef typename T::ValueCategory ValueCategory;
+	virtual ~ArgTraits() {}
+    //typedef ValueLike ValueCategory;
+};
+
+#endif
+
+} // namespace
diff --git a/pub/ThirdParty/tclap/CmdLine.h b/pub/ThirdParty/tclap/CmdLine.h
new file mode 100644
index 0000000000000000000000000000000000000000..0fec8d8a115910c800ff12a1fd1c41f6b8dc023f
--- /dev/null
+++ b/pub/ThirdParty/tclap/CmdLine.h
@@ -0,0 +1,633 @@
+// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
+
+/******************************************************************************
+ *
+ *  file:  CmdLine.h
+ *
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
+ *  All rights reverved.
+ *
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ *  DEALINGS IN THE SOFTWARE.
+ *
+ *****************************************************************************/
+
+#ifndef TCLAP_CMDLINE_H
+#define TCLAP_CMDLINE_H
+
+#include <tclap/SwitchArg.h>
+#include <tclap/MultiSwitchArg.h>
+#include <tclap/UnlabeledValueArg.h>
+#include <tclap/UnlabeledMultiArg.h>
+
+#include <tclap/XorHandler.h>
+#include <tclap/HelpVisitor.h>
+#include <tclap/VersionVisitor.h>
+#include <tclap/IgnoreRestVisitor.h>
+
+#include <tclap/CmdLineOutput.h>
+#include <tclap/StdOutput.h>
+
+#include <tclap/Constraint.h>
+#include <tclap/ValuesConstraint.h>
+
+#include <string>
+#include <vector>
+#include <list>
+#include <iostream>
+#include <iomanip>
+#include <algorithm>
+#include <stdlib.h> // Needed for exit(), which isn't defined in some envs.
+
+namespace TCLAP {
+
+template<typename T> void DelPtr(T ptr)
+{
+	delete ptr;
+}
+
+template<typename C> void ClearContainer(C &c)
+{
+	typedef typename C::value_type value_type;
+	std::for_each(c.begin(), c.end(), DelPtr<value_type>);
+	c.clear();
+}
+
+
+/**
+ * The base class that manages the command line definition and passes
+ * along the parsing to the appropriate Arg classes.
+ */
+class CmdLine : public CmdLineInterface
+{
+	protected:
+
+		/**
+		 * The list of arguments that will be tested against the
+		 * command line.
+		 */
+		std::list<Arg*> _argList;
+
+		/**
+		 * The name of the program.  Set to argv[0].
+		 */
+		std::string _progName;
+
+		/**
+		 * A message used to describe the program.  Used in the usage output.
+		 */
+		std::string _message;
+
+		/**
+		 * The version to be displayed with the --version switch.
+		 */
+		std::string _version;
+
+		/**
+		 * The number of arguments that are required to be present on
+		 * the command line. This is set dynamically, based on the
+		 * Args added to the CmdLine object.
+		 */
+		int _numRequired;
+
+		/**
+		 * The character that is used to separate the argument flag/name
+		 * from the value.  Defaults to ' ' (space).
+		 */
+		char _delimiter;
+
+		/**
+		 * The handler that manages xoring lists of args.
+		 */
+		XorHandler _xorHandler;
+
+		/**
+		 * A list of Args to be explicitly deleted when the destructor
+		 * is called.  At the moment, this only includes the three default
+		 * Args.
+		 */
+		std::list<Arg*> _argDeleteOnExitList;
+
+		/**
+		 * A list of Visitors to be explicitly deleted when the destructor
+		 * is called.  At the moment, these are the Vistors created for the
+		 * default Args.
+		 */
+		std::list<Visitor*> _visitorDeleteOnExitList;
+
+		/**
+		 * Object that handles all output for the CmdLine.
+		 */
+		CmdLineOutput* _output;
+
+		/**
+		 * Should CmdLine handle parsing exceptions internally?
+		 */
+		bool _handleExceptions;
+
+		/**
+		 * Throws an exception listing the missing args.
+		 */
+		void missingArgsException();
+
+		/**
+		 * Checks whether a name/flag string matches entirely matches
+		 * the Arg::blankChar.  Used when multiple switches are combined
+		 * into a single argument.
+		 * \param s - The message to be used in the usage.
+		 */
+		bool _emptyCombined(const std::string& s);
+
+		/**
+		 * Perform a delete ptr; operation on ptr when this object is deleted.
+		 */
+		void deleteOnExit(Arg* ptr);
+
+		/**
+		 * Perform a delete ptr; operation on ptr when this object is deleted.
+		 */
+		void deleteOnExit(Visitor* ptr);
+
+private:
+
+		/**
+		 * Prevent accidental copying.
+		 */
+		CmdLine(const CmdLine& rhs);
+		CmdLine& operator=(const CmdLine& rhs);
+
+		/**
+		 * Encapsulates the code common to the constructors
+		 * (which is all of it).
+		 */
+		void _constructor();
+
+
+		/**
+		 * Is set to true when a user sets the output object. We use this so
+		 * that we don't delete objects that are created outside of this lib.
+		 */
+		bool _userSetOutput;
+
+		/**
+		 * Whether or not to automatically create help and version switches.
+		 */
+		bool _helpAndVersion;
+
+	public:
+
+		/**
+		 * Command line constructor. Defines how the arguments will be
+		 * parsed.
+		 * \param message - The message to be used in the usage
+		 * output.
+		 * \param delimiter - The character that is used to separate
+		 * the argument flag/name from the value.  Defaults to ' ' (space).
+		 * \param version - The version number to be used in the
+		 * --version switch.
+		 * \param helpAndVersion - Whether or not to create the Help and
+		 * Version switches. Defaults to true.
+		 */
+		CmdLine(const std::string& message,
+				const char delimiter = ' ',
+				const std::string& version = "none",
+				bool helpAndVersion = true);
+
+		/**
+		 * Deletes any resources allocated by a CmdLine object.
+		 */
+		virtual ~CmdLine();
+
+		/**
+		 * Adds an argument to the list of arguments to be parsed.
+		 * \param a - Argument to be added.
+		 */
+		void add( Arg& a );
+
+		/**
+		 * An alternative add.  Functionally identical.
+		 * \param a - Argument to be added.
+		 */
+		void add( Arg* a );
+
+		/**
+		 * Add two Args that will be xor'd.  If this method is used, add does
+		 * not need to be called.
+		 * \param a - Argument to be added and xor'd.
+		 * \param b - Argument to be added and xor'd.
+		 */
+		void xorAdd( Arg& a, Arg& b );
+
+		/**
+		 * Add a list of Args that will be xor'd.  If this method is used,
+		 * add does not need to be called.
+		 * \param xors - List of Args to be added and xor'd.
+		 */
+		void xorAdd( std::vector<Arg*>& xors );
+
+		/**
+		 * Parses the command line.
+		 * \param argc - Number of arguments.
+		 * \param argv - Array of arguments.
+		 */
+		void parse(int argc, const char * const * argv);
+
+		/**
+		 * Parses the command line.
+		 * \param args - A vector of strings representing the args.
+		 * args[0] is still the program name.
+		 */
+		void parse(std::vector<std::string>& args);
+
+		/**
+		 *
+		 */
+		CmdLineOutput* getOutput();
+
+		/**
+		 *
+		 */
+		void setOutput(CmdLineOutput* co);
+
+		/**
+		 *
+		 */
+		std::string& getVersion();
+
+		/**
+		 *
+		 */
+		std::string& getProgramName();
+
+		/**
+		 *
+		 */
+		std::list<Arg*>& getArgList();
+
+		/**
+		 *
+		 */
+		XorHandler& getXorHandler();
+
+		/**
+		 *
+		 */
+		char getDelimiter();
+
+		/**
+		 *
+		 */
+		std::string& getMessage();
+
+		/**
+		 *
+		 */
+		bool hasHelpAndVersion();
+
+		/**
+		 * Disables or enables CmdLine's internal parsing exception handling.
+		 *
+		 * @param state Should CmdLine handle parsing exceptions internally?
+		 */
+		void setExceptionHandling(const bool state);
+
+		/**
+		 * Returns the current state of the internal exception handling.
+		 *
+		 * @retval true Parsing exceptions are handled internally.
+		 * @retval false Parsing exceptions are propagated to the caller.
+		 */
+		bool getExceptionHandling() const;
+
+		/**
+		 * Allows the CmdLine object to be reused.
+		 */
+		void reset();
+
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+//Begin CmdLine.cpp
+///////////////////////////////////////////////////////////////////////////////
+
+inline CmdLine::CmdLine(const std::string& m,
+                        char delim,
+                        const std::string& v,
+                        bool help )
+    :
+  _argList(std::list<Arg*>()),
+  _progName("not_set_yet"),
+  _message(m),
+  _version(v),
+  _numRequired(0),
+  _delimiter(delim),
+  _xorHandler(XorHandler()),
+  _argDeleteOnExitList(std::list<Arg*>()),
+  _visitorDeleteOnExitList(std::list<Visitor*>()),
+  _output(0),
+  _handleExceptions(true),
+  _userSetOutput(false),
+  _helpAndVersion(help)
+{
+	_constructor();
+}
+
+inline CmdLine::~CmdLine()
+{
+	ClearContainer(_argDeleteOnExitList);
+	ClearContainer(_visitorDeleteOnExitList);
+
+	if ( !_userSetOutput ) {
+		delete _output;
+		_output = 0;
+	}
+}
+
+inline void CmdLine::_constructor()
+{
+	_output = new StdOutput;
+
+	Arg::setDelimiter( _delimiter );
+
+	Visitor* v;
+
+	if ( _helpAndVersion )
+	{
+		v = new HelpVisitor( this, &_output );
+		SwitchArg* help = new SwitchArg("h","help",
+		                      "Displays usage information and exits.",
+		                      false, v);
+		add( help );
+		deleteOnExit(help);
+		deleteOnExit(v);
+
+		v = new VersionVisitor( this, &_output );
+		SwitchArg* vers = new SwitchArg("","version",
+		                      "Displays version information and exits.",
+		                      false, v);
+		add( vers );
+		deleteOnExit(vers);
+		deleteOnExit(v);
+	}
+
+	v = new IgnoreRestVisitor();
+	SwitchArg* ignore  = new SwitchArg(Arg::flagStartString(),
+	          Arg::ignoreNameString(),
+	          "Ignores the rest of the labeled arguments following this flag.",
+	          false, v);
+	add( ignore );
+	deleteOnExit(ignore);
+	deleteOnExit(v);
+}
+
+inline void CmdLine::xorAdd( std::vector<Arg*>& ors )
+{
+	_xorHandler.add( ors );
+
+	for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
+	{
+		(*it)->forceRequired();
+		(*it)->setRequireLabel( "OR required" );
+		add( *it );
+	}
+}
+
+inline void CmdLine::xorAdd( Arg& a, Arg& b )
+{
+	std::vector<Arg*> ors;
+	ors.push_back( &a );
+	ors.push_back( &b );
+	xorAdd( ors );
+}
+
+inline void CmdLine::add( Arg& a )
+{
+	add( &a );
+}
+
+inline void CmdLine::add( Arg* a )
+{
+	for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
+		if ( *a == *(*it) )
+			throw( SpecificationException(
+			        "Argument with same flag/name already exists!",
+			        a->longID() ) );
+
+	a->addToList( _argList );
+
+	if ( a->isRequired() )
+		_numRequired++;
+}
+
+
+inline void CmdLine::parse(int argc, const char * const * argv)
+{
+		// this step is necessary so that we have easy access to
+		// mutable strings.
+		std::vector<std::string> args;
+		for (int i = 0; i < argc; i++)
+			args.push_back(argv[i]);
+
+		parse(args);
+}
+
+inline void CmdLine::parse(std::vector<std::string>& args)
+{
+	bool shouldExit = false;
+	int estat = 0;
+
+	try {
+		_progName = args.front();
+		args.erase(args.begin());
+
+		int requiredCount = 0;
+
+		for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++) 
+		{
+			bool matched = false;
+			for (ArgListIterator it = _argList.begin();
+			     it != _argList.end(); it++) {
+				if ( (*it)->processArg( &i, args ) )
+				{
+					requiredCount += _xorHandler.check( *it );
+					matched = true;
+					break;
+				}
+			}
+
+			// checks to see if the argument is an empty combined
+			// switch and if so, then we've actually matched it
+			if ( !matched && _emptyCombined( args[i] ) )
+				matched = true;
+
+			if ( !matched && !Arg::ignoreRest() )
+				throw(CmdLineParseException("Couldn't find match "
+				                            "for argument",
+				                            args[i]));
+		}
+
+		if ( requiredCount < _numRequired )
+			missingArgsException();
+
+		if ( requiredCount > _numRequired )
+			throw(CmdLineParseException("Too many arguments!"));
+
+	} catch ( ArgException& e ) {
+		// If we're not handling the exceptions, rethrow.
+		if ( !_handleExceptions) {
+			throw;
+		}
+
+		try {
+			_output->failure(*this,e);
+		} catch ( ExitException &ee ) {
+			estat = ee.getExitStatus();
+			shouldExit = true;
+		}
+	} catch (ExitException &ee) {
+		// If we're not handling the exceptions, rethrow.
+		if ( !_handleExceptions) {
+			throw;
+		}
+
+		estat = ee.getExitStatus();
+		shouldExit = true;
+	}
+
+	if (shouldExit)
+		exit(estat);
+}
+
+inline bool CmdLine::_emptyCombined(const std::string& s)
+{
+	if ( s.length() > 0 && s[0] != Arg::flagStartChar() )
+		return false;
+
+	for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
+		if ( s[i] != Arg::blankChar() )
+			return false;
+
+	return true;
+}
+
+inline void CmdLine::missingArgsException()
+{
+		int count = 0;
+
+		std::string missingArgList;
+		for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
+		{
+			if ( (*it)->isRequired() && !(*it)->isSet() )
+			{
+				missingArgList += (*it)->getName();
+				missingArgList += ", ";
+				count++;
+			}
+		}
+		missingArgList = missingArgList.substr(0,missingArgList.length()-2);
+
+		std::string msg;
+		if ( count > 1 )
+			msg = "Required arguments missing: ";
+		else
+			msg = "Required argument missing: ";
+
+		msg += missingArgList;
+
+		throw(CmdLineParseException(msg));
+}
+
+inline void CmdLine::deleteOnExit(Arg* ptr)
+{
+	_argDeleteOnExitList.push_back(ptr);
+}
+
+inline void CmdLine::deleteOnExit(Visitor* ptr)
+{
+	_visitorDeleteOnExitList.push_back(ptr);
+}
+
+inline CmdLineOutput* CmdLine::getOutput()
+{
+	return _output;
+}
+
+inline void CmdLine::setOutput(CmdLineOutput* co)
+{
+	if ( !_userSetOutput )
+		delete _output;
+	_userSetOutput = true;
+	_output = co;
+}
+
+inline std::string& CmdLine::getVersion()
+{
+	return _version;
+}
+
+inline std::string& CmdLine::getProgramName()
+{
+	return _progName;
+}
+
+inline std::list<Arg*>& CmdLine::getArgList()
+{
+	return _argList;
+}
+
+inline XorHandler& CmdLine::getXorHandler()
+{
+	return _xorHandler;
+}
+
+inline char CmdLine::getDelimiter()
+{
+	return _delimiter;
+}
+
+inline std::string& CmdLine::getMessage()
+{
+	return _message;
+}
+
+inline bool CmdLine::hasHelpAndVersion()
+{
+	return _helpAndVersion;
+}
+
+inline void CmdLine::setExceptionHandling(const bool state)
+{
+	_handleExceptions = state;
+}
+
+inline bool CmdLine::getExceptionHandling() const
+{
+	return _handleExceptions;
+}
+
+inline void CmdLine::reset()
+{
+	for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
+		(*it)->reset();
+	
+	_progName.clear();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//End CmdLine.cpp
+///////////////////////////////////////////////////////////////////////////////
+
+
+
+} //namespace TCLAP
+#endif
diff --git a/pub/ThirdParty/tclap/CmdLineInterface.h b/pub/ThirdParty/tclap/CmdLineInterface.h
new file mode 100644
index 0000000000000000000000000000000000000000..1b25e9b8c950a29988bd510c9f3b3a2a6b1b3b58
--- /dev/null
+++ b/pub/ThirdParty/tclap/CmdLineInterface.h
@@ -0,0 +1,150 @@
+
+/****************************************************************************** 
+ * 
+ *  file:  CmdLineInterface.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
+ *  All rights reverved.
+ *
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+#ifndef TCLAP_COMMANDLINE_INTERFACE_H
+#define TCLAP_COMMANDLINE_INTERFACE_H
+
+#include <string>
+#include <vector>
+#include <list>
+#include <iostream>
+#include <algorithm>
+
+
+namespace TCLAP {
+     
+class Arg;
+class CmdLineOutput;
+class XorHandler;
+
+/**
+ * The base class that manages the command line definition and passes
+ * along the parsing to the appropriate Arg classes.
+ */
+class CmdLineInterface
+{
+	public:
+
+		/**
+		 * Destructor
+		 */
+		virtual ~CmdLineInterface() {}
+
+		/**
+		 * Adds an argument to the list of arguments to be parsed.
+		 * \param a - Argument to be added. 
+		 */
+		virtual void add( Arg& a )=0;
+
+		/**
+		 * An alternative add.  Functionally identical.
+		 * \param a - Argument to be added. 
+		 */
+		virtual void add( Arg* a )=0;
+
+		/**
+		 * Add two Args that will be xor'd.  
+		 * If this method is used, add does
+		 * not need to be called.
+		 * \param a - Argument to be added and xor'd. 
+		 * \param b - Argument to be added and xor'd. 
+		 */
+		virtual void xorAdd( Arg& a, Arg& b )=0;
+
+		/**
+		 * Add a list of Args that will be xor'd.  If this method is used, 
+		 * add does not need to be called.
+		 * \param xors - List of Args to be added and xor'd. 
+		 */
+		virtual void xorAdd( std::vector<Arg*>& xors )=0;
+
+		/**
+		 * Parses the command line.
+		 * \param argc - Number of arguments.
+		 * \param argv - Array of arguments.
+		 */
+		virtual void parse(int argc, const char * const * argv)=0;
+
+        /**
+         * Parses the command line.
+         * \param args - A vector of strings representing the args. 
+         * args[0] is still the program name.
+         */
+        void parse(std::vector<std::string>& args);
+
+		/**
+		 * Returns the CmdLineOutput object.
+		 */
+		virtual CmdLineOutput* getOutput()=0;
+
+		/**
+		 * \param co - CmdLineOutput object that we want to use instead. 
+		 */
+		virtual void setOutput(CmdLineOutput* co)=0;
+
+		/**
+		 * Returns the version string.
+		 */
+		virtual std::string& getVersion()=0;
+
+		/**
+		 * Returns the program name string.
+		 */
+		virtual std::string& getProgramName()=0;
+
+		/**
+		 * Returns the argList. 
+		 */
+		virtual std::list<Arg*>& getArgList()=0;
+
+		/**
+		 * Returns the XorHandler. 
+		 */
+		virtual XorHandler& getXorHandler()=0;
+
+		/**
+		 * Returns the delimiter string.
+		 */
+		virtual char getDelimiter()=0;
+
+		/**
+		 * Returns the message string.
+		 */
+		virtual std::string& getMessage()=0;
+
+		/**
+		 * Indicates whether or not the help and version switches were created
+		 * automatically.
+		 */
+		virtual bool hasHelpAndVersion()=0;
+
+		/** 
+		 * Resets the instance as if it had just been constructed so that the
+		 * instance can be reused. 
+		 */
+		virtual void reset()=0;
+};
+
+} //namespace
+
+
+#endif 
diff --git a/pub/ThirdParty/tclap/CmdLineOutput.h b/pub/ThirdParty/tclap/CmdLineOutput.h
new file mode 100644
index 0000000000000000000000000000000000000000..71ee5a3b418b4d3aaf7b2bdfd30282bc5d4e0e3b
--- /dev/null
+++ b/pub/ThirdParty/tclap/CmdLineOutput.h
@@ -0,0 +1,74 @@
+
+
+/****************************************************************************** 
+ * 
+ *  file:  CmdLineOutput.h
+ * 
+ *  Copyright (c) 2004, Michael E. Smoot
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+#ifndef TCLAP_CMDLINEOUTPUT_H
+#define TCLAP_CMDLINEOUTPUT_H
+
+#include <string>
+#include <vector>
+#include <list>
+#include <iostream>
+#include <iomanip>
+#include <algorithm>
+
+namespace TCLAP {
+
+class CmdLineInterface;
+class ArgException;
+
+/**
+ * The interface that any output object must implement.
+ */
+class CmdLineOutput 
+{
+
+	public:
+
+		/**
+		 * Virtual destructor.
+		 */
+		virtual ~CmdLineOutput() {}
+
+		/**
+		 * Generates some sort of output for the USAGE. 
+		 * \param c - The CmdLine object the output is generated for. 
+		 */
+		virtual void usage(CmdLineInterface& c)=0;
+
+		/**
+		 * Generates some sort of output for the version. 
+		 * \param c - The CmdLine object the output is generated for. 
+		 */
+		virtual void version(CmdLineInterface& c)=0;
+
+		/**
+		 * Generates some sort of output for a failure. 
+		 * \param c - The CmdLine object the output is generated for. 
+		 * \param e - The ArgException that caused the failure. 
+		 */
+		virtual void failure( CmdLineInterface& c, 
+						      ArgException& e )=0;
+
+};
+
+} //namespace TCLAP
+#endif 
diff --git a/pub/ThirdParty/tclap/Constraint.h b/pub/ThirdParty/tclap/Constraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..a92acf9a9a29e5b15f655b3d0caa6d280193f60d
--- /dev/null
+++ b/pub/ThirdParty/tclap/Constraint.h
@@ -0,0 +1,68 @@
+
+/******************************************************************************
+ *
+ *  file:  Constraint.h
+ *
+ *  Copyright (c) 2005, Michael E. Smoot
+ *  All rights reverved.
+ *
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ *  DEALINGS IN THE SOFTWARE.
+ *
+ *****************************************************************************/
+
+#ifndef TCLAP_CONSTRAINT_H
+#define TCLAP_CONSTRAINT_H
+
+#include <string>
+#include <vector>
+#include <list>
+#include <iostream>
+#include <iomanip>
+#include <algorithm>
+
+namespace TCLAP {
+
+/**
+ * The interface that defines the interaction between the Arg and Constraint.
+ */
+template<class T>
+class Constraint
+{
+
+	public:
+		/**
+		 * Returns a description of the Constraint.
+		 */
+		virtual std::string description() const =0;
+
+		/**
+		 * Returns the short ID for the Constraint.
+		 */
+		virtual std::string shortID() const =0;
+
+		/**
+		 * The method used to verify that the value parsed from the command
+		 * line meets the constraint.
+		 * \param value - The value that will be checked.
+		 */
+		virtual bool check(const T& value) const =0;
+
+		/**
+		 * Destructor.
+		 * Silences warnings about Constraint being a base class with virtual
+		 * functions but without a virtual destructor.
+		 */
+		virtual ~Constraint() { ; }
+};
+
+} //namespace TCLAP
+#endif
diff --git a/pub/ThirdParty/tclap/DocBookOutput.h b/pub/ThirdParty/tclap/DocBookOutput.h
new file mode 100644
index 0000000000000000000000000000000000000000..a42ca274dfbb4648adb62962773310e902151973
--- /dev/null
+++ b/pub/ThirdParty/tclap/DocBookOutput.h
@@ -0,0 +1,299 @@
+// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
+
+/****************************************************************************** 
+ * 
+ *  file:  DocBookOutput.h
+ * 
+ *  Copyright (c) 2004, Michael E. Smoot
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+#ifndef TCLAP_DOCBOOKOUTPUT_H
+#define TCLAP_DOCBOOKOUTPUT_H
+
+#include <string>
+#include <vector>
+#include <list>
+#include <iostream>
+#include <algorithm>
+
+#include <tclap/CmdLineInterface.h>
+#include <tclap/CmdLineOutput.h>
+#include <tclap/XorHandler.h>
+#include <tclap/Arg.h>
+
+namespace TCLAP {
+
+/**
+ * A class that generates DocBook output for usage() method for the 
+ * given CmdLine and its Args.
+ */
+class DocBookOutput : public CmdLineOutput
+{
+
+	public:
+
+		/**
+		 * Prints the usage to stdout.  Can be overridden to 
+		 * produce alternative behavior.
+		 * \param c - The CmdLine object the output is generated for. 
+		 */
+		virtual void usage(CmdLineInterface& c);
+
+		/**
+		 * Prints the version to stdout. Can be overridden 
+		 * to produce alternative behavior.
+		 * \param c - The CmdLine object the output is generated for. 
+		 */
+		virtual void version(CmdLineInterface& c);
+
+		/**
+		 * Prints (to stderr) an error message, short usage 
+		 * Can be overridden to produce alternative behavior.
+		 * \param c - The CmdLine object the output is generated for. 
+		 * \param e - The ArgException that caused the failure. 
+		 */
+		virtual void failure(CmdLineInterface& c, 
+						     ArgException& e );
+
+	protected:
+
+		/**
+		 * Substitutes the char r for string x in string s.
+		 * \param s - The string to operate on. 
+		 * \param r - The char to replace. 
+		 * \param x - What to replace r with. 
+		 */
+		void substituteSpecialChars( std::string& s, char r, std::string& x );
+		void removeChar( std::string& s, char r);
+		void basename( std::string& s );
+
+		void printShortArg(Arg* it);
+		void printLongArg(Arg* it);
+
+		char theDelimiter;
+};
+
+
+inline void DocBookOutput::version(CmdLineInterface& _cmd) 
+{ 
+	std::cout << _cmd.getVersion() << std::endl;
+}
+
+inline void DocBookOutput::usage(CmdLineInterface& _cmd ) 
+{
+	std::list<Arg*> argList = _cmd.getArgList();
+	std::string progName = _cmd.getProgramName();
+	std::string xversion = _cmd.getVersion();
+	theDelimiter = _cmd.getDelimiter();
+	XorHandler xorHandler = _cmd.getXorHandler();
+	std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
+	basename(progName);
+
+	std::cout << "<?xml version='1.0'?>" << std::endl;
+	std::cout << "<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\"" << std::endl;
+	std::cout << "\t\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\">" << std::endl << std::endl;
+
+	std::cout << "<refentry>" << std::endl;
+
+	std::cout << "<refmeta>" << std::endl;
+	std::cout << "<refentrytitle>" << progName << "</refentrytitle>" << std::endl;
+	std::cout << "<manvolnum>1</manvolnum>" << std::endl;
+	std::cout << "</refmeta>" << std::endl;
+
+	std::cout << "<refnamediv>" << std::endl;
+	std::cout << "<refname>" << progName << "</refname>" << std::endl;
+	std::cout << "<refpurpose>" << _cmd.getMessage() << "</refpurpose>" << std::endl;
+	std::cout << "</refnamediv>" << std::endl;
+
+	std::cout << "<refsynopsisdiv>" << std::endl;
+	std::cout << "<cmdsynopsis>" << std::endl;
+
+	std::cout << "<command>" << progName << "</command>" << std::endl;
+
+	// xor
+	for ( int i = 0; (unsigned int)i < xorList.size(); i++ )
+	{
+		std::cout << "<group choice='req'>" << std::endl;
+		for ( ArgVectorIterator it = xorList[i].begin(); 
+						it != xorList[i].end(); it++ )
+			printShortArg((*it));
+
+		std::cout << "</group>" << std::endl;
+	}
+	
+	// rest of args
+	for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
+		if ( !xorHandler.contains( (*it) ) )
+			printShortArg((*it));
+
+ 	std::cout << "</cmdsynopsis>" << std::endl;
+	std::cout << "</refsynopsisdiv>" << std::endl;
+
+	std::cout << "<refsect1>" << std::endl;
+	std::cout << "<title>Description</title>" << std::endl;
+	std::cout << "<para>" << std::endl;
+	std::cout << _cmd.getMessage() << std::endl; 
+	std::cout << "</para>" << std::endl;
+	std::cout << "</refsect1>" << std::endl;
+
+	std::cout << "<refsect1>" << std::endl;
+	std::cout << "<title>Options</title>" << std::endl;
+
+	std::cout << "<variablelist>" << std::endl;
+	
+	for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
+		printLongArg((*it));
+
+	std::cout << "</variablelist>" << std::endl;
+	std::cout << "</refsect1>" << std::endl;
+
+	std::cout << "<refsect1>" << std::endl;
+	std::cout << "<title>Version</title>" << std::endl;
+	std::cout << "<para>" << std::endl;
+	std::cout << xversion << std::endl; 
+	std::cout << "</para>" << std::endl;
+	std::cout << "</refsect1>" << std::endl;
+	
+	std::cout << "</refentry>" << std::endl;
+
+}
+
+inline void DocBookOutput::failure( CmdLineInterface& _cmd,
+				    ArgException& e ) 
+{ 
+	static_cast<void>(_cmd); // unused
+	std::cout << e.what() << std::endl;
+	throw ExitException(1);
+}
+
+inline void DocBookOutput::substituteSpecialChars( std::string& s,
+				                                   char r,
+												   std::string& x )
+{
+	size_t p;
+	while ( (p = s.find_first_of(r)) != std::string::npos )
+	{
+		s.erase(p,1);
+		s.insert(p,x);
+	}
+}
+
+inline void DocBookOutput::removeChar( std::string& s, char r)
+{
+	size_t p;
+	while ( (p = s.find_first_of(r)) != std::string::npos )
+	{
+		s.erase(p,1);
+	}
+}
+
+inline void DocBookOutput::basename( std::string& s )
+{
+	size_t p = s.find_last_of('/');
+	if ( p != std::string::npos )
+	{
+		s.erase(0, p + 1);
+	}
+}
+
+inline void DocBookOutput::printShortArg(Arg* a)
+{
+	std::string lt = "&lt;"; 
+	std::string gt = "&gt;"; 
+
+	std::string id = a->shortID();
+	substituteSpecialChars(id,'<',lt);
+	substituteSpecialChars(id,'>',gt);
+	removeChar(id,'[');
+	removeChar(id,']');
+	
+	std::string choice = "opt";
+	if ( a->isRequired() )
+		choice = "plain";
+
+	std::cout << "<arg choice='" << choice << '\'';
+	if ( a->acceptsMultipleValues() )
+		std::cout << " rep='repeat'";
+
+
+	std::cout << '>';
+	if ( !a->getFlag().empty() )
+		std::cout << a->flagStartChar() << a->getFlag();
+	else
+		std::cout << a->nameStartString() << a->getName();
+	if ( a->isValueRequired() )
+	{
+		std::string arg = a->shortID();
+		removeChar(arg,'[');
+		removeChar(arg,']');
+		removeChar(arg,'<');
+		removeChar(arg,'>');
+		arg.erase(0, arg.find_last_of(theDelimiter) + 1);
+		std::cout << theDelimiter;
+		std::cout << "<replaceable>" << arg << "</replaceable>";
+	}
+	std::cout << "</arg>" << std::endl;
+
+}
+
+inline void DocBookOutput::printLongArg(Arg* a)
+{
+	std::string lt = "&lt;"; 
+	std::string gt = "&gt;"; 
+
+	std::string desc = a->getDescription();
+	substituteSpecialChars(desc,'<',lt);
+	substituteSpecialChars(desc,'>',gt);
+
+	std::cout << "<varlistentry>" << std::endl;
+
+	if ( !a->getFlag().empty() )
+	{
+		std::cout << "<term>" << std::endl;
+		std::cout << "<option>";
+		std::cout << a->flagStartChar() << a->getFlag();
+		std::cout << "</option>" << std::endl;
+		std::cout << "</term>" << std::endl;
+	}
+
+	std::cout << "<term>" << std::endl;
+	std::cout << "<option>";
+	std::cout << a->nameStartString() << a->getName();
+	if ( a->isValueRequired() )
+	{
+		std::string arg = a->shortID();
+		removeChar(arg,'[');
+		removeChar(arg,']');
+		removeChar(arg,'<');
+		removeChar(arg,'>');
+		arg.erase(0, arg.find_last_of(theDelimiter) + 1);
+		std::cout << theDelimiter;
+		std::cout << "<replaceable>" << arg << "</replaceable>";
+	}
+	std::cout << "</option>" << std::endl;
+	std::cout << "</term>" << std::endl;
+
+	std::cout << "<listitem>" << std::endl;
+	std::cout << "<para>" << std::endl;
+	std::cout << desc << std::endl;
+	std::cout << "</para>" << std::endl;
+	std::cout << "</listitem>" << std::endl;
+
+	std::cout << "</varlistentry>" << std::endl;
+}
+
+} //namespace TCLAP
+#endif 
diff --git a/pub/ThirdParty/tclap/HelpVisitor.h b/pub/ThirdParty/tclap/HelpVisitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..cc3bd070cad5903ea67b15ae38ed5d605c5ac694
--- /dev/null
+++ b/pub/ThirdParty/tclap/HelpVisitor.h
@@ -0,0 +1,76 @@
+
+/****************************************************************************** 
+ * 
+ *  file:  HelpVisitor.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+#ifndef TCLAP_HELP_VISITOR_H
+#define TCLAP_HELP_VISITOR_H
+
+#include <tclap/CmdLineInterface.h>
+#include <tclap/CmdLineOutput.h>
+#include <tclap/Visitor.h>
+
+namespace TCLAP {
+
+/**
+ * A Visitor object that calls the usage method of the given CmdLineOutput
+ * object for the specified CmdLine object.
+ */
+class HelpVisitor: public Visitor
+{
+	private:
+		/**
+		 * Prevent accidental copying.
+		 */
+		HelpVisitor(const HelpVisitor& rhs);
+		HelpVisitor& operator=(const HelpVisitor& rhs);
+
+	protected:
+
+		/**
+		 * The CmdLine the output will be generated for. 
+		 */
+		CmdLineInterface* _cmd;
+
+		/**
+		 * The output object. 
+		 */
+		CmdLineOutput** _out;
+
+	public:
+
+		/**
+		 * Constructor.
+		 * \param cmd - The CmdLine the output will be generated for.
+		 * \param out - The type of output. 
+		 */
+		HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out) 
+				: Visitor(), _cmd( cmd ), _out( out ) { }
+
+		/**
+		 * Calls the usage method of the CmdLineOutput for the 
+		 * specified CmdLine.
+		 */
+		void visit() { (*_out)->usage(*_cmd); throw ExitException(0); }
+		
+};
+
+}
+
+#endif
diff --git a/pub/ThirdParty/tclap/IgnoreRestVisitor.h b/pub/ThirdParty/tclap/IgnoreRestVisitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..e328649e511eb737e098e411e17552dbc3da1b73
--- /dev/null
+++ b/pub/ThirdParty/tclap/IgnoreRestVisitor.h
@@ -0,0 +1,52 @@
+
+/****************************************************************************** 
+ * 
+ *  file:  IgnoreRestVisitor.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+
+#ifndef TCLAP_IGNORE_REST_VISITOR_H
+#define TCLAP_IGNORE_REST_VISITOR_H
+
+#include <tclap/Visitor.h>
+#include <tclap/Arg.h>
+
+namespace TCLAP {
+
+/**
+ * A Vistor that tells the CmdLine to begin ignoring arguments after
+ * this one is parsed.
+ */
+class IgnoreRestVisitor: public Visitor
+{
+	public:
+
+		/**
+		 * Constructor.
+		 */
+		IgnoreRestVisitor() : Visitor() {}
+
+		/**
+		 * Sets Arg::_ignoreRest.
+		 */
+		void visit() { Arg::beginIgnoring();  }
+};
+
+}
+
+#endif
diff --git a/pub/ThirdParty/tclap/MultiArg.h b/pub/ThirdParty/tclap/MultiArg.h
new file mode 100644
index 0000000000000000000000000000000000000000..34bb2d7895269cb676ff06b792bb914c79b5cc91
--- /dev/null
+++ b/pub/ThirdParty/tclap/MultiArg.h
@@ -0,0 +1,433 @@
+/****************************************************************************** 
+ * 
+ *  file:  MultiArg.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/
+
+
+#ifndef TCLAP_MULTIPLE_ARGUMENT_H
+#define TCLAP_MULTIPLE_ARGUMENT_H
+
+#include <string>
+#include <vector>
+
+#include <tclap/Arg.h>
+#include <tclap/Constraint.h>
+
+namespace TCLAP {
+/**
+ * An argument that allows multiple values of type T to be specified.  Very
+ * similar to a ValueArg, except a vector of values will be returned
+ * instead of just one.
+ */
+template<class T>
+class MultiArg : public Arg
+{
+public:
+	typedef std::vector<T> container_type;	
+	typedef typename container_type::iterator iterator;
+	typedef typename container_type::const_iterator const_iterator;
+
+protected:
+
+	/**
+	 * The list of values parsed from the CmdLine.
+	 */
+	std::vector<T> _values;
+
+	/**
+	 * The description of type T to be used in the usage.
+	 */
+	std::string _typeDesc;
+
+	/**
+	 * A list of constraint on this Arg. 
+	 */
+	Constraint<T>* _constraint;
+
+	/**
+	 * Extracts the value from the string.
+	 * Attempts to parse string as type T, if this fails an exception
+	 * is thrown.
+	 * \param val - The string to be read.
+	 */
+	void _extractValue( const std::string& val );
+
+	/**
+	 * Used by XorHandler to decide whether to keep parsing for this arg.
+	 */
+	bool _allowMore;
+
+public:
+
+	/**
+	 * Constructor.
+	 * \param flag - The one character flag that identifies this
+	 * argument on the command line.
+	 * \param name - A one word name for the argument.  Can be
+	 * used as a long flag on the command line.
+	 * \param desc - A description of what the argument is for or
+	 * does.
+	 * \param req - Whether the argument is required on the command
+	 * line.
+	 * \param typeDesc - A short, human readable description of the
+	 * type that this object expects.  This is used in the generation
+	 * of the USAGE statement.  The goal is to be helpful to the end user
+	 * of the program.
+	 * \param v - An optional visitor.  You probably should not
+	 * use this unless you have a very good reason.
+	 */
+	MultiArg( const std::string& flag,
+                  const std::string& name,
+                  const std::string& desc,
+                  bool req,
+                  const std::string& typeDesc,
+                  Visitor* v = NULL);
+
+	/**
+	 * Constructor.
+	 * \param flag - The one character flag that identifies this
+	 * argument on the command line.
+	 * \param name - A one word name for the argument.  Can be
+	 * used as a long flag on the command line.
+	 * \param desc - A description of what the argument is for or
+	 * does.
+	 * \param req - Whether the argument is required on the command
+	 * line.
+	 * \param typeDesc - A short, human readable description of the
+	 * type that this object expects.  This is used in the generation
+	 * of the USAGE statement.  The goal is to be helpful to the end user
+	 * of the program.
+	 * \param parser - A CmdLine parser object to add this Arg to
+	 * \param v - An optional visitor.  You probably should not
+	 * use this unless you have a very good reason.
+	 */
+	MultiArg( const std::string& flag, 
+                  const std::string& name,
+                  const std::string& desc,
+                  bool req,
+                  const std::string& typeDesc,
+                  CmdLineInterface& parser,
+                  Visitor* v = NULL );
+
+	/**
+	 * Constructor.
+	 * \param flag - The one character flag that identifies this
+	 * argument on the command line.
+	 * \param name - A one word name for the argument.  Can be
+	 * used as a long flag on the command line.
+	 * \param desc - A description of what the argument is for or
+	 * does.
+	 * \param req - Whether the argument is required on the command
+	 * line.
+	 * \param constraint - A pointer to a Constraint object used
+	 * to constrain this Arg.
+	 * \param v - An optional visitor.  You probably should not
+	 * use this unless you have a very good reason.
+	 */
+	MultiArg( const std::string& flag,
+                  const std::string& name,
+                  const std::string& desc,
+                  bool req,
+                  Constraint<T>* constraint,
+                  Visitor* v = NULL );
+		  
+	/**
+	 * Constructor.
+	 * \param flag - The one character flag that identifies this
+	 * argument on the command line.
+	 * \param name - A one word name for the argument.  Can be
+	 * used as a long flag on the command line.
+	 * \param desc - A description of what the argument is for or
+	 * does.
+	 * \param req - Whether the argument is required on the command
+	 * line.
+	 * \param constraint - A pointer to a Constraint object used
+	 * to constrain this Arg.
+	 * \param parser - A CmdLine parser object to add this Arg to
+	 * \param v - An optional visitor.  You probably should not
+	 * use this unless you have a very good reason.
+	 */
+	MultiArg( const std::string& flag, 
+                  const std::string& name,
+                  const std::string& desc,
+                  bool req,
+                  Constraint<T>* constraint,
+                  CmdLineInterface& parser,
+                  Visitor* v = NULL );
+		  
+	/**
+	 * Handles the processing of the argument.
+	 * This re-implements the Arg version of this method to set the
+	 * _value of the argument appropriately.  It knows the difference
+	 * between labeled and unlabeled.
+	 * \param i - Pointer the the current argument in the list.
+	 * \param args - Mutable list of strings. Passed from main().
+	 */
+	virtual bool processArg(int* i, std::vector<std::string>& args); 
+
+	/**
+	 * Returns a vector of type T containing the values parsed from
+	 * the command line.
+	 */
+	const std::vector<T>& getValue();
+
+	/**
+	 * Returns an iterator over the values parsed from the command
+	 * line.
+	 */
+	const_iterator begin() const { return _values.begin(); }
+
+	/**
+	 * Returns the end of the values parsed from the command
+	 * line.
+	 */
+	const_iterator end() const { return _values.end(); }
+
+	/**
+	 * Returns the a short id string.  Used in the usage. 
+	 * \param val - value to be used.
+	 */
+	virtual std::string shortID(const std::string& val="val") const;
+
+	/**
+	 * Returns the a long id string.  Used in the usage. 
+	 * \param val - value to be used.
+	 */
+	virtual std::string longID(const std::string& val="val") const;
+
+	/**
+	 * Once we've matched the first value, then the arg is no longer
+	 * required.
+	 */
+	virtual bool isRequired() const;
+
+	virtual bool allowMore();
+	
+	virtual void reset();
+
+private:
+	/**
+	 * Prevent accidental copying
+	 */
+	MultiArg<T>(const MultiArg<T>& rhs);
+	MultiArg<T>& operator=(const MultiArg<T>& rhs);
+
+};
+
+template<class T>
+MultiArg<T>::MultiArg(const std::string& flag, 
+                      const std::string& name,
+                      const std::string& desc,
+                      bool req,
+                      const std::string& typeDesc,
+                      Visitor* v) :
+   Arg( flag, name, desc, req, true, v ),
+  _values(std::vector<T>()),
+  _typeDesc( typeDesc ),
+  _constraint( NULL ),
+  _allowMore(false)
+{ 
+	_acceptsMultipleValues = true;
+}
+
+template<class T>
+MultiArg<T>::MultiArg(const std::string& flag, 
+                      const std::string& name,
+                      const std::string& desc,
+                      bool req,
+                      const std::string& typeDesc,
+                      CmdLineInterface& parser,
+                      Visitor* v)
+: Arg( flag, name, desc, req, true, v ),
+  _values(std::vector<T>()),
+  _typeDesc( typeDesc ),
+  _constraint( NULL ),
+  _allowMore(false)
+{ 
+	parser.add( this );
+	_acceptsMultipleValues = true;
+}
+
+/**
+ *
+ */
+template<class T>
+MultiArg<T>::MultiArg(const std::string& flag, 
+                      const std::string& name,
+                      const std::string& desc,
+                      bool req,
+                      Constraint<T>* constraint,
+                      Visitor* v)
+: Arg( flag, name, desc, req, true, v ),
+  _values(std::vector<T>()),
+  _typeDesc( constraint->shortID() ),
+  _constraint( constraint ),
+  _allowMore(false)
+{ 
+	_acceptsMultipleValues = true;
+}
+
+template<class T>
+MultiArg<T>::MultiArg(const std::string& flag, 
+                      const std::string& name,
+                      const std::string& desc,
+                      bool req,
+                      Constraint<T>* constraint,
+                      CmdLineInterface& parser,
+                      Visitor* v)
+: Arg( flag, name, desc, req, true, v ),
+  _values(std::vector<T>()),
+  _typeDesc( constraint->shortID() ),
+  _constraint( constraint ),
+  _allowMore(false)
+{ 
+	parser.add( this );
+	_acceptsMultipleValues = true;
+}
+
+template<class T>
+const std::vector<T>& MultiArg<T>::getValue() { return _values; }
+
+template<class T>
+bool MultiArg<T>::processArg(int *i, std::vector<std::string>& args) 
+{
+ 	if ( _ignoreable && Arg::ignoreRest() )
+		return false;
+
+	if ( _hasBlanks( args[*i] ) )
+		return false;
+
+	std::string flag = args[*i];
+	std::string value = "";
+
+   	trimFlag( flag, value );
+
+   	if ( argMatches( flag ) )
+   	{
+   		if ( Arg::delimiter() != ' ' && value == "" )
+			throw( ArgParseException( 
+			           "Couldn't find delimiter for this argument!",
+					   toString() ) );
+
+		// always take the first one, regardless of start string
+		if ( value == "" )
+		{
+			(*i)++;
+			if ( static_cast<unsigned int>(*i) < args.size() )
+				_extractValue( args[*i] );
+			else
+				throw( ArgParseException("Missing a value for this argument!",
+                                         toString() ) );
+		} 
+		else
+			_extractValue( value );
+
+		/*
+		// continuing taking the args until we hit one with a start string 
+		while ( (unsigned int)(*i)+1 < args.size() &&
+				args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
+		        args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) 
+				_extractValue( args[++(*i)] );
+		*/
+
+		_alreadySet = true;
+		_checkWithVisitor();
+
+		return true;
+	}
+	else
+		return false;
+}
+
+/**
+ *
+ */
+template<class T>
+std::string MultiArg<T>::shortID(const std::string& val) const
+{
+	static_cast<void>(val); // Ignore input, don't warn
+	return Arg::shortID(_typeDesc) + " ... ";
+}
+
+/**
+ *
+ */
+template<class T>
+std::string MultiArg<T>::longID(const std::string& val) const
+{
+	static_cast<void>(val); // Ignore input, don't warn
+	return Arg::longID(_typeDesc) + "  (accepted multiple times)";
+}
+
+/**
+ * Once we've matched the first value, then the arg is no longer
+ * required.
+ */
+template<class T>
+bool MultiArg<T>::isRequired() const
+{
+	if ( _required )
+	{
+		if ( _values.size() > 1 )
+			return false;
+		else
+			return true;
+   	}
+   	else
+		return false;
+
+}
+
+template<class T>
+void MultiArg<T>::_extractValue( const std::string& val ) 
+{
+    try {
+	T tmp;
+	ExtractValue(tmp, val, typename ArgTraits<T>::ValueCategory());
+	_values.push_back(tmp);
+    } catch( ArgParseException &e) {
+	throw ArgParseException(e.error(), toString());
+    }
+
+    if ( _constraint != NULL )
+	if ( ! _constraint->check( _values.back() ) )
+	    throw( CmdLineParseException( "Value '" + val +
+					  "' does not meet constraint: " +
+					  _constraint->description(), 
+					  toString() ) );
+}
+		
+template<class T>
+bool MultiArg<T>::allowMore()
+{
+	bool am = _allowMore;
+	_allowMore = true;
+	return am;
+}
+
+template<class T>
+void MultiArg<T>::reset()
+{
+	Arg::reset();
+	_values.clear();
+}
+
+} // namespace TCLAP
+
+#endif
diff --git a/pub/ThirdParty/tclap/MultiSwitchArg.h b/pub/ThirdParty/tclap/MultiSwitchArg.h
new file mode 100644
index 0000000000000000000000000000000000000000..8820b641626ed8dd28fb000211076e37d14f6c33
--- /dev/null
+++ b/pub/ThirdParty/tclap/MultiSwitchArg.h
@@ -0,0 +1,216 @@
+
+/****************************************************************************** 
+*
+*  file:  MultiSwitchArg.h
+*
+*  Copyright (c) 2003, Michael E. Smoot .
+*  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
+*  Copyright (c) 2005, Michael E. Smoot, Daniel Aarno, Erik Zeek.
+*  All rights reverved.
+*
+*  See the file COPYING in the top directory of this distribution for
+*  more information.
+*
+*  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
+*  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+*  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+*  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+*  DEALINGS IN THE SOFTWARE.
+*
+*****************************************************************************/
+
+
+#ifndef TCLAP_MULTI_SWITCH_ARG_H
+#define TCLAP_MULTI_SWITCH_ARG_H
+
+#include <string>
+#include <vector>
+
+#include <tclap/SwitchArg.h>
+
+namespace TCLAP {
+
+/**
+* A multiple switch argument.  If the switch is set on the command line, then
+* the getValue method will return the number of times the switch appears.
+*/
+class MultiSwitchArg : public SwitchArg
+{
+	protected:
+
+		/**
+		 * The value of the switch.
+		 */
+		int _value;
+
+		/**
+		 * Used to support the reset() method so that ValueArg can be
+		 * reset to their constructed value.
+		 */
+		int _default;
+
+	public:
+
+		/**
+		 * MultiSwitchArg constructor.
+		 * \param flag - The one character flag that identifies this
+		 * argument on the command line.
+		 * \param name - A one word name for the argument.  Can be
+		 * used as a long flag on the command line.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param init - Optional. The initial/default value of this Arg. 
+		 * Defaults to 0.
+		 * \param v - An optional visitor.  You probably should not
+		 * use this unless you have a very good reason.
+		 */
+		MultiSwitchArg(const std::string& flag, 
+				const std::string& name,
+				const std::string& desc,
+				int init = 0,
+				Visitor* v = NULL);
+
+
+		/**
+		 * MultiSwitchArg constructor.
+		 * \param flag - The one character flag that identifies this
+		 * argument on the command line.
+		 * \param name - A one word name for the argument.  Can be
+		 * used as a long flag on the command line.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param parser - A CmdLine parser object to add this Arg to
+		 * \param init - Optional. The initial/default value of this Arg. 
+		 * Defaults to 0.
+		 * \param v - An optional visitor.  You probably should not
+		 * use this unless you have a very good reason.
+		 */
+		MultiSwitchArg(const std::string& flag, 
+				const std::string& name,
+				const std::string& desc,
+				CmdLineInterface& parser,
+				int init = 0,
+				Visitor* v = NULL);
+
+
+		/**
+		 * Handles the processing of the argument.
+		 * This re-implements the SwitchArg version of this method to set the
+		 * _value of the argument appropriately.
+		 * \param i - Pointer the the current argument in the list.
+		 * \param args - Mutable list of strings. Passed
+		 * in from main().
+		 */
+		virtual bool processArg(int* i, std::vector<std::string>& args); 
+
+		/**
+		 * Returns int, the number of times the switch has been set.
+		 */
+		int getValue();
+
+		/**
+		 * Returns the shortID for this Arg.
+		 */
+		std::string shortID(const std::string& val) const;
+
+		/**
+		 * Returns the longID for this Arg.
+		 */
+		std::string longID(const std::string& val) const;
+		
+		void reset();
+
+};
+
+//////////////////////////////////////////////////////////////////////
+//BEGIN MultiSwitchArg.cpp
+//////////////////////////////////////////////////////////////////////
+inline MultiSwitchArg::MultiSwitchArg(const std::string& flag,
+					const std::string& name,
+					const std::string& desc,
+					int init,
+					Visitor* v )
+: SwitchArg(flag, name, desc, false, v),
+_value( init ),
+_default( init )
+{ }
+
+inline MultiSwitchArg::MultiSwitchArg(const std::string& flag,
+					const std::string& name, 
+					const std::string& desc, 
+					CmdLineInterface& parser,
+					int init,
+					Visitor* v )
+: SwitchArg(flag, name, desc, false, v),
+_value( init ),
+_default( init )
+{ 
+	parser.add( this );
+}
+
+inline int MultiSwitchArg::getValue() { return _value; }
+
+inline bool MultiSwitchArg::processArg(int *i, std::vector<std::string>& args)
+{
+	if ( _ignoreable && Arg::ignoreRest() )
+		return false;
+
+	if ( argMatches( args[*i] ))
+	{
+		// so the isSet() method will work
+		_alreadySet = true;
+
+		// Matched argument: increment value.
+		++_value;
+
+		_checkWithVisitor();
+
+		return true;
+	}
+	else if ( combinedSwitchesMatch( args[*i] ) )
+	{
+		// so the isSet() method will work
+		_alreadySet = true;
+
+		// Matched argument: increment value.
+		++_value;
+
+		// Check for more in argument and increment value.
+		while ( combinedSwitchesMatch( args[*i] ) ) 
+			++_value;
+
+		_checkWithVisitor();
+
+		return false;
+	}
+	else
+		return false;
+}
+
+inline std::string 
+MultiSwitchArg::shortID(const std::string& val) const
+{
+	return Arg::shortID(val) + " ... ";
+}
+
+inline std::string 
+MultiSwitchArg::longID(const std::string& val) const
+{
+	return Arg::longID(val) + "  (accepted multiple times)";
+}
+
+inline void
+MultiSwitchArg::reset()
+{
+	MultiSwitchArg::_value = MultiSwitchArg::_default;
+}
+
+//////////////////////////////////////////////////////////////////////
+//END MultiSwitchArg.cpp
+//////////////////////////////////////////////////////////////////////
+
+} //namespace TCLAP
+
+#endif
diff --git a/pub/ThirdParty/tclap/OptionalUnlabeledTracker.h b/pub/ThirdParty/tclap/OptionalUnlabeledTracker.h
new file mode 100644
index 0000000000000000000000000000000000000000..8174c5f624b8e208abda65a84aadfbb2da83b10e
--- /dev/null
+++ b/pub/ThirdParty/tclap/OptionalUnlabeledTracker.h
@@ -0,0 +1,62 @@
+
+
+/****************************************************************************** 
+ * 
+ *  file:  OptionalUnlabeledTracker.h
+ * 
+ *  Copyright (c) 2005, Michael E. Smoot .
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+
+#ifndef TCLAP_OPTIONAL_UNLABELED_TRACKER_H
+#define TCLAP_OPTIONAL_UNLABELED_TRACKER_H
+
+#include <string>
+
+namespace TCLAP {
+
+class OptionalUnlabeledTracker
+{
+
+	public:
+
+		static void check( bool req, const std::string& argName );
+
+		static void gotOptional() { alreadyOptionalRef() = true; }
+
+		static bool& alreadyOptional() { return alreadyOptionalRef(); } 
+
+	private:
+
+		static bool& alreadyOptionalRef() { static bool ct = false; return ct; }
+};
+
+
+inline void OptionalUnlabeledTracker::check( bool req, const std::string& argName )
+{
+    if ( OptionalUnlabeledTracker::alreadyOptional() )
+        throw( SpecificationException(
+	"You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg",
+	                argName ) );
+
+    if ( !req )
+        OptionalUnlabeledTracker::gotOptional();
+}
+
+
+} // namespace TCLAP
+
+#endif
diff --git a/pub/ThirdParty/tclap/StandardTraits.h b/pub/ThirdParty/tclap/StandardTraits.h
new file mode 100644
index 0000000000000000000000000000000000000000..46d7f6fafdeda744890e223c13ef3630c9784e72
--- /dev/null
+++ b/pub/ThirdParty/tclap/StandardTraits.h
@@ -0,0 +1,208 @@
+// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
+
+/******************************************************************************
+ *
+ *  file:  StandardTraits.h
+ *
+ *  Copyright (c) 2007, Daniel Aarno, Michael E. Smoot .
+ *  All rights reverved.
+ *
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ *  DEALINGS IN THE SOFTWARE.
+ *
+ *****************************************************************************/
+
+// This is an internal tclap file, you should probably not have to
+// include this directly
+
+#ifndef TCLAP_STANDARD_TRAITS_H
+#define TCLAP_STANDARD_TRAITS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h> // To check for long long
+#endif
+
+// If Microsoft has already typedef'd wchar_t as an unsigned 
+// short, then compiles will break because it's as if we're
+// creating ArgTraits twice for unsigned short. Thus...
+#ifdef _MSC_VER
+#ifndef _NATIVE_WCHAR_T_DEFINED
+#define TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS
+#endif
+#endif
+
+namespace TCLAP {
+
+// ======================================================================
+// Integer types
+// ======================================================================
+
+/**
+ * longs have value-like semantics.
+ */
+template<>
+struct ArgTraits<long> {
+    typedef ValueLike ValueCategory;
+};
+
+/**
+ * ints have value-like semantics.
+ */
+template<>
+struct ArgTraits<int> {
+    typedef ValueLike ValueCategory;
+};
+
+/**
+ * shorts have value-like semantics.
+ */
+template<>
+struct ArgTraits<short> {
+    typedef ValueLike ValueCategory;
+};
+
+/**
+ * chars have value-like semantics.
+ */
+template<>
+struct ArgTraits<char> {
+    typedef ValueLike ValueCategory;
+};
+
+#ifdef HAVE_LONG_LONG
+/**
+ * long longs have value-like semantics.
+ */
+template<>
+struct ArgTraits<long long> {
+    typedef ValueLike ValueCategory;
+};
+#endif
+
+// ======================================================================
+// Unsigned integer types
+// ======================================================================
+
+/**
+ * unsigned longs have value-like semantics.
+ */
+template<>
+struct ArgTraits<unsigned long> {
+    typedef ValueLike ValueCategory;
+};
+
+/**
+ * unsigned ints have value-like semantics.
+ */
+template<>
+struct ArgTraits<unsigned int> {
+    typedef ValueLike ValueCategory;
+};
+
+/**
+ * unsigned shorts have value-like semantics.
+ */
+template<>
+struct ArgTraits<unsigned short> {
+    typedef ValueLike ValueCategory;
+};
+
+/**
+ * unsigned chars have value-like semantics.
+ */
+template<>
+struct ArgTraits<unsigned char> {
+    typedef ValueLike ValueCategory;
+};
+
+// Microsoft implements size_t awkwardly. 
+#if defined(_MSC_VER) && defined(_M_X64)
+/**
+ * size_ts have value-like semantics.
+ */
+template<>
+struct ArgTraits<size_t> {
+    typedef ValueLike ValueCategory;
+};
+#endif
+
+
+#ifdef HAVE_LONG_LONG
+/**
+ * unsigned long longs have value-like semantics.
+ */
+template<>
+struct ArgTraits<unsigned long long> {
+    typedef ValueLike ValueCategory;
+};
+#endif
+
+// ======================================================================
+// Float types
+// ======================================================================
+
+/**
+ * floats have value-like semantics.
+ */
+template<>
+struct ArgTraits<float> {
+    typedef ValueLike ValueCategory;
+};
+
+/**
+ * doubles have value-like semantics.
+ */
+template<>
+struct ArgTraits<double> {
+    typedef ValueLike ValueCategory;
+};
+
+// ======================================================================
+// Other types
+// ======================================================================
+
+/**
+ * bools have value-like semantics.
+ */
+template<>
+struct ArgTraits<bool> {
+    typedef ValueLike ValueCategory;
+};
+
+
+/**
+ * wchar_ts have value-like semantics.
+ */
+#ifndef TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS
+template<>
+struct ArgTraits<wchar_t> {
+    typedef ValueLike ValueCategory;
+};
+#endif
+
+/**
+ * Strings have string like argument traits.
+ */
+template<>
+struct ArgTraits<std::string> {
+    typedef StringLike ValueCategory;
+};
+
+template<typename T>
+void SetString(T &dst, const std::string &src)
+{
+    dst = src;
+}
+
+} // namespace
+
+#endif
+
diff --git a/pub/ThirdParty/tclap/StdOutput.h b/pub/ThirdParty/tclap/StdOutput.h
new file mode 100644
index 0000000000000000000000000000000000000000..35f7b99b2ccf4b626fb9926f167a34ce5a371e0a
--- /dev/null
+++ b/pub/ThirdParty/tclap/StdOutput.h
@@ -0,0 +1,298 @@
+// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
+
+/****************************************************************************** 
+ * 
+ *  file:  StdOutput.h
+ * 
+ *  Copyright (c) 2004, Michael E. Smoot
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+#ifndef TCLAP_STDCMDLINEOUTPUT_H
+#define TCLAP_STDCMDLINEOUTPUT_H
+
+#include <string>
+#include <vector>
+#include <list>
+#include <iostream>
+#include <algorithm>
+
+#include <tclap/CmdLineInterface.h>
+#include <tclap/CmdLineOutput.h>
+#include <tclap/XorHandler.h>
+#include <tclap/Arg.h>
+
+namespace TCLAP {
+
+/**
+ * A class that isolates any output from the CmdLine object so that it
+ * may be easily modified.
+ */
+class StdOutput : public CmdLineOutput
+{
+
+	public:
+
+		/**
+		 * Prints the usage to stdout.  Can be overridden to 
+		 * produce alternative behavior.
+		 * \param c - The CmdLine object the output is generated for. 
+		 */
+		virtual void usage(CmdLineInterface& c);
+
+		/**
+		 * Prints the version to stdout. Can be overridden 
+		 * to produce alternative behavior.
+		 * \param c - The CmdLine object the output is generated for. 
+		 */
+		virtual void version(CmdLineInterface& c);
+
+		/**
+		 * Prints (to stderr) an error message, short usage 
+		 * Can be overridden to produce alternative behavior.
+		 * \param c - The CmdLine object the output is generated for. 
+		 * \param e - The ArgException that caused the failure. 
+		 */
+		virtual void failure(CmdLineInterface& c, 
+				     ArgException& e );
+
+	protected:
+
+        /**
+         * Writes a brief usage message with short args.
+		 * \param c - The CmdLine object the output is generated for. 
+         * \param os - The stream to write the message to.
+         */
+        void _shortUsage( CmdLineInterface& c, std::ostream& os ) const;
+
+        /**
+		 * Writes a longer usage message with long and short args, 
+		 * provides descriptions and prints message.
+		 * \param c - The CmdLine object the output is generated for. 
+		 * \param os - The stream to write the message to.
+		 */
+		void _longUsage( CmdLineInterface& c, std::ostream& os ) const;
+
+		/**
+		 * This function inserts line breaks and indents long strings 
+		 * according the  params input. It will only break lines at spaces, 
+		 * commas and pipes.
+		 * \param os - The stream to be printed to.
+		 * \param s - The string to be printed.
+		 * \param maxWidth - The maxWidth allowed for the output line. 
+		 * \param indentSpaces - The number of spaces to indent the first line. 
+		 * \param secondLineOffset - The number of spaces to indent the second
+		 * and all subsequent lines in addition to indentSpaces.
+		 */
+		void spacePrint( std::ostream& os, 
+						 const std::string& s, 
+						 int maxWidth, 
+						 int indentSpaces, 
+						 int secondLineOffset ) const;
+
+};
+
+
+inline void StdOutput::version(CmdLineInterface& _cmd) 
+{
+	std::string progName = _cmd.getProgramName();
+	std::string xversion = _cmd.getVersion();
+
+	std::cout << std::endl << progName << "  version: " 
+			  << xversion << std::endl << std::endl;
+}
+
+inline void StdOutput::usage(CmdLineInterface& _cmd ) 
+{
+	std::cout << std::endl << "USAGE: " << std::endl << std::endl; 
+
+	_shortUsage( _cmd, std::cout );
+
+	std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl;
+
+	_longUsage( _cmd, std::cout );
+
+	std::cout << std::endl; 
+
+}
+
+inline void StdOutput::failure( CmdLineInterface& _cmd,
+								ArgException& e ) 
+{
+	std::string progName = _cmd.getProgramName();
+
+	std::cerr << "PARSE ERROR: " << e.argId() << std::endl
+		      << "             " << e.error() << std::endl << std::endl;
+
+	if ( _cmd.hasHelpAndVersion() )
+		{
+			std::cerr << "Brief USAGE: " << std::endl;
+
+			_shortUsage( _cmd, std::cerr );	
+
+			std::cerr << std::endl << "For complete USAGE and HELP type: " 
+					  << std::endl << "   " << progName << " --help" 
+					  << std::endl << std::endl;
+		}
+	else
+		usage(_cmd);
+
+	throw ExitException(1);
+}
+
+inline void 
+StdOutput::_shortUsage( CmdLineInterface& _cmd, 
+						std::ostream& os ) const
+{
+	std::list<Arg*> argList = _cmd.getArgList();
+	std::string progName = _cmd.getProgramName();
+	XorHandler xorHandler = _cmd.getXorHandler();
+	std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
+
+	std::string s = progName + " ";
+
+	// first the xor
+	for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
+		{
+			s += " {";
+			for ( ArgVectorIterator it = xorList[i].begin(); 
+				  it != xorList[i].end(); it++ )
+				s += (*it)->shortID() + "|";
+
+			s[s.length()-1] = '}';
+		}
+
+	// then the rest
+	for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
+		if ( !xorHandler.contains( (*it) ) )
+			s += " " + (*it)->shortID();
+
+	// if the program name is too long, then adjust the second line offset 
+	int secondLineOffset = static_cast<int>(progName.length()) + 2;
+	if ( secondLineOffset > 75/2 )
+		secondLineOffset = static_cast<int>(75/2);
+
+	spacePrint( os, s, 75, 3, secondLineOffset );
+}
+
+inline void 
+StdOutput::_longUsage( CmdLineInterface& _cmd, 
+					   std::ostream& os ) const
+{
+	std::list<Arg*> argList = _cmd.getArgList();
+	std::string message = _cmd.getMessage();
+	XorHandler xorHandler = _cmd.getXorHandler();
+	std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
+
+	// first the xor 
+	for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
+		{
+			for ( ArgVectorIterator it = xorList[i].begin(); 
+				  it != xorList[i].end(); 
+				  it++ )
+				{
+					spacePrint( os, (*it)->longID(), 75, 3, 3 );
+					spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
+
+					if ( it+1 != xorList[i].end() )
+						spacePrint(os, "-- OR --", 75, 9, 0);
+				}
+			os << std::endl << std::endl;
+		}
+
+	// then the rest
+	for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
+		if ( !xorHandler.contains( (*it) ) )
+			{
+				spacePrint( os, (*it)->longID(), 75, 3, 3 ); 
+				spacePrint( os, (*it)->getDescription(), 75, 5, 0 ); 
+				os << std::endl;
+			}
+
+	os << std::endl;
+
+	spacePrint( os, message, 75, 3, 0 );
+}
+
+inline void StdOutput::spacePrint( std::ostream& os, 
+						           const std::string& s, 
+						           int maxWidth, 
+						           int indentSpaces, 
+						           int secondLineOffset ) const
+{
+	int len = static_cast<int>(s.length());
+
+	if ( (len + indentSpaces > maxWidth) && maxWidth > 0 )
+		{
+			int allowedLen = maxWidth - indentSpaces;
+			int start = 0;
+			while ( start < len )
+				{
+					// find the substring length
+					// int stringLen = std::min<int>( len - start, allowedLen );
+					// doing it this way to support a VisualC++ 2005 bug 
+					using namespace std; 
+					int stringLen = min<int>( len - start, allowedLen );
+
+					// trim the length so it doesn't end in middle of a word
+					if ( stringLen == allowedLen )
+						while ( stringLen >= 0 &&
+								s[stringLen+start] != ' ' && 
+								s[stringLen+start] != ',' &&
+								s[stringLen+start] != '|' ) 
+							stringLen--;
+	
+					// ok, the word is longer than the line, so just split 
+					// wherever the line ends
+					if ( stringLen <= 0 )
+						stringLen = allowedLen;
+
+					// check for newlines
+					for ( int i = 0; i < stringLen; i++ )
+						if ( s[start+i] == '\n' )
+							stringLen = i+1;
+
+					// print the indent	
+					for ( int i = 0; i < indentSpaces; i++ )
+						os << " ";
+
+					if ( start == 0 )
+						{
+							// handle second line offsets
+							indentSpaces += secondLineOffset;
+
+							// adjust allowed len
+							allowedLen -= secondLineOffset;
+						}
+
+					os << s.substr(start,stringLen) << std::endl;
+
+					// so we don't start a line with a space
+					while ( s[stringLen+start] == ' ' && start < len )
+						start++;
+			
+					start += stringLen;
+				}
+		}
+	else
+		{
+			for ( int i = 0; i < indentSpaces; i++ )
+				os << " ";
+			os << s << std::endl;
+		}
+}
+
+} //namespace TCLAP
+#endif 
diff --git a/pub/ThirdParty/tclap/SwitchArg.h b/pub/ThirdParty/tclap/SwitchArg.h
new file mode 100644
index 0000000000000000000000000000000000000000..39161090692aebc454b10a330191cce6250a67e2
--- /dev/null
+++ b/pub/ThirdParty/tclap/SwitchArg.h
@@ -0,0 +1,266 @@
+
+/****************************************************************************** 
+ * 
+ *  file:  SwitchArg.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+
+#ifndef TCLAP_SWITCH_ARG_H
+#define TCLAP_SWITCH_ARG_H
+
+#include <string>
+#include <vector>
+
+#include <tclap/Arg.h>
+
+namespace TCLAP {
+
+/**
+ * A simple switch argument.  If the switch is set on the command line, then
+ * the getValue method will return the opposite of the default value for the
+ * switch.
+ */
+class SwitchArg : public Arg
+{
+	protected:
+
+		/**
+		 * The value of the switch.
+		 */
+		bool _value;
+
+		/**
+		 * Used to support the reset() method so that ValueArg can be
+		 * reset to their constructed value.
+		 */
+        bool _default;
+
+	public:
+
+        /**
+		 * SwitchArg constructor.
+		 * \param flag - The one character flag that identifies this
+		 * argument on the command line.
+		 * \param name - A one word name for the argument.  Can be
+		 * used as a long flag on the command line.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param def - The default value for this Switch. 
+		 * \param v - An optional visitor.  You probably should not
+		 * use this unless you have a very good reason.
+		 */
+		SwitchArg(const std::string& flag, 
+			      const std::string& name, 
+			      const std::string& desc,
+			      bool def = false,
+				  Visitor* v = NULL);
+
+				  
+		/**
+		 * SwitchArg constructor.
+		 * \param flag - The one character flag that identifies this
+		 * argument on the command line.
+		 * \param name - A one word name for the argument.  Can be
+		 * used as a long flag on the command line.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param parser - A CmdLine parser object to add this Arg to
+		 * \param def - The default value for this Switch.
+		 * \param v - An optional visitor.  You probably should not
+		 * use this unless you have a very good reason.
+		 */
+		SwitchArg(const std::string& flag, 
+			      const std::string& name, 
+			      const std::string& desc,
+				  CmdLineInterface& parser,
+			      bool def = false,
+				  Visitor* v = NULL);
+				  
+				  
+        /**
+		 * Handles the processing of the argument.
+		 * This re-implements the Arg version of this method to set the
+		 * _value of the argument appropriately.
+		 * \param i - Pointer the the current argument in the list.
+		 * \param args - Mutable list of strings. Passed
+		 * in from main().
+		 */
+		virtual bool processArg(int* i, std::vector<std::string>& args); 
+
+		/**
+		 * Checks a string to see if any of the chars in the string
+		 * match the flag for this Switch.
+		 */
+		bool combinedSwitchesMatch(std::string& combined);
+
+		/**
+		 * Returns bool, whether or not the switch has been set.
+		 */
+		bool getValue();
+		
+		virtual void reset();
+
+	private:
+		/**
+		 * Checks to see if we've found the last match in
+		 * a combined string.
+		 */
+		bool lastCombined(std::string& combined);
+
+		/**
+		 * Does the common processing of processArg.
+		 */
+		void commonProcessing();
+};
+
+//////////////////////////////////////////////////////////////////////
+//BEGIN SwitchArg.cpp
+//////////////////////////////////////////////////////////////////////
+inline SwitchArg::SwitchArg(const std::string& flag, 
+                            const std::string& name, 
+                            const std::string& desc, 
+                            bool default_val,
+                            Visitor* v )
+: Arg(flag, name, desc, false, false, v),
+  _value( default_val ),
+  _default( default_val )
+{ }
+
+inline SwitchArg::SwitchArg(const std::string& flag, 
+                            const std::string& name, 
+                            const std::string& desc, 
+                            CmdLineInterface& parser,
+                            bool default_val,
+                            Visitor* v )
+: Arg(flag, name, desc, false, false, v),
+  _value( default_val ),
+  _default(default_val)
+{ 
+	parser.add( this );
+}
+
+inline bool SwitchArg::getValue() { return _value; }
+
+inline bool SwitchArg::lastCombined(std::string& combinedSwitches ) 
+{
+	for ( unsigned int i = 1; i < combinedSwitches.length(); i++ )
+		if ( combinedSwitches[i] != Arg::blankChar() )
+			return false;
+	
+	return true;
+}
+
+inline bool SwitchArg::combinedSwitchesMatch(std::string& combinedSwitches )
+{
+	// make sure this is actually a combined switch
+	if ( combinedSwitches.length() > 0 &&
+	     combinedSwitches[0] != Arg::flagStartString()[0] )
+		return false;
+
+	// make sure it isn't a long name 
+	if ( combinedSwitches.substr( 0, Arg::nameStartString().length() ) == 
+	     Arg::nameStartString() )
+		return false;
+
+	// make sure the delimiter isn't in the string 
+	if ( combinedSwitches.find_first_of( Arg::delimiter() ) != std::string::npos )
+		return false;
+
+	// ok, we're not specifying a ValueArg, so we know that we have
+	// a combined switch list.  
+	for ( unsigned int i = 1; i < combinedSwitches.length(); i++ )
+		if ( _flag.length() > 0 && 
+		     combinedSwitches[i] == _flag[0] &&
+		     _flag[0] != Arg::flagStartString()[0] ) 
+		{
+			// update the combined switches so this one is no longer present
+			// this is necessary so that no unlabeled args are matched
+			// later in the processing.
+			//combinedSwitches.erase(i,1);
+			combinedSwitches[i] = Arg::blankChar(); 
+			return true;
+		}
+
+	// none of the switches passed in the list match. 
+	return false;	
+}
+
+inline void SwitchArg::commonProcessing()
+{
+	if ( _xorSet )
+		throw(CmdLineParseException(
+		      "Mutually exclusive argument already set!", toString()));
+
+	if ( _alreadySet ) 
+		throw(CmdLineParseException("Argument already set!", toString()));
+
+	_alreadySet = true;
+
+	if ( _value == true )
+		_value = false;
+	else
+		_value = true;
+
+	_checkWithVisitor();
+}
+
+inline bool SwitchArg::processArg(int *i, std::vector<std::string>& args)
+{
+	if ( _ignoreable && Arg::ignoreRest() )
+		return false;
+
+	// if the whole string matches the flag or name string
+	if ( argMatches( args[*i] ) )
+	{
+		commonProcessing();
+
+		return true;
+	}
+	// if a substring matches the flag as part of a combination
+	else if ( combinedSwitchesMatch( args[*i] ) )
+	{
+		// check again to ensure we don't misinterpret 
+		// this as a MultiSwitchArg 
+		if ( combinedSwitchesMatch( args[*i] ) )
+			throw(CmdLineParseException("Argument already set!", 
+			                            toString()));
+
+		commonProcessing();
+
+		// We only want to return true if we've found the last combined
+		// match in the string, otherwise we return true so that other 
+		// switches in the combination will have a chance to match.
+		return lastCombined( args[*i] );
+	}
+	else
+		return false;
+}
+
+inline void SwitchArg::reset()
+{
+	Arg::reset();
+	_value = _default;  
+}
+//////////////////////////////////////////////////////////////////////
+//End SwitchArg.cpp
+//////////////////////////////////////////////////////////////////////
+
+} //namespace TCLAP
+
+#endif
diff --git a/pub/ThirdParty/tclap/UnlabeledMultiArg.h b/pub/ThirdParty/tclap/UnlabeledMultiArg.h
new file mode 100644
index 0000000000000000000000000000000000000000..d5e1781060dceb3fe59c504825fcf888c930f7e8
--- /dev/null
+++ b/pub/ThirdParty/tclap/UnlabeledMultiArg.h
@@ -0,0 +1,301 @@
+
+/****************************************************************************** 
+ * 
+ *  file:  UnlabeledMultiArg.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot.
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+
+#ifndef TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H
+#define TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H
+
+#include <string>
+#include <vector>
+
+#include <tclap/MultiArg.h>
+#include <tclap/OptionalUnlabeledTracker.h>
+
+namespace TCLAP {
+
+/**
+ * Just like a MultiArg, except that the arguments are unlabeled.  Basically,
+ * this Arg will slurp up everything that hasn't been matched to another 
+ * Arg.
+ */
+template<class T>
+class UnlabeledMultiArg : public MultiArg<T>
+{
+
+	// If compiler has two stage name lookup (as gcc >= 3.4 does)
+	// this is requried to prevent undef. symbols
+	using MultiArg<T>::_ignoreable;
+	using MultiArg<T>::_hasBlanks;
+	using MultiArg<T>::_extractValue;
+	using MultiArg<T>::_typeDesc;
+	using MultiArg<T>::_name;
+	using MultiArg<T>::_description;
+	using MultiArg<T>::_alreadySet;
+	using MultiArg<T>::toString;
+
+	public:
+		
+		/**
+		 * Constructor.  
+		 * \param name - The name of the Arg. Note that this is used for
+		 * identification, not as a long flag.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param req - Whether the argument is required on the command
+		 *  line.
+		 * \param typeDesc - A short, human readable description of the
+		 * type that this object expects.  This is used in the generation
+		 * of the USAGE statement.  The goal is to be helpful to the end user
+		 * of the program.
+		 * \param ignoreable - Whether or not this argument can be ignored
+		 * using the "--" flag.
+		 * \param v - An optional visitor.  You probably should not
+		 * use this unless you have a very good reason.
+		 */
+		UnlabeledMultiArg( const std::string& name,
+				           const std::string& desc,
+						   bool req,
+				           const std::string& typeDesc,
+						   bool ignoreable = false,
+				           Visitor* v = NULL );
+		/**
+		 * Constructor.  
+		 * \param name - The name of the Arg. Note that this is used for
+		 * identification, not as a long flag.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param req - Whether the argument is required on the command
+		 *  line.
+		 * \param typeDesc - A short, human readable description of the
+		 * type that this object expects.  This is used in the generation
+		 * of the USAGE statement.  The goal is to be helpful to the end user
+		 * of the program.
+		 * \param parser - A CmdLine parser object to add this Arg to
+		 * \param ignoreable - Whether or not this argument can be ignored
+		 * using the "--" flag.
+		 * \param v - An optional visitor.  You probably should not
+		 * use this unless you have a very good reason.
+		 */
+		UnlabeledMultiArg( const std::string& name,
+				           const std::string& desc,
+						   bool req,
+				           const std::string& typeDesc,
+						   CmdLineInterface& parser,
+						   bool ignoreable = false,
+				           Visitor* v = NULL );
+						 
+		/**
+		 * Constructor.  
+		 * \param name - The name of the Arg. Note that this is used for
+		 * identification, not as a long flag.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param req - Whether the argument is required on the command
+		 *  line.
+		 * \param constraint - A pointer to a Constraint object used
+		 * to constrain this Arg.
+		 * \param ignoreable - Whether or not this argument can be ignored
+		 * using the "--" flag.
+		 * \param v - An optional visitor.  You probably should not
+		 * use this unless you have a very good reason.
+		 */
+		UnlabeledMultiArg( const std::string& name,
+						   const std::string& desc,
+						   bool req,
+						   Constraint<T>* constraint,
+						   bool ignoreable = false,
+						   Visitor* v = NULL );
+
+		/**
+		 * Constructor.  
+		 * \param name - The name of the Arg. Note that this is used for
+		 * identification, not as a long flag.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param req - Whether the argument is required on the command
+		 *  line.
+		 * \param constraint - A pointer to a Constraint object used
+		 * to constrain this Arg.
+		 * \param parser - A CmdLine parser object to add this Arg to
+		 * \param ignoreable - Whether or not this argument can be ignored
+		 * using the "--" flag.
+		 * \param v - An optional visitor.  You probably should not
+		 * use this unless you have a very good reason.
+		 */
+		UnlabeledMultiArg( const std::string& name, 
+						   const std::string& desc, 
+						   bool req,
+						   Constraint<T>* constraint,
+						   CmdLineInterface& parser,
+						   bool ignoreable = false,
+						   Visitor* v = NULL );
+						 
+		/**
+		 * Handles the processing of the argument.
+		 * This re-implements the Arg version of this method to set the
+		 * _value of the argument appropriately.  It knows the difference
+		 * between labeled and unlabeled.
+		 * \param i - Pointer the the current argument in the list.
+		 * \param args - Mutable list of strings. Passed from main().
+		 */
+		virtual bool processArg(int* i, std::vector<std::string>& args); 
+
+		/**
+		 * Returns the a short id string.  Used in the usage.
+		 * \param val - value to be used.
+		 */
+		virtual std::string shortID(const std::string& val="val") const;
+
+		/**
+		 * Returns the a long id string.  Used in the usage.
+		 * \param val - value to be used.
+		 */
+		virtual std::string longID(const std::string& val="val") const;
+
+		/**
+		 * Opertor ==.
+		 * \param a - The Arg to be compared to this.
+		 */
+		virtual bool operator==(const Arg& a) const;
+
+		/**
+		 * Pushes this to back of list rather than front.
+		 * \param argList - The list this should be added to.
+		 */
+		virtual void addToList( std::list<Arg*>& argList ) const;
+};
+
+template<class T>
+UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, 
+				                        const std::string& desc, 
+										bool req,
+					                    const std::string& typeDesc,
+										bool ignoreable,
+					                    Visitor* v)
+: MultiArg<T>("", name, desc,  req, typeDesc, v)
+{ 
+	_ignoreable = ignoreable;
+	OptionalUnlabeledTracker::check(true, toString());
+}
+
+template<class T>
+UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, 
+				                        const std::string& desc, 
+										bool req,
+					                    const std::string& typeDesc,
+										CmdLineInterface& parser,
+										bool ignoreable,
+					                    Visitor* v)
+: MultiArg<T>("", name, desc,  req, typeDesc, v)
+{ 
+	_ignoreable = ignoreable;
+	OptionalUnlabeledTracker::check(true, toString());
+	parser.add( this );
+}
+
+
+template<class T>
+UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, 
+				                        const std::string& desc, 
+										bool req,
+					                    Constraint<T>* constraint,
+										bool ignoreable,
+					                    Visitor* v)
+: MultiArg<T>("", name, desc,  req, constraint, v)
+{ 
+	_ignoreable = ignoreable;
+	OptionalUnlabeledTracker::check(true, toString());
+}
+
+template<class T>
+UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name, 
+				                        const std::string& desc, 
+										bool req,
+					                    Constraint<T>* constraint,
+										CmdLineInterface& parser,
+										bool ignoreable,
+					                    Visitor* v)
+: MultiArg<T>("", name, desc,  req, constraint, v)
+{ 
+	_ignoreable = ignoreable;
+	OptionalUnlabeledTracker::check(true, toString());
+	parser.add( this );
+}
+
+
+template<class T>
+bool UnlabeledMultiArg<T>::processArg(int *i, std::vector<std::string>& args) 
+{
+
+	if ( _hasBlanks( args[*i] ) )
+		return false;
+
+	// never ignore an unlabeled multi arg
+
+
+	// always take the first value, regardless of the start string 
+	_extractValue( args[(*i)] );
+
+	/*
+	// continue taking args until we hit the end or a start string 
+	while ( (unsigned int)(*i)+1 < args.size() &&
+			args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
+            args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 ) 
+		_extractValue( args[++(*i)] );
+	*/
+
+	_alreadySet = true;
+
+	return true;
+}
+
+template<class T>
+std::string UnlabeledMultiArg<T>::shortID(const std::string& val) const
+{
+	static_cast<void>(val); // Ignore input, don't warn
+	return std::string("<") + _typeDesc + "> ...";
+}
+
+template<class T>
+std::string UnlabeledMultiArg<T>::longID(const std::string& val) const
+{
+	static_cast<void>(val); // Ignore input, don't warn
+	return std::string("<") + _typeDesc + ">  (accepted multiple times)";
+}
+
+template<class T>
+bool UnlabeledMultiArg<T>::operator==(const Arg& a) const
+{
+	if ( _name == a.getName() || _description == a.getDescription() )
+		return true;
+	else
+		return false;
+}
+
+template<class T>
+void UnlabeledMultiArg<T>::addToList( std::list<Arg*>& argList ) const
+{
+	argList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );
+}
+
+}
+
+#endif
diff --git a/pub/ThirdParty/tclap/UnlabeledValueArg.h b/pub/ThirdParty/tclap/UnlabeledValueArg.h
new file mode 100644
index 0000000000000000000000000000000000000000..5721d61252f20180c349bb126e582a79f939367b
--- /dev/null
+++ b/pub/ThirdParty/tclap/UnlabeledValueArg.h
@@ -0,0 +1,340 @@
+
+/****************************************************************************** 
+ * 
+ *  file:  UnlabeledValueArg.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+
+#ifndef TCLAP_UNLABELED_VALUE_ARGUMENT_H
+#define TCLAP_UNLABELED_VALUE_ARGUMENT_H
+
+#include <string>
+#include <vector>
+
+#include <tclap/ValueArg.h>
+#include <tclap/OptionalUnlabeledTracker.h>
+
+
+namespace TCLAP {
+
+/**
+ * The basic unlabeled argument that parses a value.
+ * This is a template class, which means the type T defines the type
+ * that a given object will attempt to parse when an UnlabeledValueArg
+ * is reached in the list of args that the CmdLine iterates over.
+ */
+template<class T>
+class UnlabeledValueArg : public ValueArg<T>
+{
+
+	// If compiler has two stage name lookup (as gcc >= 3.4 does)
+	// this is requried to prevent undef. symbols
+	using ValueArg<T>::_ignoreable;
+	using ValueArg<T>::_hasBlanks;
+	using ValueArg<T>::_extractValue;
+	using ValueArg<T>::_typeDesc;
+	using ValueArg<T>::_name;
+	using ValueArg<T>::_description;
+	using ValueArg<T>::_alreadySet;
+	using ValueArg<T>::toString;
+
+	public:
+
+		/**
+		 * UnlabeledValueArg constructor.
+		 * \param name - A one word name for the argument.  Note that this is used for
+		 * identification, not as a long flag.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param req - Whether the argument is required on the command
+		 * line.
+		 * \param value - The default value assigned to this argument if it
+		 * is not present on the command line.
+		 * \param typeDesc - A short, human readable description of the
+		 * type that this object expects.  This is used in the generation
+		 * of the USAGE statement.  The goal is to be helpful to the end user
+		 * of the program.
+		 * \param ignoreable - Allows you to specify that this argument can be
+		 * ignored if the '--' flag is set.  This defaults to false (cannot
+		 * be ignored) and should  generally stay that way unless you have 
+		 * some special need for certain arguments to be ignored.
+		 * \param v - Optional Vistor.  You should leave this blank unless
+		 * you have a very good reason.
+		 */
+		UnlabeledValueArg( const std::string& name, 
+			               const std::string& desc, 
+						   bool req,
+				           T value,
+				           const std::string& typeDesc,
+						   bool ignoreable = false,
+				           Visitor* v = NULL); 
+
+		/**
+		 * UnlabeledValueArg constructor.
+		 * \param name - A one word name for the argument.  Note that this is used for
+		 * identification, not as a long flag.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param req - Whether the argument is required on the command
+		 * line.
+		 * \param value - The default value assigned to this argument if it
+		 * is not present on the command line.
+		 * \param typeDesc - A short, human readable description of the
+		 * type that this object expects.  This is used in the generation
+		 * of the USAGE statement.  The goal is to be helpful to the end user
+		 * of the program.
+		 * \param parser - A CmdLine parser object to add this Arg to
+		 * \param ignoreable - Allows you to specify that this argument can be
+		 * ignored if the '--' flag is set.  This defaults to false (cannot
+		 * be ignored) and should  generally stay that way unless you have 
+		 * some special need for certain arguments to be ignored.
+		 * \param v - Optional Vistor.  You should leave this blank unless
+		 * you have a very good reason.
+		 */
+		UnlabeledValueArg( const std::string& name, 
+			               const std::string& desc, 
+						   bool req,
+				           T value,
+				           const std::string& typeDesc,
+						   CmdLineInterface& parser,
+						   bool ignoreable = false,
+				           Visitor* v = NULL ); 					
+						
+		/**
+		 * UnlabeledValueArg constructor.
+		 * \param name - A one word name for the argument.  Note that this is used for
+		 * identification, not as a long flag.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param req - Whether the argument is required on the command
+		 * line.
+		 * \param value - The default value assigned to this argument if it
+		 * is not present on the command line.
+		 * \param constraint - A pointer to a Constraint object used
+		 * to constrain this Arg.
+		 * \param ignoreable - Allows you to specify that this argument can be
+		 * ignored if the '--' flag is set.  This defaults to false (cannot
+		 * be ignored) and should  generally stay that way unless you have 
+		 * some special need for certain arguments to be ignored.
+		 * \param v - Optional Vistor.  You should leave this blank unless
+		 * you have a very good reason.
+		 */
+		UnlabeledValueArg( const std::string& name, 
+			               const std::string& desc, 
+						   bool req,
+				           T value,
+				           Constraint<T>* constraint,
+						   bool ignoreable = false,
+				           Visitor* v = NULL ); 
+
+		
+		/**
+		 * UnlabeledValueArg constructor.
+		 * \param name - A one word name for the argument.  Note that this is used for
+		 * identification, not as a long flag.
+		 * \param desc - A description of what the argument is for or
+		 * does.
+		 * \param req - Whether the argument is required on the command
+		 * line.
+		 * \param value - The default value assigned to this argument if it
+		 * is not present on the command line.
+		 * \param constraint - A pointer to a Constraint object used
+		 * to constrain this Arg.
+		 * \param parser - A CmdLine parser object to add this Arg to
+		 * \param ignoreable - Allows you to specify that this argument can be
+		 * ignored if the '--' flag is set.  This defaults to false (cannot
+		 * be ignored) and should  generally stay that way unless you have 
+		 * some special need for certain arguments to be ignored.
+		 * \param v - Optional Vistor.  You should leave this blank unless
+		 * you have a very good reason.
+		 */
+		UnlabeledValueArg( const std::string& name, 
+			               const std::string& desc, 
+						   bool req,
+				           T value,
+				           Constraint<T>* constraint,
+						   CmdLineInterface& parser,
+						   bool ignoreable = false,
+				           Visitor* v = NULL);
+						
+		/**
+		 * Handles the processing of the argument.
+		 * This re-implements the Arg version of this method to set the
+		 * _value of the argument appropriately.  Handling specific to
+		 * unlabled arguments.
+		 * \param i - Pointer the the current argument in the list.
+		 * \param args - Mutable list of strings. 
+		 */
+		virtual bool processArg(int* i, std::vector<std::string>& args); 
+
+		/**
+		 * Overrides shortID for specific behavior.
+		 */
+		virtual std::string shortID(const std::string& val="val") const;
+
+		/**
+		 * Overrides longID for specific behavior.
+		 */
+		virtual std::string longID(const std::string& val="val") const;
+
+		/**
+		 * Overrides operator== for specific behavior.
+		 */
+		virtual bool operator==(const Arg& a ) const;
+
+		/**
+		 * Instead of pushing to the front of list, push to the back.
+		 * \param argList - The list to add this to.
+		 */
+		virtual void addToList( std::list<Arg*>& argList ) const;
+
+};
+
+/**
+ * Constructor implemenation.
+ */
+template<class T>
+UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, 
+					                    const std::string& desc, 
+										bool req,
+					                    T val,
+					                    const std::string& typeDesc,
+					                    bool ignoreable,
+					                    Visitor* v)
+: ValueArg<T>("", name, desc, req, val, typeDesc, v)
+{ 
+	_ignoreable = ignoreable;
+
+	OptionalUnlabeledTracker::check(req, toString());
+
+}
+
+template<class T>
+UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, 
+					                    const std::string& desc, 
+										bool req,
+					                    T val,
+					                    const std::string& typeDesc,
+					                    CmdLineInterface& parser,
+					                    bool ignoreable,
+					                    Visitor* v)
+: ValueArg<T>("", name, desc, req, val, typeDesc, v)
+{ 
+	_ignoreable = ignoreable;
+	OptionalUnlabeledTracker::check(req, toString());
+	parser.add( this );
+}
+
+/**
+ * Constructor implemenation.
+ */
+template<class T>
+UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, 
+                                        const std::string& desc, 
+										bool req,
+                                        T val,
+                                        Constraint<T>* constraint,
+                                        bool ignoreable,
+                                        Visitor* v)
+: ValueArg<T>("", name, desc, req, val, constraint, v)
+{ 
+	_ignoreable = ignoreable;
+	OptionalUnlabeledTracker::check(req, toString());
+}
+
+template<class T>
+UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name, 
+					                    const std::string& desc, 
+										bool req,
+					                    T val,
+					                    Constraint<T>* constraint,
+					                    CmdLineInterface& parser,
+					                    bool ignoreable,
+					                    Visitor* v)
+: ValueArg<T>("", name, desc, req, val, constraint,  v)
+{ 
+	_ignoreable = ignoreable;
+	OptionalUnlabeledTracker::check(req, toString());
+	parser.add( this );
+}
+
+/**
+ * Implementation of processArg().
+ */
+template<class T>
+bool UnlabeledValueArg<T>::processArg(int *i, std::vector<std::string>& args) 
+{
+	
+	if ( _alreadySet )
+		return false;
+	
+	if ( _hasBlanks( args[*i] ) )
+		return false;
+
+	// never ignore an unlabeled arg
+	
+	_extractValue( args[*i] );
+	_alreadySet = true;
+	return true;
+}
+
+/**
+ * Overriding shortID for specific output.
+ */
+template<class T>
+std::string UnlabeledValueArg<T>::shortID(const std::string& val) const
+{
+	static_cast<void>(val); // Ignore input, don't warn
+	return std::string("<") + _typeDesc + ">";
+}
+
+/**
+ * Overriding longID for specific output.
+ */
+template<class T>
+std::string UnlabeledValueArg<T>::longID(const std::string& val) const
+{
+	static_cast<void>(val); // Ignore input, don't warn
+
+	// Ideally we would like to be able to use RTTI to return the name
+	// of the type required for this argument.  However, g++ at least, 
+	// doesn't appear to return terribly useful "names" of the types.  
+	return std::string("<") + _typeDesc + ">";
+}
+
+/**
+ * Overriding operator== for specific behavior.
+ */
+template<class T>
+bool UnlabeledValueArg<T>::operator==(const Arg& a ) const
+{
+	if ( _name == a.getName() || _description == a.getDescription() )
+		return true;
+	else
+		return false;
+}
+
+template<class T>
+void UnlabeledValueArg<T>::addToList( std::list<Arg*>& argList ) const
+{
+	argList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );
+}
+
+}
+#endif
diff --git a/pub/ThirdParty/tclap/ValueArg.h b/pub/ThirdParty/tclap/ValueArg.h
new file mode 100644
index 0000000000000000000000000000000000000000..7ac29526b94393a4b5441921307fbf5b419805fb
--- /dev/null
+++ b/pub/ThirdParty/tclap/ValueArg.h
@@ -0,0 +1,425 @@
+/****************************************************************************** 
+ * 
+ *  file:  ValueArg.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+
+#ifndef TCLAP_VALUE_ARGUMENT_H
+#define TCLAP_VALUE_ARGUMENT_H
+
+#include <string>
+#include <vector>
+
+#include <tclap/Arg.h>
+#include <tclap/Constraint.h>
+
+namespace TCLAP {
+
+/**
+ * The basic labeled argument that parses a value.
+ * This is a template class, which means the type T defines the type
+ * that a given object will attempt to parse when the flag/name is matched
+ * on the command line.  While there is nothing stopping you from creating
+ * an unflagged ValueArg, it is unwise and would cause significant problems.
+ * Instead use an UnlabeledValueArg.
+ */
+template<class T>
+class ValueArg : public Arg 
+{
+    protected:
+
+        /**
+         * The value parsed from the command line.
+         * Can be of any type, as long as the >> operator for the type
+         * is defined.
+         */
+        T _value;
+
+		/**
+		 * Used to support the reset() method so that ValueArg can be
+		 * reset to their constructed value.
+		 */
+        T _default;
+
+        /**
+         * A human readable description of the type to be parsed.
+         * This is a hack, plain and simple.  Ideally we would use RTTI to
+         * return the name of type T, but until there is some sort of
+         * consistent support for human readable names, we are left to our
+         * own devices.
+         */
+        std::string _typeDesc;
+
+        /**
+         * A Constraint this Arg must conform to. 
+         */
+        Constraint<T>* _constraint;
+
+        /**
+         * Extracts the value from the string.
+         * Attempts to parse string as type T, if this fails an exception
+         * is thrown.
+         * \param val - value to be parsed. 
+         */
+        void _extractValue( const std::string& val );
+
+	public:
+
+        /**
+         * Labeled ValueArg constructor.
+         * You could conceivably call this constructor with a blank flag, 
+         * but that would make you a bad person.  It would also cause
+         * an exception to be thrown.   If you want an unlabeled argument, 
+         * use the other constructor.
+         * \param flag - The one character flag that identifies this
+         * argument on the command line.
+         * \param name - A one word name for the argument.  Can be
+         * used as a long flag on the command line.
+         * \param desc - A description of what the argument is for or
+         * does.
+         * \param req - Whether the argument is required on the command
+         * line.
+         * \param value - The default value assigned to this argument if it
+         * is not present on the command line.
+         * \param typeDesc - A short, human readable description of the
+         * type that this object expects.  This is used in the generation
+         * of the USAGE statement.  The goal is to be helpful to the end user
+         * of the program.
+         * \param v - An optional visitor.  You probably should not
+         * use this unless you have a very good reason.
+         */
+        ValueArg( const std::string& flag, 
+                  const std::string& name, 
+                  const std::string& desc, 
+                  bool req, 
+                  T value,
+                  const std::string& typeDesc,
+                  Visitor* v = NULL);
+				 
+				 
+        /**
+         * Labeled ValueArg constructor.
+         * You could conceivably call this constructor with a blank flag, 
+         * but that would make you a bad person.  It would also cause
+         * an exception to be thrown.   If you want an unlabeled argument, 
+         * use the other constructor.
+         * \param flag - The one character flag that identifies this
+         * argument on the command line.
+         * \param name - A one word name for the argument.  Can be
+         * used as a long flag on the command line.
+         * \param desc - A description of what the argument is for or
+         * does.
+         * \param req - Whether the argument is required on the command
+         * line.
+         * \param value - The default value assigned to this argument if it
+         * is not present on the command line.
+         * \param typeDesc - A short, human readable description of the
+         * type that this object expects.  This is used in the generation
+         * of the USAGE statement.  The goal is to be helpful to the end user
+         * of the program.
+         * \param parser - A CmdLine parser object to add this Arg to
+         * \param v - An optional visitor.  You probably should not
+         * use this unless you have a very good reason.
+         */
+        ValueArg( const std::string& flag, 
+                  const std::string& name, 
+                  const std::string& desc, 
+                  bool req, 
+                  T value,
+                  const std::string& typeDesc,
+                  CmdLineInterface& parser,
+                  Visitor* v = NULL );
+ 
+        /**
+         * Labeled ValueArg constructor.
+         * You could conceivably call this constructor with a blank flag, 
+         * but that would make you a bad person.  It would also cause
+         * an exception to be thrown.   If you want an unlabeled argument, 
+         * use the other constructor.
+         * \param flag - The one character flag that identifies this
+         * argument on the command line.
+         * \param name - A one word name for the argument.  Can be
+         * used as a long flag on the command line.
+         * \param desc - A description of what the argument is for or
+         * does.
+         * \param req - Whether the argument is required on the command
+         * line.
+         * \param value - The default value assigned to this argument if it
+         * is not present on the command line.
+         * \param constraint - A pointer to a Constraint object used
+		 * to constrain this Arg.
+         * \param parser - A CmdLine parser object to add this Arg to.
+         * \param v - An optional visitor.  You probably should not
+         * use this unless you have a very good reason.
+         */
+        ValueArg( const std::string& flag, 
+                  const std::string& name, 
+                  const std::string& desc, 
+                  bool req, 
+                  T value,
+                  Constraint<T>* constraint,
+                  CmdLineInterface& parser,
+                  Visitor* v = NULL );
+	  
+        /**
+         * Labeled ValueArg constructor.
+         * You could conceivably call this constructor with a blank flag, 
+         * but that would make you a bad person.  It would also cause
+         * an exception to be thrown.   If you want an unlabeled argument, 
+         * use the other constructor.
+         * \param flag - The one character flag that identifies this
+         * argument on the command line.
+         * \param name - A one word name for the argument.  Can be
+         * used as a long flag on the command line.
+         * \param desc - A description of what the argument is for or
+         * does.
+         * \param req - Whether the argument is required on the command
+         * line.
+         * \param value - The default value assigned to this argument if it
+         * is not present on the command line.
+         * \param constraint - A pointer to a Constraint object used
+		 * to constrain this Arg.
+         * \param v - An optional visitor.  You probably should not
+         * use this unless you have a very good reason.
+         */
+        ValueArg( const std::string& flag, 
+                  const std::string& name, 
+                  const std::string& desc, 
+                  bool req, 
+                  T value,
+                  Constraint<T>* constraint,
+                  Visitor* v = NULL );
+
+        /**
+         * Handles the processing of the argument.
+         * This re-implements the Arg version of this method to set the
+         * _value of the argument appropriately.  It knows the difference
+         * between labeled and unlabeled.
+         * \param i - Pointer the the current argument in the list.
+         * \param args - Mutable list of strings. Passed 
+         * in from main().
+         */
+        virtual bool processArg(int* i, std::vector<std::string>& args); 
+
+        /**
+         * Returns the value of the argument.
+         */
+        T& getValue() ;
+
+        /**
+         * Specialization of shortID.
+         * \param val - value to be used.
+         */
+        virtual std::string shortID(const std::string& val = "val") const;
+
+        /**
+         * Specialization of longID.
+         * \param val - value to be used.
+         */
+        virtual std::string longID(const std::string& val = "val") const;
+        
+        virtual void reset() ;
+
+private:
+       /**
+        * Prevent accidental copying
+        */
+       ValueArg<T>(const ValueArg<T>& rhs);
+       ValueArg<T>& operator=(const ValueArg<T>& rhs);
+};
+
+
+/**
+ * Constructor implementation.
+ */
+template<class T>
+ValueArg<T>::ValueArg(const std::string& flag, 
+                      const std::string& name, 
+                      const std::string& desc, 
+                      bool req, 
+                      T val,
+                      const std::string& typeDesc,
+                      Visitor* v)
+: Arg(flag, name, desc, req, true, v),
+  _value( val ),
+  _default( val ),
+  _typeDesc( typeDesc ),
+  _constraint( NULL )
+{ }
+
+template<class T>
+ValueArg<T>::ValueArg(const std::string& flag, 
+                      const std::string& name, 
+                      const std::string& desc, 
+                      bool req, 
+                      T val,
+                      const std::string& typeDesc,
+                      CmdLineInterface& parser,
+                      Visitor* v)
+: Arg(flag, name, desc, req, true, v),
+  _value( val ),
+  _default( val ),
+  _typeDesc( typeDesc ),
+  _constraint( NULL )
+{ 
+    parser.add( this );
+}
+
+template<class T>
+ValueArg<T>::ValueArg(const std::string& flag, 
+                      const std::string& name, 
+                      const std::string& desc, 
+                      bool req, 
+                      T val,
+                      Constraint<T>* constraint,
+                      Visitor* v)
+: Arg(flag, name, desc, req, true, v),
+  _value( val ),
+  _default( val ),
+  _typeDesc( constraint->shortID() ),
+  _constraint( constraint )
+{ }
+
+template<class T>
+ValueArg<T>::ValueArg(const std::string& flag, 
+                      const std::string& name, 
+                      const std::string& desc, 
+                      bool req, 
+                      T val,
+                      Constraint<T>* constraint,
+                      CmdLineInterface& parser,
+                      Visitor* v)
+: Arg(flag, name, desc, req, true, v),
+  _value( val ),
+  _default( val ),
+  _typeDesc( constraint->shortID() ),
+  _constraint( constraint )
+{ 
+    parser.add( this );
+}
+
+
+/**
+ * Implementation of getValue().
+ */
+template<class T>
+T& ValueArg<T>::getValue() { return _value; }
+
+/**
+ * Implementation of processArg().
+ */
+template<class T>
+bool ValueArg<T>::processArg(int *i, std::vector<std::string>& args)
+{
+    if ( _ignoreable && Arg::ignoreRest() )
+		return false;
+
+    if ( _hasBlanks( args[*i] ) )
+		return false;
+
+    std::string flag = args[*i];
+
+    std::string value = "";
+    trimFlag( flag, value );
+
+    if ( argMatches( flag ) )
+    {
+        if ( _alreadySet )
+		{
+			if ( _xorSet )
+				throw( CmdLineParseException(
+				       "Mutually exclusive argument already set!", 
+				                             toString()) );
+			else
+				throw( CmdLineParseException("Argument already set!", 
+				                             toString()) );
+		}
+
+        if ( Arg::delimiter() != ' ' && value == "" )
+			throw( ArgParseException( 
+							"Couldn't find delimiter for this argument!",
+                             toString() ) );
+
+        if ( value == "" )
+        {
+            (*i)++;
+            if ( static_cast<unsigned int>(*i) < args.size() ) 
+				_extractValue( args[*i] );
+            else
+				throw( ArgParseException("Missing a value for this argument!",
+                                                    toString() ) );
+        }
+        else
+			_extractValue( value );
+				
+        _alreadySet = true;
+        _checkWithVisitor();
+        return true;
+    }	
+    else
+		return false;
+}
+
+/**
+ * Implementation of shortID.
+ */
+template<class T>
+std::string ValueArg<T>::shortID(const std::string& val) const
+{
+	static_cast<void>(val); // Ignore input, don't warn
+	return Arg::shortID( _typeDesc ); 
+}
+
+/**
+ * Implementation of longID.
+ */
+template<class T>
+std::string ValueArg<T>::longID(const std::string& val) const
+{
+	static_cast<void>(val); // Ignore input, don't warn
+	return Arg::longID( _typeDesc ); 
+}
+
+template<class T>
+void ValueArg<T>::_extractValue( const std::string& val ) 
+{
+    try {
+	ExtractValue(_value, val, typename ArgTraits<T>::ValueCategory());
+    } catch( ArgParseException &e) {
+	throw ArgParseException(e.error(), toString());
+    }
+    
+    if ( _constraint != NULL )
+	if ( ! _constraint->check( _value ) )
+	    throw( CmdLineParseException( "Value '" + val + 
+					  + "' does not meet constraint: " 
+					  + _constraint->description(),
+					  toString() ) );
+}
+
+template<class T>
+void ValueArg<T>::reset()
+{
+	Arg::reset();
+	_value = _default;
+}
+
+} // namespace TCLAP
+
+#endif
diff --git a/pub/ThirdParty/tclap/ValuesConstraint.h b/pub/ThirdParty/tclap/ValuesConstraint.h
new file mode 100644
index 0000000000000000000000000000000000000000..cb41f645e55b7352dd85d0bb0657ad8e2c0324bf
--- /dev/null
+++ b/pub/ThirdParty/tclap/ValuesConstraint.h
@@ -0,0 +1,148 @@
+
+
+/****************************************************************************** 
+ * 
+ *  file:  ValuesConstraint.h
+ * 
+ *  Copyright (c) 2005, Michael E. Smoot
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+#ifndef TCLAP_VALUESCONSTRAINT_H
+#define TCLAP_VALUESCONSTRAINT_H
+
+#include <string>
+#include <vector>
+#include <tclap/Constraint.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#define HAVE_SSTREAM
+#endif
+
+#if defined(HAVE_SSTREAM)
+#include <sstream>
+#elif defined(HAVE_STRSTREAM)
+#include <strstream>
+#else
+#error "Need a stringstream (sstream or strstream) to compile!"
+#endif
+
+namespace TCLAP {
+
+/**
+ * A Constraint that constrains the Arg to only those values specified
+ * in the constraint.
+ */
+template<class T>
+class ValuesConstraint : public Constraint<T>
+{
+
+	public:
+
+		/**
+		 * Constructor. 
+		 * \param allowed - vector of allowed values. 
+		 */
+		ValuesConstraint(std::vector<T>& allowed);	
+
+		/**
+		 * Virtual destructor.
+		 */
+		virtual ~ValuesConstraint() {}
+
+		/**
+		 * Returns a description of the Constraint. 
+		 */
+		virtual std::string description() const;
+
+		/**
+		 * Returns the short ID for the Constraint.
+		 */
+		virtual std::string shortID() const;
+
+		/**
+		 * The method used to verify that the value parsed from the command
+		 * line meets the constraint.
+		 * \param value - The value that will be checked. 
+		 */
+		virtual bool check(const T& value) const;
+	
+	protected:
+
+		/**
+		 * The list of valid values. 
+		 */
+		std::vector<T> _allowed;
+
+		/**
+		 * The string used to describe the allowed values of this constraint.
+		 */
+		std::string _typeDesc;
+
+};
+
+template<class T>
+ValuesConstraint<T>::ValuesConstraint(std::vector<T>& allowed)
+: _allowed(allowed),
+  _typeDesc("")
+{ 
+    for ( unsigned int i = 0; i < _allowed.size(); i++ )
+    {
+
+#if defined(HAVE_SSTREAM)
+        std::ostringstream os;
+#elif defined(HAVE_STRSTREAM)
+        std::ostrstream os;
+#else
+#error "Need a stringstream (sstream or strstream) to compile!"
+#endif
+
+        os << _allowed[i];
+
+        std::string temp( os.str() ); 
+
+        if ( i > 0 )
+			_typeDesc += "|";
+        _typeDesc += temp;
+    }
+}
+
+template<class T>
+bool ValuesConstraint<T>::check( const T& val ) const
+{
+	if ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() )
+		return false;
+	else 
+		return true;
+}
+
+template<class T>
+std::string ValuesConstraint<T>::shortID() const
+{
+    return _typeDesc;	
+}
+
+template<class T>
+std::string ValuesConstraint<T>::description() const
+{
+    return _typeDesc;	
+}
+
+
+} //namespace TCLAP
+#endif 
+
diff --git a/pub/ThirdParty/tclap/VersionVisitor.h b/pub/ThirdParty/tclap/VersionVisitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..c110d4fa009401bcf88533b9f7d7101e9735bb1d
--- /dev/null
+++ b/pub/ThirdParty/tclap/VersionVisitor.h
@@ -0,0 +1,81 @@
+// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
+
+/****************************************************************************** 
+ * 
+ *  file:  VersionVisitor.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+
+#ifndef TCLAP_VERSION_VISITOR_H
+#define TCLAP_VERSION_VISITOR_H
+
+#include <tclap/CmdLineInterface.h>
+#include <tclap/CmdLineOutput.h>
+#include <tclap/Visitor.h>
+
+namespace TCLAP {
+
+/**
+ * A Vistor that will call the version method of the given CmdLineOutput
+ * for the specified CmdLine object and then exit.
+ */
+class VersionVisitor: public Visitor
+{
+	private:
+		/**
+		 * Prevent accidental copying
+		 */
+		VersionVisitor(const VersionVisitor& rhs);
+		VersionVisitor& operator=(const VersionVisitor& rhs);
+
+	protected:
+
+		/**
+		 * The CmdLine of interest.
+		 */
+		CmdLineInterface* _cmd;
+
+		/**
+		 * The output object. 
+		 */
+		CmdLineOutput** _out;
+
+	public:
+
+		/**
+		 * Constructor.
+		 * \param cmd - The CmdLine the output is generated for. 
+		 * \param out - The type of output. 
+		 */
+		VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out ) 
+				: Visitor(), _cmd( cmd ), _out( out ) { }
+
+		/**
+		 * Calls the version method of the output object using the
+		 * specified CmdLine.
+		 */
+		void visit() { 
+		    (*_out)->version(*_cmd); 
+		    throw ExitException(0); 
+		}
+
+};
+
+}
+
+#endif
diff --git a/pub/ThirdParty/tclap/Visitor.h b/pub/ThirdParty/tclap/Visitor.h
new file mode 100644
index 0000000000000000000000000000000000000000..38ddcbdb86107a52300b99ca1369f65b0efa1354
--- /dev/null
+++ b/pub/ThirdParty/tclap/Visitor.h
@@ -0,0 +1,53 @@
+
+/****************************************************************************** 
+ * 
+ *  file:  Visitor.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+
+#ifndef TCLAP_VISITOR_H
+#define TCLAP_VISITOR_H
+
+namespace TCLAP {
+
+/**
+ * A base class that defines the interface for visitors.
+ */
+class Visitor
+{
+	public:
+
+		/**
+		 * Constructor. Does nothing.
+		 */
+		Visitor() { }
+
+		/**
+		 * Destructor. Does nothing.
+		 */
+		virtual ~Visitor() { }
+
+		/**
+		 * Does nothing. Should be overridden by child.
+		 */
+		virtual void visit() { }
+};
+
+}
+
+#endif
diff --git a/pub/ThirdParty/tclap/XorHandler.h b/pub/ThirdParty/tclap/XorHandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..d9dfad31f6ff6b7d18a7b045d8f8347f1118c172
--- /dev/null
+++ b/pub/ThirdParty/tclap/XorHandler.h
@@ -0,0 +1,166 @@
+
+/****************************************************************************** 
+ * 
+ *  file:  XorHandler.h
+ * 
+ *  Copyright (c) 2003, Michael E. Smoot .
+ *  Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.  
+ *  
+ *****************************************************************************/ 
+
+#ifndef TCLAP_XORHANDLER_H
+#define TCLAP_XORHANDLER_H
+
+#include <tclap/Arg.h>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <iostream>
+
+namespace TCLAP {
+
+/**
+ * This class handles lists of Arg's that are to be XOR'd on the command
+ * line.  This is used by CmdLine and you shouldn't ever use it.
+ */
+class XorHandler
+{
+	protected:
+
+		/**
+		 * The list of of lists of Arg's to be or'd together.
+		 */
+		std::vector< std::vector<Arg*> > _orList;
+
+	public:
+
+		/**
+		 * Constructor.  Does nothing.
+		 */
+		XorHandler( ) : _orList(std::vector< std::vector<Arg*> >()) {}
+
+		/**
+		 * Add a list of Arg*'s that will be orred together.
+		 * \param ors - list of Arg* that will be xor'd.
+		 */
+		void add( std::vector<Arg*>& ors );
+			
+		/**
+		 * Checks whether the specified Arg is in one of the xor lists and
+		 * if it does match one, returns the size of the xor list that the
+		 * Arg matched.  If the Arg matches, then it also sets the rest of
+		 * the Arg's in the list. You shouldn't use this.  
+		 * \param a - The Arg to be checked.
+		 */
+		int check( const Arg* a );
+
+		/**
+		 * Returns the XOR specific short usage.
+		 */
+		std::string shortUsage();
+
+		/**
+		 * Prints the XOR specific long usage.
+		 * \param os - Stream to print to.
+		 */
+		void printLongUsage(std::ostream& os);
+
+		/**
+		 * Simply checks whether the Arg is contained in one of the arg
+		 * lists.
+		 * \param a - The Arg to be checked.
+		 */
+		bool contains( const Arg* a );
+
+		std::vector< std::vector<Arg*> >& getXorList(); 
+
+};
+
+
+//////////////////////////////////////////////////////////////////////
+//BEGIN XOR.cpp
+//////////////////////////////////////////////////////////////////////
+inline void XorHandler::add( std::vector<Arg*>& ors )
+{ 
+	_orList.push_back( ors );
+}
+
+inline int XorHandler::check( const Arg* a ) 
+{
+	// iterate over each XOR list
+	for ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )
+	{
+		// if the XOR list contains the arg..
+		ArgVectorIterator ait = std::find( _orList[i].begin(), 
+		                                   _orList[i].end(), a );
+		if ( ait != _orList[i].end() )
+		{
+			// first check to see if a mutually exclusive switch
+			// has not already been set
+			for ( ArgVectorIterator it = _orList[i].begin(); 
+				  it != _orList[i].end(); 
+				  it++ )
+				if ( a != (*it) && (*it)->isSet() )
+					throw(CmdLineParseException(
+					      "Mutually exclusive argument already set!",
+					      (*it)->toString()));
+
+			// go through and set each arg that is not a
+			for ( ArgVectorIterator it = _orList[i].begin(); 
+				  it != _orList[i].end(); 
+				  it++ )
+				if ( a != (*it) )
+					(*it)->xorSet();
+
+			// return the number of required args that have now been set
+			if ( (*ait)->allowMore() )
+				return 0;
+			else
+				return static_cast<int>(_orList[i].size());
+		}
+	}
+
+	if ( a->isRequired() )
+		return 1;
+	else
+		return 0;
+}
+
+inline bool XorHandler::contains( const Arg* a )
+{
+	for ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )
+		for ( ArgVectorIterator it = _orList[i].begin(); 
+			  it != _orList[i].end(); 
+			  it++ )	
+			if ( a == (*it) )
+				return true;
+
+	return false;
+}
+
+inline std::vector< std::vector<Arg*> >& XorHandler::getXorList() 
+{
+	return _orList;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////
+//END XOR.cpp
+//////////////////////////////////////////////////////////////////////
+
+} //namespace TCLAP
+
+#endif 
diff --git a/pub/ThirdParty/tclap/ZshCompletionOutput.h b/pub/ThirdParty/tclap/ZshCompletionOutput.h
new file mode 100644
index 0000000000000000000000000000000000000000..0b37fc7296c6b5f4179467318d590c350fb84832
--- /dev/null
+++ b/pub/ThirdParty/tclap/ZshCompletionOutput.h
@@ -0,0 +1,323 @@
+// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
+
+/****************************************************************************** 
+ * 
+ *  file:  ZshCompletionOutput.h
+ * 
+ *  Copyright (c) 2006, Oliver Kiddle
+ *  All rights reverved.
+ * 
+ *  See the file COPYING in the top directory of this distribution for
+ *  more information.
+ *  
+ *  THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS 
+ *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
+ *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
+ *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+ *  DEALINGS IN THE SOFTWARE.
+ *  
+ *****************************************************************************/ 
+
+#ifndef TCLAP_ZSHCOMPLETIONOUTPUT_H
+#define TCLAP_ZSHCOMPLETIONOUTPUT_H
+
+#include <string>
+#include <vector>
+#include <list>
+#include <iostream>
+#include <map>
+
+#include <tclap/CmdLineInterface.h>
+#include <tclap/CmdLineOutput.h>
+#include <tclap/XorHandler.h>
+#include <tclap/Arg.h>
+
+namespace TCLAP {
+
+/**
+ * A class that generates a Zsh completion function as output from the usage()
+ * method for the given CmdLine and its Args.
+ */
+class ZshCompletionOutput : public CmdLineOutput
+{
+
+	public:
+
+		ZshCompletionOutput();
+
+		/**
+		 * Prints the usage to stdout.  Can be overridden to 
+		 * produce alternative behavior.
+		 * \param c - The CmdLine object the output is generated for. 
+		 */
+		virtual void usage(CmdLineInterface& c);
+
+		/**
+		 * Prints the version to stdout. Can be overridden 
+		 * to produce alternative behavior.
+		 * \param c - The CmdLine object the output is generated for. 
+		 */
+		virtual void version(CmdLineInterface& c);
+
+		/**
+		 * Prints (to stderr) an error message, short usage 
+		 * Can be overridden to produce alternative behavior.
+		 * \param c - The CmdLine object the output is generated for. 
+		 * \param e - The ArgException that caused the failure. 
+		 */
+		virtual void failure(CmdLineInterface& c,
+						     ArgException& e );
+
+	protected:
+
+		void basename( std::string& s );
+		void quoteSpecialChars( std::string& s );
+
+		std::string getMutexList( CmdLineInterface& _cmd, Arg* a );
+		void printOption( Arg* it, std::string mutex );
+		void printArg( Arg* it );
+
+		std::map<std::string, std::string> common;
+		char theDelimiter;
+};
+
+ZshCompletionOutput::ZshCompletionOutput()
+: common(std::map<std::string, std::string>()),
+  theDelimiter('=')
+{
+	common["host"] = "_hosts";
+	common["hostname"] = "_hosts";
+	common["file"] = "_files";
+	common["filename"] = "_files";
+	common["user"] = "_users";
+	common["username"] = "_users";
+	common["directory"] = "_directories";
+	common["path"] = "_directories";
+	common["url"] = "_urls";
+}
+
+inline void ZshCompletionOutput::version(CmdLineInterface& _cmd)
+{
+	std::cout << _cmd.getVersion() << std::endl;
+}
+
+inline void ZshCompletionOutput::usage(CmdLineInterface& _cmd )
+{
+	std::list<Arg*> argList = _cmd.getArgList();
+	std::string progName = _cmd.getProgramName();
+	std::string xversion = _cmd.getVersion();
+	theDelimiter = _cmd.getDelimiter();
+	basename(progName);
+
+	std::cout << "#compdef " << progName << std::endl << std::endl <<
+		"# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl <<
+		"_arguments -s -S";
+
+	for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
+	{
+		if ( (*it)->shortID().at(0) == '<' )
+			printArg((*it));
+		else if ( (*it)->getFlag() != "-" )
+			printOption((*it), getMutexList(_cmd, *it));
+	}
+
+	std::cout << std::endl;
+}
+
+inline void ZshCompletionOutput::failure( CmdLineInterface& _cmd,
+				                ArgException& e )
+{
+	static_cast<void>(_cmd); // unused
+	std::cout << e.what() << std::endl;
+}
+
+inline void ZshCompletionOutput::quoteSpecialChars( std::string& s )
+{
+	size_t idx = s.find_last_of(':');
+	while ( idx != std::string::npos )
+	{
+		s.insert(idx, 1, '\\');
+		idx = s.find_last_of(':', idx);
+	}
+	idx = s.find_last_of('\'');
+	while ( idx != std::string::npos )
+	{
+		s.insert(idx, "'\\'");
+		if (idx == 0)
+			idx = std::string::npos;
+		else
+			idx = s.find_last_of('\'', --idx);
+	}
+}
+
+inline void ZshCompletionOutput::basename( std::string& s )
+{
+	size_t p = s.find_last_of('/');
+	if ( p != std::string::npos )
+	{
+		s.erase(0, p + 1);
+	}
+}
+
+inline void ZshCompletionOutput::printArg(Arg* a)
+{
+	static int count = 1;
+
+	std::cout << " \\" << std::endl << "  '";
+	if ( a->acceptsMultipleValues() )
+		std::cout << '*';
+	else
+		std::cout << count++;
+	std::cout << ':';
+	if ( !a->isRequired() )
+		std::cout << ':';
+
+	std::cout << a->getName() << ':';
+	std::map<std::string, std::string>::iterator compArg = common.find(a->getName());
+	if ( compArg != common.end() )
+	{
+		std::cout << compArg->second;
+	}
+	else
+	{
+		std::cout << "_guard \"^-*\" " << a->getName();
+	}
+	std::cout << '\'';
+}
+
+inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex)
+{
+	std::string flag = a->flagStartChar() + a->getFlag();
+	std::string name = a->nameStartString() + a->getName();
+	std::string desc = a->getDescription();
+
+	// remove full stop and capitalisation from description as
+	// this is the convention for zsh function
+	if (!desc.compare(0, 12, "(required)  "))
+	{
+		desc.erase(0, 12);
+	}
+	if (!desc.compare(0, 15, "(OR required)  "))
+	{
+		desc.erase(0, 15);
+	}
+	size_t len = desc.length();
+	if (len && desc.at(--len) == '.')
+	{
+		desc.erase(len);
+	}
+	if (len)
+	{
+		desc.replace(0, 1, 1, tolower(desc.at(0)));
+	}
+
+	std::cout << " \\" << std::endl << "  '" << mutex;
+
+	if ( a->getFlag().empty() )
+	{
+		std::cout << name;
+	}
+	else
+	{
+		std::cout << "'{" << flag << ',' << name << "}'";
+	}
+	if ( theDelimiter == '=' && a->isValueRequired() )
+		std::cout << "=-";
+	quoteSpecialChars(desc);
+	std::cout << '[' << desc << ']';
+
+	if ( a->isValueRequired() )
+	{
+		std::string arg = a->shortID();
+		arg.erase(0, arg.find_last_of(theDelimiter) + 1);
+		if ( arg.at(arg.length()-1) == ']' )
+			arg.erase(arg.length()-1);
+		if ( arg.at(arg.length()-1) == ']' )
+		{
+			arg.erase(arg.length()-1);
+		}
+		if ( arg.at(0) == '<' )
+		{
+			arg.erase(arg.length()-1);
+			arg.erase(0, 1);
+		}
+		size_t p = arg.find('|');
+		if ( p != std::string::npos )
+		{
+			do
+			{
+				arg.replace(p, 1, 1, ' ');
+			}
+			while ( (p = arg.find_first_of('|', p)) != std::string::npos );
+			quoteSpecialChars(arg);
+			std::cout << ": :(" << arg << ')';
+		}
+		else
+		{
+			std::cout << ':' << arg;
+			std::map<std::string, std::string>::iterator compArg = common.find(arg);
+			if ( compArg != common.end() )
+			{
+				std::cout << ':' << compArg->second;
+			}
+		}
+	}
+
+	std::cout << '\'';
+}
+
+inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Arg* a)
+{
+	XorHandler xorHandler = _cmd.getXorHandler();
+	std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
+	
+	if (a->getName() == "help" || a->getName() == "version")
+	{
+		return "(-)";
+	}
+
+	std::ostringstream list;
+	if ( a->acceptsMultipleValues() )
+	{
+		list << '*';
+	}
+
+	for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
+	{
+		for ( ArgVectorIterator it = xorList[i].begin();
+			it != xorList[i].end();
+			it++)
+		if ( a == (*it) )
+		{
+			list << '(';
+			for ( ArgVectorIterator iu = xorList[i].begin();
+				iu != xorList[i].end();
+				iu++ )
+			{
+				bool notCur = (*iu) != a;
+				bool hasFlag = !(*iu)->getFlag().empty();
+				if ( iu != xorList[i].begin() && (notCur || hasFlag) )
+					list << ' ';
+				if (hasFlag)
+					list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' ';
+				if ( notCur || hasFlag )
+					list << (*iu)->nameStartString() << (*iu)->getName();
+			}
+			list << ')';
+			return list.str();
+		}
+	}
+	
+	// wasn't found in xor list
+	if (!a->getFlag().empty()) {
+		list << "(" << a->flagStartChar() << a->getFlag() << ' ' <<
+			a->nameStartString() << a->getName() << ')';
+	}
+	
+	return list.str();
+}
+
+} //namespace TCLAP
+#endif
diff --git a/pub/cmake/scripts/CTestCustom.cmake.in b/pub/cmake/scripts/CTestCustom.cmake.in
index 85ee881065af6d348b71d02d7525c35000e80d58..a6cae54447a736bae3c88129627a507015391f75 100644
--- a/pub/cmake/scripts/CTestCustom.cmake.in
+++ b/pub/cmake/scripts/CTestCustom.cmake.in
@@ -1 +1,2 @@
+set(CTEST_CUSTOM_PRE_TEST "echo To run ctest before make install, unset LD_LIBRARY_PATH")
 set(CTEST_CUSTOM_POST_TEST "echo For details, see the log files in Testing/Temporary/")
diff --git a/pub/ftest/CMakeLists.txt b/pub/ftest/CMakeLists.txt
index 742c691c1bc256100b12d240e85d1594ca23031d..40112f1eeef198c72b656518f929ceaa678d6c20 100644
--- a/pub/ftest/CMakeLists.txt
+++ b/pub/ftest/CMakeLists.txt
@@ -11,13 +11,17 @@ enable_testing()
 file(GLOB test_sources "*.f2t")
 list(SORT test_sources)
 
+# This one-line script ensures termination of the functional test.
+# It is only executed if the test script terminates without reaching an 'exit' command.
+set(exit1file "${CMAKE_BINARY_DIR}/exit1file.f2s")
+file(WRITE ${exit1file} "exit(1)")
+
 foreach(test_src ${test_sources})
     # remove directory path and suffix, to retain just the name of the test
     string(REGEX REPLACE ".*/" "" test_name "${test_src}")
-    string(REGEX REPLACE ".f2t$" "" test_name "${test_name}")
+    string(REGEX REPLACE "\\.f2t$" "" test_name "${test_name}")
     add_test(
         NAME ${test_name}
-        COMMAND ${CMAKE_BINARY_DIR}/src/frida
-        ARGUMENTS ${test_src}
+        COMMAND ${CMAKE_BINARY_DIR}/src/frida ${test_src} ${exit1file}
         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
 endforeach(test_src)
diff --git a/pub/ftest/mpa.f2t b/pub/ftest/mpa.f2t
index f88813c16b3947cd2a82684e197e24782fa56fe8..a6ad824249faf8e48ead71983ab1be38c43fbeb2 100755
--- a/pub/ftest/mpa.f2t
+++ b/pub/ftest/mpa.f2t
@@ -1,9 +1,12 @@
 #!/usr/bin/env frida
 fm 9 1 h
 0 oy 3+i
+1 oy! y+-sqrt(y)
 1 mpa 0,3
 exit_unless(abs(y[2,0,0]-(3+1))<1e-15,"mpa_test11")
 exit_unless(abs(y[2,0,1]-(3+5.5))<1e-15,"mpa_test12")
+exit_unless(dy[2,0,1]>sqrt(6)/sqrt(6),"mpa_test13")
+exit_unless(dy[2,0,1]<sqrt(12)/sqrt(6),"mpa_test13")
 1 mpaf 3
 exit_unless(ni[3,0]==3,"mpa_test20")
 exit_unless(abs(y[3,0,0]-(3+1))<1e-15,"mpa_test21")
@@ -12,4 +15,8 @@ exit_unless(abs(y[3,0,2]-(3+7))<1e-15,"mpa_test22")
 exit_unless(ni[4,0]==2,"mpa_test30")
 exit_unless(abs(y[4,0,0]-(3+1.5))<1e-15,"mpa_test31")
 exit_unless(abs(y[4,0,1]-(3+5.5))<1e-15,"mpa_test32")
+1 mpas 0,3
+exit_unless(abs(y[5,0,0]-(3+1))<1e-15,"mpa_test51")
+exit_unless(abs(y[5,0,1]-(3+5.5))<1e-15,"mpa_test52")
+exit_unless(dy[5,0,0]>dy[2,0,0],"mpa_test53")
 exit(0)
diff --git a/pub/ftest/oi_idxwith.f2t b/pub/ftest/oi_idxwith.f2t
new file mode 100755
index 0000000000000000000000000000000000000000..99a3be4ad5028e6fd305707c6abc50c7d1077a10
--- /dev/null
+++ b/pub/ftest/oi_idxwith.f2t
@@ -0,0 +1,6 @@
+#!/usr/bin/env frida
+fm 11 1 h
+oy i^2
+exit_unless(firstwith(y>10)==4,"firstwith_wrong")
+exit_unless(lastwith(y>7*sqrt(y))==8,"lastwith_wrong")
+exit(0)
\ No newline at end of file
diff --git a/pub/ftest/oxy_idep.f2t b/pub/ftest/oxy_idep.f2t
new file mode 100755
index 0000000000000000000000000000000000000000..286198e3731a057a841fc1bf214dc379291a2517
--- /dev/null
+++ b/pub/ftest/oxy_idep.f2t
@@ -0,0 +1,19 @@
+#!/usr/bin/env frida
+# pointwise operations with i dependent indices
+fm 3 3 h1
+ox! 100+j*10+i
+exit_unless(x[,1,1]==111,"test1")
+oy! x[,,i]
+exit_unless(y[,1,1]==111,"test2")
+oy! x[,,ni-1-i]
+exit_unless(y[,1,0]==112,"test3")
+oy! x[,,i-i]
+exit_unless(y[,1,2]==110,"test4")
+oy! x[,i-i,1]
+exit_unless(y[,1,2]==101,"test5")
+oy! x[i-i,2,0]
+exit_unless(y[,1,2]==120,"test6")
+oy! x[,i,j]
+exit_unless(y[,1,2]==121,"test7")
+exit_unless(y[,2,1]==112,"test8")
+exit(0)
\ No newline at end of file
diff --git a/pub/itest/checkIntegrity.ps b/pub/itest/checkIntegrity.ps
new file mode 100644
index 0000000000000000000000000000000000000000..d31a46fd4bb09d2a8803ab072e57b626a7b2912c
--- /dev/null
+++ b/pub/itest/checkIntegrity.ps
@@ -0,0 +1,16 @@
+    {Script run} stopped
+    {
+       (\n===> Integrity test failed: ) print Script print ( has error\n\n) print
+       handleerror
+       (ignore this error which only serves to force a return value of 1) /syntaxerror signalerror
+    }{
+       % script passed, now check the stack
+       count dup 0 eq {
+          pop (\n===> Integrity test passed: ) print Script print ( terminated normally\n\n) print
+       } {
+          (\n===> Integrity test failed: ) print Script print ( left ) print
+          3 string cvs print ( item(s) on stack\n\n) print
+          Script /syntaxerror signalerror
+       } ifelse
+    } ifelse
+    quit
diff --git a/pub/itest/curveplot.f2t b/pub/itest/curveplot.f2t
new file mode 100755
index 0000000000000000000000000000000000000000..b2a4287d9759d1dbde176c192f42c1a85a277772
--- /dev/null
+++ b/pub/itest/curveplot.f2t
@@ -0,0 +1,89 @@
+#!/usr/bin/env frida
+! rm -f /tmp/P.ps
+ps_setup1D="setup_wallpaper.ps"
+gnc 100
+cca p0+p1*t
+op0 100000
+g0
+gx 0 1
+gya
+p
+gp /tmp/P
+op0 -.5
+gya
+p
+gfa /tmp/P.ps
+op1 50
+op0 -.47319*p1
+p
+gfa /tmp/P.ps
+op0 .4
+op1 3
+p
+gfa /tmp/P.ps
+op0 768.34
+op1 0
+gya
+p
+gfa /tmp/P.ps
+cr t<.52||.53<t&&t<.61||.65<t
+gya
+p
+gfa /tmp/P.ps
+cca sin(t)
+gx 0 80
+gya
+p
+gfa /tmp/P.ps
+gy -.5 .5
+p
+gfa /tmp/P.ps
+cca t^p0
+op0 5
+gx -2 2
+gya
+p
+gfa /tmp/P.ps
+op0 15
+gya
+p
+gfa /tmp/P.ps
+op0 35
+gya
+p
+gfa /tmp/P.ps
+cca t<-2?0:t^p0
+op0 5
+gx -3 2
+gya
+p
+gfa /tmp/P.ps
+op0 25
+gya
+p
+gfa /tmp/P.ps
+op0 26
+gya
+p
+gfa /tmp/P.ps
+cca p0+p1*t
+cr .2<t && t<.730812
+gx 0 1
+gya
+p
+gfa /tmp/P.ps
+gy -3 0
+p
+gfa /tmp/P.ps
+cca sin(t)
+cr abs(f(t))<.3
+gx 0 40
+gy -1.1 .9
+p
+gfa /tmp/P.ps
+cca ln(abs(sin(t)))
+gx 0 20
+gy -12 1
+p
+gfa /tmp/P.ps
+qui
diff --git a/pub/itest/grid40x20.yda b/pub/itest/grid40x20.yda
new file mode 100644
index 0000000000000000000000000000000000000000..cf07673ea1768555214fe74814372abda8e89be2
--- /dev/null
+++ b/pub/itest/grid40x20.yda
@@ -0,0 +1,94 @@
+Meta:
+  format: yaml/frida 2.0
+  type: generic tabular data
+History:
+  - fm 40 20
+  - oy (i+j)*sin(i-j)
+  - "fs grid40x20.yda # 2017-03-18 Sat 10:10:24 CET"
+Coord:
+  x: {name: x, unit: ""}
+  y: {name: i+j*sin(i-j), unit: ""}
+  z: [{name: z, unit: ""}]
+RPar:
+  []
+Slices:
+  - j: 0
+    z: [{val: 0}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [0, 0.8414709848078965, 1.818594853651363, 0.4233600241796016, -3.027209981231713, -4.794621373315692, -1.676492989193555, 4.598906191031523, 7.914865972987054, 3.709066367175809, -5.440211108893697, -10.99989227205774, -6.43887501600522, 5.462171478746332, 13.86850297972818, 9.754317602356753, -4.606453066641045, -16.34375736195247, -13.51777044189017, 2.847666983596095, 18.25890501455255, 17.56976840925718, -0.1947288043888853, -19.46306929602892, -21.73388068815897, -3.308793752444326, 19.82651971246967, 25.82215006692158, 7.585362072620333, -19.24538264217606, -29.64094872278585, -12.52516700501502, 17.6456537997341, 32.99709138353982, 17.98881132808081, -14.98639343236529, -35.70403872395217, -23.81091093420898, 11.26200599095664, 37.58802006507943]
+  - j: 1
+    z: [{val: 1}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [-0.8414709848078965, 0, 2.524412954423689, 3.637189707302727, 0.7056000402993361, -4.540814971847569, -6.71246992264197, -2.235323985591407, 5.912879388469102, 9.893582466233818, 4.533303337659323, -6.528253330672437, -12.99987268515915, -7.512020852006089, 6.302505552399614, 15.84971769111793, 11.05489328267099, -5.182259699971175, -18.26655234571158, -15.01974493543352, 3.147421402921999, 20.08479551600781, 19.24307968632929, -0.212431422969693, -21.15551010437927, -23.54503741217222, -3.573497252639872, 21.35163661342888, 27.73490192373059, 8.127173649236072, -20.57265041060199, -31.61701197097158, -13.33324229566115, 18.74850716221748, 34.99691510375435, 19.04697670032086, -15.84275877135759, -37.6875964308384, -25.09798720092298, 11.85474314837541]
+  - j: 2
+    z: [{val: 2}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [-1.818594853651363, -2.524412954423689, 0, 4.207354924039483, 5.45578456095409, 0.9878400564190705, -6.054419962463426, -8.630318471968247, -2.794154981989259, 7.22685258590668, 11.87229895948058, 5.357540308142836, -7.616295552451177, -14.99985309826055, -8.585166688006959, 7.142839626052895, 17.83093240250767, 12.35546896298522, -5.758066333301306, -20.18934732947069, -16.52171942897687, 3.447175822247904, 21.91068601746306, 20.9163909634014, -0.2301340415505008, -22.84795091272961, -25.35619413618547, -3.838200752835418, 22.87675351438808, 29.64765378053959, 8.668985225851809, -21.89991817902793, -33.5930752191573, -14.14131758630728, 19.85136052470086, 36.99673882396888, 20.10514207256091, -16.69912411034989, -39.67115413772463, -26.38506346763698]
+  - j: 3
+    z: [{val: 3}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [-0.4233600241796016, -3.637189707302727, -4.207354924039483, 0, 5.890296893655275, 7.274379414605454, 1.270080072538805, -7.568024953079282, -10.54816702129452, -3.35298597838711, 8.540825783344257, 13.85101545272735, 6.181777278626349, -8.704337774229916, -16.99983351136196, -9.65831252400783, 7.983173699706177, 19.81214711389741, 13.65604464329945, -6.333872966631437, -22.11214231322981, -18.02369392252022, 3.746930241573808, 23.73657651891832, 22.58970224047351, -0.2478366601313085, -24.54039172107995, -27.16735086019872, -4.102904253030964, 24.40187041534729, 31.5604056373486, 9.210796802467547, -23.22718594745387, -35.56913846734302, -14.94939287695341, 20.95421388718424, 38.99656254418342, 21.16330744480095, -17.55548944934219, -41.65471184461087]
+  - j: 4
+    z: [{val: 4}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [3.027209981231713, -0.7056000402993361, -5.45578456095409, -5.890296893655275, 0, 7.573238863271069, 9.092974268256818, 1.552320088658539, -9.081629943695138, -12.4660155706208, -3.911816974784962, 9.854798980781837, 15.82973194597411, 7.006014249109862, -9.792379996008655, -18.99981392446337, -10.7314583600087, 8.823507773359459, 21.79336182528715, 14.95662032361369, -6.909679599961567, -24.03493729698892, -19.52566841606358, 4.046684660899714, 25.56246702037357, 24.26301351754563, -0.2655392787121163, -26.23283252943029, -28.97850758421196, -4.36760775322651, 25.92698731630649, 33.4731574941576, 9.752608379083286, -24.5544537158798, -37.54520171552875, -15.75746816759954, 22.05706724966763, 40.99638626439796, 22.221472817041, -18.41185478833449]
+  - j: 5
+    z: [{val: 5}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [4.794621373315692, 4.540814971847569, -0.9878400564190705, -7.274379414605454, -7.573238863271069, 0, 9.256180832886862, 10.91156912190818, 1.834560104778274, -10.59523493431099, -14.38386411994708, -4.470647971182814, 11.16877217821941, 17.80844843922087, 7.830251219593375, -10.88042221778739, -20.99979433756477, -11.80460419600957, 9.663841847012741, 23.77457653667689, 16.25719600392792, -7.485486233291698, -25.95773228074803, -21.02764290960693, 4.346439080225618, 27.38835752182883, 25.93632479461774, -0.283241897292924, -27.92527333778063, -30.78966430822521, -4.632311253422056, 27.4521042172657, 35.38590935096661, 10.29441995569902, -25.88172148430574, -39.52126496371447, -16.56554345824567, 23.15992061215101, 42.99620998461249, 23.27963818928105]
+  - j: 6
+    z: [{val: 6}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [1.676492989193555, 6.71246992264197, 6.054419962463426, -1.270080072538805, -9.092974268256818, -9.256180832886862, 0, 10.93912280250265, 12.73016397555954, 2.116800120898008, -12.10883992492685, -16.30171266927335, -5.029478967580665, 12.48274537565699, 19.78716493246764, 8.654488190076888, -11.96846443956614, -22.99977475066618, -12.87775003201044, 10.50417592066602, 25.75579124806663, 17.55777168424216, -8.061292866621828, -27.88052726450715, -22.52961740315028, 4.646193499551523, 29.21424802328409, 27.60963607168985, -0.3009445158737318, -29.61771414613097, -32.60082103223846, -4.897014753617603, 28.9772211182249, 37.29866120777562, 10.83623153231476, -27.20898925273167, -41.4973282119002, -17.3736187488918, 24.26277397463438, 44.99603370482702]
+  - j: 7
+    z: [{val: 7}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [-4.598906191031523, 2.235323985591407, 8.630318471968247, 7.568024953079282, -1.552320088658539, -10.91156912190818, -10.93912280250265, 0, 12.62206477211845, 14.54875882921091, 2.399040137017743, -13.62244491554271, -18.21956121859963, -5.588309963978517, 13.79671857309457, 21.7658814257144, 9.478725160560401, -13.05650666134487, -24.99975516376759, -13.95089586801131, 11.3445099943193, 27.73700595945637, 18.85834736455639, -8.637099499951958, -29.80332224826626, -24.03159189669363, 4.945947918877427, 31.04013852473934, 29.28294734876196, -0.3186471344545395, -31.31015495448131, -34.41197775625171, -5.161718253813148, 30.50233801918411, 39.21141306458463, 11.3780431089305, -28.5362570211576, -43.47339146008592, -18.18169403953793, 25.36562733711777]
+  - j: 8
+    z: [{val: 8}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [-7.914865972987054, -5.912879388469102, 2.794154981989259, 10.54816702129452, 9.081629943695138, -1.834560104778274, -12.73016397555954, -12.62206477211845, 0, 14.30500674173424, 16.36735368286227, 2.681280153137477, -15.13604990615856, -20.13740976792591, -6.147140960376369, 15.11069177053215, 23.74459791896116, 10.30296213104391, -14.14454888312361, -26.99973557686899, -15.02404170401218, 12.18484406797259, 29.71822067084611, 20.15892304487062, -9.21290613328209, -31.72611723202537, -25.53356639023698, 5.245702338203332, 32.8660290261946, 30.95625862583407, -0.3363497530353473, -33.00259576283165, -36.22313448026495, -5.426421754008694, 32.02745492014331, 41.12416492139363, 11.91985468554624, -29.86352478958354, -45.44945470827165, -18.98976933018406]
+  - j: 9
+    z: [{val: 9}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [-3.709066367175809, -9.893582466233818, -7.22685258590668, 3.35298597838711, 12.4660155706208, 10.59523493431099, -2.116800120898008, -14.54875882921091, -14.30500674173424, 0, 15.98794871135003, 18.18594853651364, 2.963520169257211, -16.64965489677442, -22.05525831725219, -6.705971956774221, 16.42466496796973, 25.72331441220793, 11.12719910152743, -15.23259110490235, -28.9997159899704, -16.09718754001305, 13.02517814162587, 31.69943538223585, 21.45949872518485, -9.788712766612221, -33.64891221578449, -27.03554088378034, 5.545456757529236, 34.69191952764985, 32.62956990290618, -0.354052371616155, -34.69503657118199, -38.0342912042782, -5.69112525420424, 33.55257182110252, 43.03691677820264, 12.46166626216198, -31.19079255800947, -47.42551795645737]
+  - j: 10
+    z: [{val: 10}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [5.440211108893697, -4.533303337659323, -11.87229895948058, -8.540825783344257, 3.911816974784962, 14.38386411994708, 12.10883992492685, -2.399040137017743, -16.36735368286227, -15.98794871135003, 0, 17.67089068096583, 20.004543390165, 3.245760185376946, -18.16325988739028, -23.97310686657846, -7.264802953172072, 17.73863816540731, 27.70203090545469, 11.95143607201094, -16.32063332668109, -30.99969640307181, -17.17033337601392, 13.86551221527915, 33.68065009362559, 22.76007440549909, -10.36451939994235, -35.5717071995436, -28.53751537732369, 5.845211176855141, 36.51781002910511, 34.3028811799783, -0.3717549901969628, -36.38747737953233, -39.84544792829145, -5.955828754399787, 35.07768872206172, 44.94966863501164, 13.00347783877771, -32.51806032643541]
+  - j: 11
+    z: [{val: 11}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [10.99989227205774, 6.528253330672437, -5.357540308142836, -13.85101545272735, -9.854798980781837, 4.470647971182814, 16.30171266927335, 13.62244491554271, -2.681280153137477, -18.18594853651364, -17.67089068096583, 0, 19.35383265058162, 21.82313824381636, 3.52800020149668, -19.67686487800613, -25.89095541590474, -7.823633949569924, 19.05261136284488, 29.68074739870145, 12.77567304249445, -17.40867554845983, -32.99967681617321, -18.24347921201479, 14.70584628893243, 35.66186480501533, 24.06065008581332, -10.94032603327248, -37.49450218330271, -30.03948987086704, 6.144965596181046, 38.34370053056036, 35.97619245705041, -0.3894576087777706, -38.07991818788268, -41.6566046523047, -6.220532254595333, 36.60280562302093, 46.86242049182065, 13.54528941539345]
+  - j: 12
+    z: [{val: 12}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [6.43887501600522, 12.99987268515915, 7.616295552451177, -6.181777278626349, -15.82973194597411, -11.16877217821941, 5.029478967580665, 18.21956121859963, 15.13604990615856, -2.963520169257211, -20.004543390165, -19.35383265058162, 0, 21.03677462019741, 23.64173309746772, 3.810240217616415, -21.19046986862199, -27.80880396523101, -8.382464945967776, 20.36658456028246, 31.65946389194822, 13.59991001297797, -18.49671777023857, -34.99965722927463, -19.31662504801566, 15.54618036258571, 37.64307951640507, 25.36122576612756, -11.51613266660261, -39.41729716706183, -31.54146436441039, 6.444720015506951, 40.16959103201562, 37.64950373412253, -0.4071602273585783, -39.77235899623302, -43.46776137631795, -6.485235754790878, 38.12792252398013, 48.77517234862965]
+  - j: 13
+    z: [{val: 13}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [-5.462171478746332, 7.512020852006089, 14.99985309826055, 8.704337774229916, -7.006014249109862, -17.80844843922087, -12.48274537565699, 5.588309963978517, 20.13740976792591, 16.64965489677442, -3.245760185376946, -21.82313824381636, -21.03677462019741, 0, 22.71971658981321, 25.46032795111909, 4.092480233736149, -22.70407485923785, -29.72665251455729, -8.941295942365628, 21.68055775772004, 33.63818038519498, 14.42414698346148, -19.58475999201731, -36.99963764237603, -20.38977088401653, 16.386514436239, 39.62429422779481, 26.66180144644179, -12.09193929993274, -41.34009215082094, -33.04343885795375, 6.744474434832855, 41.99548153347087, 39.32281501119463, -0.4248628459393861, -41.46479980458336, -45.2789181003312, -6.749939254986424, 39.65303942493934]
+  - j: 14
+    z: [{val: 14}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [-13.86850297972818, -6.302505552399614, 8.585166688006959, 16.99983351136196, 9.792379996008655, -7.830251219593375, -19.78716493246764, -13.79671857309457, 6.147140960376369, 22.05525831725219, 18.16325988739028, -3.52800020149668, -23.64173309746772, -22.71971658981321, 0, 24.402658559429, 27.27892280477045, 4.374720249855883, -24.2176798498537, -31.64450106388357, -9.500126938763479, 22.99453095515762, 35.61689687844174, 15.24838395394499, -20.67280221379605, -38.99961805547743, -21.4629167200174, 17.22684850989228, 41.60550893918455, 27.96237712675602, -12.66774593326287, -43.26288713458005, -34.5454133514971, 7.04422885415876, 43.82137203492613, 40.99612628826674, -0.4425654645201938, -43.15724061293371, -47.09007482434444, -7.014642755181971]
+  - j: 15
+    z: [{val: 15}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [-9.754317602356753, -15.84971769111793, -7.142839626052895, 9.65831252400783, 18.99981392446337, 10.88042221778739, -8.654488190076888, -21.7658814257144, -15.11069177053215, 6.705971956774221, 23.97310686657846, 19.67686487800613, -3.810240217616415, -25.46032795111909, -24.402658559429, 0, 26.08560052904479, 29.09751765842181, 4.656960265975618, -25.73128484046956, -33.56234961320985, -10.05895793516133, 24.30850415259519, 37.59561337168851, 16.07262092442851, -21.76084443557479, -40.99959846857885, -22.53606255601827, 18.06718258354556, 43.58672365057429, 29.26295280707026, -13.243552566593, -45.18568211833917, -36.04738784504045, 7.343983273484665, 45.64726253638138, 42.66943756533886, -0.4602680831010015, -44.84968142128405, -48.90123154835769]
+  - j: 16
+    z: [{val: 16}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [4.606453066641045, -11.05489328267099, -17.83093240250767, -7.983173699706177, 10.7314583600087, 20.99979433756477, 11.96846443956614, -9.478725160560401, -23.74459791896116, -16.42466496796973, 7.264802953172072, 25.89095541590474, 21.19046986862199, -4.092480233736149, -27.27892280477045, -26.08560052904479, 0, 27.76854249866058, 30.91611251207318, 4.939200282095353, -27.24488983108542, -35.48019816253612, -10.61778893155918, 25.62247735003277, 39.57432986493527, 16.89685789491202, -22.84888665735353, -42.99957888168025, -23.60920839201914, 18.90751665719884, 45.56793836196404, 30.56352848738449, -13.81935919992313, -47.10847710209828, -37.5493623385838, 7.64373769281057, 47.47315303783664, 44.34274884241097, -0.4779707016818093, -46.54212222963439]
+  - j: 17
+    z: [{val: 17}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [16.34375736195247, 5.182259699971175, -12.35546896298522, -19.81214711389741, -8.823507773359459, 11.80460419600957, 22.99977475066618, 13.05650666134487, -10.30296213104391, -25.72331441220793, -17.73863816540731, 7.823633949569924, 27.80880396523101, 22.70407485923785, -4.374720249855883, -29.09751765842181, -27.76854249866058, 0, 29.45148446827638, 32.73470736572454, 5.221440298215087, -28.75849482170127, -37.3980467118624, -11.17661992795703, 26.93645054747035, 41.55304635818204, 17.72109486539553, -23.93692887913227, -44.99955929478165, -24.68235422802001, 19.74785073085212, 47.54915307335378, 31.86410416769872, -14.39516583325327, -49.0312720858574, -39.05133683212716, 7.943492112136474, 49.29904353929189, 46.01606011948309, -0.4956733202626171]
+  - j: 18
+    z: [{val: 18}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [13.51777044189017, 18.26655234571158, 5.758066333301306, -13.65604464329945, -21.79336182528715, -9.663841847012741, 12.87775003201044, 24.99975516376759, 14.14454888312361, -11.12719910152743, -27.70203090545469, -19.05261136284488, 8.382464945967776, 29.72665251455729, 24.2176798498537, -4.656960265975618, -30.91611251207318, -29.45148446827638, 0, 31.13442643789217, 34.55330221937591, 5.503680314334821, -30.27209981231713, -39.31589526118868, -11.73545092435489, 28.25042374490793, 43.5317628514288, 18.54533183587905, -25.02497110091101, -46.99953970788307, -25.75550006402088, 20.58818480450541, 49.53036778474352, 33.16467984801296, -14.9709724665834, -50.95406706961651, -40.55331132567051, 8.243246531462379, 51.12493404074715, 47.6893713965552]
+  - j: 19
+    z: [{val: 19}]
+    x: [0, 0.02564102564102564, 0.05128205128205128, 0.07692307692307693, 0.1025641025641026, 0.1282051282051282, 0.1538461538461539, 0.1794871794871795, 0.2051282051282051, 0.2307692307692308, 0.2564102564102564, 0.282051282051282, 0.3076923076923077, 0.3333333333333333, 0.358974358974359, 0.3846153846153846, 0.4102564102564102, 0.4358974358974359, 0.4615384615384616, 0.4871794871794872, 0.5128205128205128, 0.5384615384615384, 0.5641025641025641, 0.5897435897435898, 0.6153846153846154, 0.6410256410256411, 0.6666666666666666, 0.6923076923076923, 0.717948717948718, 0.7435897435897436, 0.7692307692307693, 0.7948717948717948, 0.8205128205128205, 0.8461538461538461, 0.8717948717948718, 0.8974358974358975, 0.9230769230769231, 0.9487179487179487, 0.9743589743589743, 1]
+    y: [-2.847666983596095, 15.01974493543352, 20.18934732947069, 6.333872966631437, -14.95662032361369, -23.77457653667689, -10.50417592066602, 13.95089586801131, 26.99973557686899, 15.23259110490235, -11.95143607201094, -29.68074739870145, -20.36658456028246, 8.941295942365628, 31.64450106388357, 25.73128484046956, -4.939200282095353, -32.73470736572454, -31.13442643789217, 0, 32.81736840750796, 36.37189707302727, 5.785920330454556, -31.78570480293298, -41.23374381051495, -12.29428192075274, 29.56439694234551, 45.51047934467556, 19.36956880636256, -26.11301332268975, -48.99952012098447, -26.82864590002175, 21.42851887815869, 51.51158249613326, 34.46525552832719, -15.54677909991353, -52.87686205337562, -42.05528581921386, 8.543000950788283, 52.9508245422024]
\ No newline at end of file
diff --git a/pub/itest/p2D.f2t b/pub/itest/p2D.f2t
new file mode 100755
index 0000000000000000000000000000000000000000..e86ada7923a297dc2e112bca99c027e9ca85389b
--- /dev/null
+++ b/pub/itest/p2D.f2t
@@ -0,0 +1,5 @@
+#!/usr/bin/env frida
+fl grid40x20
+gt+
+p
+qui
diff --git a/pub/itest/setup_wallpaper.ps b/pub/itest/setup_wallpaper.ps
new file mode 100644
index 0000000000000000000000000000000000000000..f78e8cc66a8275121eee8c2c318fb9541088264e
--- /dev/null
+++ b/pub/itest/setup_wallpaper.ps
@@ -0,0 +1,49 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Customizable plot setup, copied from g3.ps (editör: use latin-1)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+WuGdict17a begin
+
+12 dup autolabel defsiz
+.4 dup geld stdred
+
+2 -11 setnewpage newpage
+3 8 13 -12 setpagegrid
+
+2 8 24 abcset % usage: {(text)} abc
+/EndFrame { nextFrame end } def
+
+1 1 language
+0 infSet % plot info block?
+1 dup 2 SymGSet % srad slin serr(2=from pset) : graph symbols, global preset
+% /setboxbackgroundcolor { 0.93 setgray } def % default is white
+% setPalatino
+
+{ 8 aCol5 iColA } /ipCol x bind def % number of colours and colour style
+/pStyles [
+   { 11 0 0 1. 1. pset  0 ipCol }
+   { 12 1 0 1. 1. pset  1 ipCol }
+   { 13 1 0 1. 1. pset  2 ipCol }
+   {  1 0 0 1. 1. pset  3 ipCol }
+   {  1 1 0 .7 1. pset  4 ipCol }
+   {  3 0 0 1. 1. pset  5 ipCol }
+   {  3 1 0 .7 1. pset  6 ipCol }
+   {  4 0 0 1. 1. pset  7 ipCol }
+   {  4 1 0 .7 1. pset  0 ipCol }
+   {  5 0 0 1. 1. pset  1 ipCol }
+   {  5 1 0 .7 1. pset  2 ipCol }
+   {  2 0 0 1. 1. pset  3 ipCol }
+   {  2 1 0 .7 1. pset  4 ipCol }
+   ] def
+
+{ 8 aCol2 iColA } /icCol x bind def % number of colours and colour style
+/cStyles [
+   { 1. [] lset siemensred }
+   ] def
+
+Resets
+BoxBackground
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Mark "ecu", end of the customization section
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/pub/lib/CMakeLists.txt b/pub/lib/CMakeLists.txt
index 8bb758396f4cdb21f31863be993f5ae1d092ee10..d57ae7585b41850096a756c74e717ef6953ed1f6 100644
--- a/pub/lib/CMakeLists.txt
+++ b/pub/lib/CMakeLists.txt
@@ -1,5 +1,9 @@
 # frida: lib/CMakeLists.txt
 
+set(library_name fridacore)
+set(${library_name}_LIBRARY ${library_name} PARENT_SCOPE)
+set(${library_name}_LIBRARY_TYPE SHARED)
+
 bison_target(xaxyacc
     xax_yacc.ypp ${CMAKE_CURRENT_BINARY_DIR}/xax_yacc.cpp COMPILE_FLAGS "-p xax -y" )
 flex_target(xaxlex
@@ -81,25 +85,23 @@ set(inc_files
     xax_lex.hpp
     )
 
-add_library(libfrida SHARED
+add_library(${library_name} SHARED
     ${src_files}
     ${BISON_xaxyacc_OUTPUTS}
     ${FLEX_xaxlex_OUTPUTS}
     )
 
-set_target_properties(libfrida PROPERTIES OUTPUT_NAME frida)
-
-target_link_libraries(libfrida
-    libreadplus
-    libtrivia
-    libfridaplot
+target_link_libraries(${library_name}
+    ${readplus_LIBRARY}
+    ${fridatrivia_LIBRARY}
+    ${fridaplot_LIBRARY}
     pthread
-    ${GSL_LIBRARIES}
     ${FFTW_LIBRARIES}
     ${KWW_LIBRARIES}
     ${Cerf_LIBRARIES}
-    ${YAMLCPP_LIBRARY}
     ${LMFit_LIBRARIES}
     )
 
-install(TARGETS libfrida DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
+set_target_properties(${library_name} PROPERTIES OUTPUT_NAME ${library_name})
+
+install(TARGETS ${library_name} LIBRARY DESTINATION ${destination_lib} COMPONENT Libraries)
diff --git a/pub/lib/commands.cpp b/pub/lib/commands.cpp
index fb239c859c21534f2418d0dc608bd9c130479ee5..96032ff539b7931f2148b085fc31b3d17eedbe69 100644
--- a/pub/lib/commands.cpp
+++ b/pub/lib/commands.cpp
@@ -11,6 +11,7 @@
 #include "ptr.hpp"
 
 #include <cstring>
+#include <boost/filesystem.hpp>
 
 #include "../plot/dualplot.hpp"
 #include "../plot/plowin.hpp"
@@ -38,9 +39,13 @@
 #include "reduce_spec.hpp"
 #include "rssm.hpp"
 #include "special.hpp"
+#include "variables.hpp"
 
 #include "commands.hpp"
 
+namespace fs = boost::filesystem;
+
+
 //! Executes cmd if is a Frida command, and returns true when successful.
 
 bool frida_command(string cmd)
@@ -84,7 +89,7 @@ bool frida_command(string cmd)
                 "  hic  dimension-reducing functionals of curves\n"
                 "  ho   operators by precedence\n"
                 "  hr   handling resolution functions (convolution, Dirac delta function)\n"
-                "  hv   variables\n"
+                "  hp   parameters\n"
                 "  \\h   meta commands and macros\n";
 
     } else if (cmd == "hc") {
@@ -117,8 +122,8 @@ bool frida_command(string cmd)
                 "    - use command 'cv' to provide resolution file reference\n"
                 "If function f has a sharp peak (strong variation within one resolution bin):\n"
                 "    - use 'pconv(F(t,...))', where F is the primitive of f\n";
-    } else if (cmd == "hv") {
-        cout << "Variables for use in expressions\n"
+    } else if (cmd == "hp") {
+        cout << "Parameters for use in expressions\n"
                 "  t         dummy argument in curve definition\n"
                 "  k         index running over files in online memory\n"
                 "  j         index running over slices (spectra or curves) in a file\n"
@@ -148,7 +153,6 @@ bool frida_command(string cmd)
                 "  cm   modify function\n"
                 "  cd   set data file to fit\n"
                 "  cv   set file to convolute with (cv-: no convolution)\n"
-                "  cr   set fit range restriction\n"
                 "  cf   fit\n"
                 "  cfs  fit, allow slow convolution\n"
                 "  cp   print parameters\n"
@@ -164,6 +168,7 @@ bool frida_command(string cmd)
                 "  cwvc weighing: reciprocal variance, curve only\n"
                 "  cgd+ graphics: take x points from data reference file\n"
                 "  cgd- graphics: create x points by dividing the plot window\n"
+                "  cr   set restrictions for plot range\n"
                 "Frida-wide settings:\n"
                 "  cs?  show fit parameters, and indicate commands to modify them\n"
                 "  cn?  show parameters for numeric integration, and indicate commands to modify "
@@ -184,7 +189,7 @@ bool frida_command(string cmd)
         NCurveFile::set_file_reference(cmd.substr(1));
 
     } else if (cmd == "cr") {
-        NCurveFile::change_range();
+        NCurveFile::change_prange();
 
     } else if (cmd == "cp") {
         NCurveFile::show_pars();
@@ -207,28 +212,31 @@ bool frida_command(string cmd)
 
     } else if (cmd == "d") {
         cout << "Directory commands: inspect internal files\n"
-                "  df   list of files\n"
-                "  dz   z-values and spectral ranges\n"
-                "  dp   x|y-values\n"
-                "  dy   y-values\n"
-                "  dr   real parameters\n"
-                "  dc   coordinate names and units\n"
-                "  dd   doc lines\n";
+            "  dc   coordinate names and units\n"
+            "  dd   doc lines\n"
+            "  df   list of files\n"
+            "  dp   x|y-values\n"
+            "  dr   real parameters\n"
+            "  dv   variables\n"
+            "  dy   y-values\n"
+            "  dz   z-values and spectral ranges\n";
 
+    } else if (cmd == "dc") {
+        NEdif::show_coord();
+    } else if (cmd == "dd") {
+        NEdif::show_doc();
     } else if (cmd == "df") {
         NEdif::show_files();
-    } else if (cmd == "dz") {
-        NEdif::show_spectra();
     } else if (cmd == "dp") {
         NOperate::show("xyd");
-    } else if (cmd == "dy") {
-        NOperate::show("y");
     } else if (cmd == "dr") {
         NEdif::show_numpars();
-    } else if (cmd == "dc") {
-        NEdif::show_coord();
-    } else if (cmd == "dd") {
-        NEdif::show_doc();
+    } else if (cmd == "dv") {
+        SVariRegistry::instance()->display_all();
+    } else if (cmd == "dy") {
+        NOperate::show("y");
+    } else if (cmd == "dz") {
+        NEdif::show_spectra();
 
     } else if (cmd == "e") {
         cout << "Edit commands:\n"
@@ -247,9 +255,7 @@ bool frida_command(string cmd)
     } else if (cmd == "f") {
         cout << "File commands:\n"
                 "  fl   load from disk\n"
-                "  fs   save to disk\n"
-                "  fso  save to disk, allow overwrite\n"
-                "  fe0  export to old y08 format (obsolete!)\n"
+                "  fs   save to disk (use modifier ! to overwrite)\n"
                 "  fe1  export (only z and y, one line per spectrum)\n"
                 "  fe2  export (one block per spectrum: z header and x-y lines)\n"
                 "  fc   copy\n"
@@ -268,13 +274,7 @@ bool frida_command(string cmd)
     } else if (cmd == "fl") {
         NFileIn::load();
     } else if (cmd == "fs") {
-        NFileOut::save("yda");
-    } else if (cmd == "fso") {
-        NFileOut::save("yda", true);
-    } else if (cmd == "fe0") {
-        NFileOut::save("y08");
-    } else if (cmd == "fe0o") {
-        NFileOut::save("y08", true);
+        NFileOut::save("yda", SMem::instance()->overwrite);
     } else if (cmd == "fe1") {
         NFileOut::save("csv");
     } else if (cmd == "fe2") {
@@ -303,18 +303,23 @@ bool frida_command(string cmd)
                 "  gd   graphic dialog (feed commands to gnuplot)\n"
                 "Save for print:\n"
                 "  gp   plot to complete .ps file\n"
-                "  gf   plot to short .psX file\n"
+                "  gf   plot to short .psa file\n"
+                "  gfa  append plot to existing .ps or .psa file\n"
                 "Change window:\n"
                 "  gw   list of plot windows\n"
                 "  g<n> switch to plot window <n>\n"
                 "Set axes:\n"
+                "  gt   2D plot (toggle; or use gt+ gt-)\n"
                 "  gx   set x range\n"
-                "  gy   set x range\n"
+                "  gy   set y range\n"
+                "  gz   set z range (for 2D plots)\n"
                 "  ga   auto-ranges\n"
                 "  gxa  x auto-range\n"
                 "  gya  y auto-range\n"
+                "  gza  z auto-range (for 2D plots)\n"
                 "  gxl  log x (toggle; or use gxl+ gxl-)\n"
                 "  gyl  log y\n"
+                "  gzl  log z\n"
                 "  gxf  force x into frame (toggle; or use gxf+ gxf-)\n"
                 "  gyf  force y into frame (toggle; or use gyf+ gyf-)\n"
                 "Other setup:\n"
@@ -329,14 +334,20 @@ bool frida_command(string cmd)
         SPloWin::instance()->current()->X.ask_and_set("Plot x range");
     } else if (cmd == "gy") {
         SPloWin::instance()->current()->Y.ask_and_set("Plot y range");
+    } else if (cmd == "gz") {
+        SPloWin::instance()->current()->Z.ask_and_set("Plot z range");
     } else if (cmd == "ga") {
         SPloWin::instance()->current()->X.set_auto();
         SPloWin::instance()->current()->Y.set_auto();
+        SPloWin::instance()->current()->Z.set_auto();
     } else if (cmd == "gxa") {
         SPloWin::instance()->current()->X.set_auto();
     } else if (cmd == "gya") {
         SPloWin::instance()->current()->Y.set_auto();
-    } else if (cmd.substr(0, 2) == "gx" || cmd.substr(0, 2) == "gy" || cmd.substr(0, 2) == "ge") {
+    } else if (cmd == "gza") {
+        SPloWin::instance()->current()->Z.set_auto();
+    } else if (cmd.substr(0, 2) == "gx" || cmd.substr(0, 2) == "gy" || cmd.substr(0, 2) == "gz"
+               || cmd.substr(0, 2) == "ge" || cmd.substr(0, 2) == "gt") {
         SPloWin::instance()->current()->set_aux(cmd);
     } else if (cmd == "gnd") {
         SPloWin::instance()->current()->maxpoints = iask(
@@ -349,11 +360,29 @@ bool frida_command(string cmd)
         SPloWin::instance()->current()->refine = bask(
             "Allow iterative refinement for curve plotting",
             SPloWin::instance()->current()->refine);
-    } else if (cmd == "gp" || cmd == "gf") {
-        string ps_outdir = CNode::eval("psdir")->to_s();
-        string ps_head = CNode::eval("pshead")->to_s();
-        string ps_dict = cmd == "gp" ? CNode::eval("psdict")->to_s() : "";
-        SPloWin::instance()->current()->write_postscript(ps_outdir, ps_head, ps_dict);
+    } else if (cmd == "gp" || cmd == "gf" || cmd == "gfa") {
+        bool withDefs = cmd.substr(0,2)=="gp";
+        const string ext = string(".") + (withDefs ? "ps" : "psa");
+        static string fname = "";
+        string mode;
+        if (cmd != "gfa") {
+            fs::path defaultname = triv::next_tmp_file(
+                CNode::eval("ps_outdir")->to_s() + (withDefs ? "L" : "l") + "%i" + ext);
+            defaultname.replace_extension("");
+            fname = sask("Graphic file name (without extension "+ext+")", defaultname.string());
+            if (fname=="")
+                return false;
+            if (fs::path(fname).extension().string()=="")
+                fname += ext;
+            mode = SMem::instance()->overwrite ? "overwrite" : "create";
+        } else { // gfa
+            fname = sask("Graphic file name", fname);
+            mode = "append";
+        }
+        if (fname != "")
+            SPloWin::instance()->current()->write_postscript(
+                triv::wordexp_unique(fname), mode, withDefs,
+                SVariRegistry::instance()->to_sMap());
     } else if (cmd == "gw") {
         SPloWin::instance()->display_list();
     } else if (sscanf(cmd.c_str(), "g%i", &i) == 1) {
@@ -404,23 +433,44 @@ bool frida_command(string cmd)
                 "  md    generic delete\n"
                 "  mr    generic retain\n"
                 "Per point:\n"
+                "  mp?   command list\n"
+                "Per slice (spectrum/curve):\n"
+                "  ms?   command list\n"
+                "Per file:\n"
+                "  mfj   merge (\"join\")\n"
+                "  mfj+  merge, adding z=number-of-input-file\n"
+                "  mfjp  merge pointwise\n"
+                "  mr-   remove real par\n"
+                "Histogram operations:\n"
+                "  mhm   bin data\n";
+
+    } else if (cmd == "mp?") {
+        cout << "Pointwise manipulations:\n"
                 "  mpd   delete\n"
                 "  mpr   retain\n"
-                "  mpa   average (=bin), list controlled\n"
-                "  mpaf  average, reduce number of points by fixed factor\n"
-                "  mpaea average according to error bound (absolute)\n"
-                "  mpaer average according to error bound (relative)\n"
+                "  mpa?  average (rebin) command list\n"
                 "  mpbf  break into spectra by fixed factor\n"
                 "  mpo   sort\n"
-                "  mpq   average when x equal\n"
                 "  mpsym symmetrize: map -x -> x, then average\n"
                 "  mpe-  remove error bar\n"
                 "  mpgi  interpolate to given x grid\n"
-                "  mpgr  redistribute histogram intensity to given x grid\n"
-                "Per spectrum:\n"
+                "  mpgr  redistribute histogram intensity to given x grid\n";
+
+    } else if (cmd == "mpa?") {
+        cout << "Commands to average (rebin) adjacent channels:\n"
+                "  mpa[d|f|e|r][s]\n"
+                "        d only bin channels with duplicate x\n"
+                "        f bin size given by fixed factor\n"
+                "        e bring absolute error below some bound\n"
+                "        r bring relative error below some bound\n"
+                "        s error estimate includes sampling error\n";
+
+    } else if (cmd == "ms?") {
+        cout << "Pointwise manipulations:\n"
                 "  msd   delete\n"
                 "  msr   retain\n"
                 "  msa   average\n"
+                "  msas  average, error estimate includes sampling error\n"
                 "  msb   break into files\n"
                 "  msj   join\n"
                 "  ms*   spawn spectra\n"
@@ -428,14 +478,7 @@ bool frida_command(string cmd)
                 "  mso   sort by expression\n"
                 "  msoz  sort by z-values\n"
                 "  mzx   exchange / rotate z coordinates\n"
-                "  mz-   delete z coordinate\n"
-                "Per file:\n"
-                "  mfj   merge (\"join\")\n"
-                "  mfj+  merge, adding z=number-of-input-file\n"
-                "  mfjp  merge pointwise\n"
-                "  mr-   remove real par\n"
-                "Histogram operations:\n"
-                "  mhm   bin data\n";
+                "  mz-   delete z coordinate\n";
 
     } else if (cmd == "m/") {
         NManip::freeze_slices();
@@ -450,17 +493,23 @@ bool frida_command(string cmd)
     } else if (cmd == "mpr") {
         NManip::points_select(false);
     } else if (cmd == "mpa") {
-        NManip::points_rebin();
+        NManip::points_rebin(false);
+    } else if (cmd == "mpas") {
+        NManip::points_rebin(true);
+    } else if (cmd == "mpad") {
+        NManip::points_rebin_duplicates();
     } else if (cmd == "mpaf") {
-        NManip::points_rebin_by_factor();
-    } else if (cmd.substr(0, 4) == "mpae") {
-        NManip::points_rebin_by_err(cmd.substr(4));
+        NManip::points_rebin_by_factor(false);
+    } else if (cmd == "mpafs") {
+        NManip::points_rebin_by_factor(true);
+    } else if (cmd == "mpae") {
+        NManip::points_rebin_by_err(true);
+    } else if (cmd == "mpar") {
+        NManip::points_rebin_by_err(false);
     } else if (cmd == "mpbf") {
         NManip::points_break_by_factor();
     } else if (cmd == "mpo") {
         NManip::points_sort();
-    } else if (cmd == "mpq") {
-        NManip::points_rebin_duplicates();
     } else if (cmd == "mpsym") {
         NManip::points_symmetrize();
     } else if (cmd == "mpe-") {
@@ -474,7 +523,9 @@ bool frida_command(string cmd)
     } else if (cmd == "msr") {
         NManip::slices_select(false);
     } else if (cmd == "msa") {
-        NManip::slices_rebin();
+        NManip::slices_rebin(false);
+    } else if (cmd == "msas") {
+        NManip::slices_rebin(true);
     } else if (cmd == "msb") {
         NManip::slices_break();
     } else if (cmd == "msj") {
diff --git a/pub/lib/curve.cpp b/pub/lib/curve.cpp
index ece8756db0c0dd31a2b48db572c8769b607f0363..7fd003f2663cbcc4a9820a5634dd479bfc8dd6ce 100644
--- a/pub/lib/curve.cpp
+++ b/pub/lib/curve.cpp
@@ -53,7 +53,7 @@ void NCurveFile::create_fitcurve()
         fout->RPar = fd->RPar;
         fout->log_action("cc " + fc->expr + " # z from " + fd->name);
         fout->weighing = COlc::_VAR;
-        if (fd->has_nonzero_dy()) {
+        if (!fd->dy_are_all_nonzero()) {
             fout->weighing = COlc::_LIN;
             cout << "Constant weight since there are data points with dy=0\n";
         }
@@ -203,22 +203,20 @@ void NCurveFile::set_par_attr(char attr)
 }
 
 
-//! Queries and sets fit range restrictions.
+//! Queries and sets plot range restrictions.
 
-void NCurveFile::change_range()
+void NCurveFile::change_prange()
 {
     FileIterator fiter(SFSel::instance()->selC());
 
-    string expr = sask("Expression restricting the fit range");
+    string query = "Expression in t, f(t) to restrict the plot range";
+    string expr = sask(query); // TODO: default if only one file
 
     while (COlc* fc = fiter.nextC()) {
-        fc->range_expr = expr;
+        RNode T = expr!="" ? user_xaxparse(expr.c_str()) : nullptr;
         fc->log_action("cr " + expr);
-        if (expr == "") {
-            fc->range_T = nullptr;
-            continue;
-        }
-        fc->range_T = user_xaxparse(expr.c_str());
+        fc->prange_expr = expr;
+        fc->prange_T = T;
     }
 }
 
diff --git a/pub/lib/curve.hpp b/pub/lib/curve.hpp
index 9b0c781bd45818679b24090a52b6cfefe7521603..df3fedfbbf5f082c2ecc63df724289890d5993b2 100644
--- a/pub/lib/curve.hpp
+++ b/pub/lib/curve.hpp
@@ -20,7 +20,7 @@ namespace NCurveFile
 void create_fitcurve();
 void create_freecurve();
 void change_expr();
-void change_range();
+void change_prange();
 void set_file_reference(const string& which);
 
 void set_properties(string which);
diff --git a/pub/lib/defs.hpp b/pub/lib/defs.hpp
index f0824e2ed1754108853d6152ae50ab7d9aa29b24..9bf1447fa1aecb117c16624b5a7820b9b1e2633d 100644
--- a/pub/lib/defs.hpp
+++ b/pub/lib/defs.hpp
@@ -12,14 +12,12 @@
 
 #include "../trivia/string_convs.hpp"
 #include <iostream>
-#include <map>
 #include <vector>
 
 #define S(a) triv::strg((a))
 
 #define SQR(a) ((a) * (a))
 
-using std::map;
 using std::string;
 using std::vector;
 using std::cout;
diff --git a/pub/lib/expr.hpp b/pub/lib/expr.hpp
index d5a1ff1975b7f460699fb9b1c3e47ec8eba6098b..fd996fe3b0884614ec6bb8e53cf37a50bf747d32 100644
--- a/pub/lib/expr.hpp
+++ b/pub/lib/expr.hpp
@@ -79,7 +79,6 @@ public:
 
 class CNode
 {
-private:
 public:
     virtual ~CNode() {}
 
diff --git a/pub/lib/fbase.cpp b/pub/lib/fbase.cpp
index 2c08f6c335d525b1b2391f63f0bf8509d71ae025..2a9362f89ad2b347405d682a125f72a6b4cd71e1 100644
--- a/pub/lib/fbase.cpp
+++ b/pub/lib/fbase.cpp
@@ -51,8 +51,8 @@ void func_neg(double& r, double& dr, double v, double dv)
     dr = dv;
 }
 
-double func_ln(double v) { return v > 0 ? log(v) : 0; }
-void func_ln(double& r, double& dr, double v, double dv)
+double func_ln0(double v) { return v > 0 ? log(v) : 0; }
+void func_ln0(double& r, double& dr, double v, double dv)
 {
     if (v > 0) {
         r = log(v);
@@ -63,8 +63,15 @@ void func_ln(double& r, double& dr, double v, double dv)
     }
 }
 
-double func_lg(double v) { return v > 0 ? log10(v) : 0; }
-void func_lg(double& r, double& dr, double v, double dv)
+double func_ln(double v) { return log(v); }
+void func_ln(double& r, double& dr, double v, double dv)
+{
+    r = log(v);
+    dr = dv / v;
+}
+
+double func_lg0(double v) { return v > 0 ? log10(v) : 0; }
+void func_lg0(double& r, double& dr, double v, double dv)
 {
     if (v > 0) {
         r = log10(v);
@@ -75,8 +82,15 @@ void func_lg(double& r, double& dr, double v, double dv)
     }
 }
 
-double func_sqrt(double v) { return v >= 0 ? sqrt(v) : 0; }
-void func_sqrt(double& r, double& dr, double v, double dv)
+double func_lg(double v) { return log10(v); }
+void func_lg(double& r, double& dr, double v, double dv)
+{
+    r = log10(v);
+    dr = dv / v / log(10);
+}
+
+double func_sqrt0(double v) { return v >= 0 ? sqrt(v) : 0; }
+void func_sqrt0(double& r, double& dr, double v, double dv)
 {
     if (v > 0) {
         r = sqrt(v);
@@ -87,6 +101,13 @@ void func_sqrt(double& r, double& dr, double v, double dv)
     }
 }
 
+double func_sqrt(double v) { return sqrt(v); }
+void func_sqrt(double& r, double& dr, double v, double dv)
+{
+    r = sqrt(v);
+    dr = dv / 2 / r;
+}
+
 double func_abs(double v) { return fabs(v); }
 int func_abs(int v) { return abs(v); }
 void func_abs(double& r, double& dr, double v, double dv)
@@ -541,6 +562,28 @@ double func_ornuhl(double _w, double _a, double _b)
     return -9; // too many terms
 }
 
+double func_sears_forward(double t, double rho, double z)
+{
+    double k = rho<1 ? sqrt(1-rho*rho) : 0;
+    double a = k*(1-z)/2;
+    if (t*a>100)
+        return 1;
+    else if (t*k>200)
+        return 0;
+    double J = k>0 ? (k*cosh(t*a)+sinh(t*a))/(k*cosh(t*k)+sinh(t*k)) : (1+t*a)/(1+t);
+    return J; // *exp(t*k*(1+z)/2);
+}
+
+double func_sears_backward(double t, double rho, double z)
+{
+    double k = rho<1 ? sqrt(1-rho*rho) : 0;
+    double a = k*(1-z)/2;
+    if (t*a>30)
+        return rho/(k+1);
+    double J = k>0 ? rho*sinh(t*a)/(k*cosh(t*k)+sinh(t*k)) : rho*t/(1+t);
+    return J; // *exp(t*k*(1+z)/2);
+}
+
 //**************************************************************************************************
 //*  Registration
 //**************************************************************************************************
@@ -630,15 +673,24 @@ void fbase_initialize()
     G->register_fct_0_s(m, func_pop);
     m = { "exit", 1, "(x): exit(x)" };
     G->register_fct_i_i(m, func_exit);
-    m = { "ln", 1, "(x): natural logarithm of x, or 0 if x<=0" };
+    m = { "ln", 1, "(x): natural logarithm of x" };
     G->register_fct_d_d(m, func_ln);
     G->register_fct_e_e(m, func_ln);
-    m = { "lg", 1, "(x): decadic logarithm of x, or 0 if x<=0" };
+    m = { "ln0", 1, "(x): natural logarithm of x, or 0 if x<=0" };
+    G->register_fct_d_d(m, func_ln0);
+    G->register_fct_e_e(m, func_ln0);
+    m = { "lg", 1, "(x): decadic logarithm of x" };
     G->register_fct_d_d(m, func_lg);
     G->register_fct_e_e(m, func_lg);
-    m = { "sqrt", 1, "(x): square root of x, or 0 if x<0" };
+    m = { "lg0", 1, "(x): decadic logarithm of x, or 0 if x<=0" };
+    G->register_fct_d_d(m, func_lg0);
+    G->register_fct_e_e(m, func_lg0);
+    m = { "sqrt", 1, "(x): square root of x" };
     G->register_fct_d_d(m, func_sqrt);
     G->register_fct_e_e(m, func_sqrt);
+    m = { "sqrt0", 1, "(x): square root of x, or 0 if x<0" };
+    G->register_fct_d_d(m, func_sqrt0);
+    G->register_fct_e_e(m, func_sqrt0);
     m = { "abs", 1, "(x): absolute value of x" };
     G->register_fct_i_i(m, func_abs);
     G->register_fct_d_d(m, func_abs);
@@ -798,4 +850,9 @@ void fbase_initialize()
     G->register_fct_d_ddd(m, func_ornuhl);
     m = { "rotdiff", 3, "(w,tau,qb: rotational diffusion spectrum)" };
     G->register_fct_d_ddd(m, func_rotdiff);
+
+    m = { "sears_forward", 3, "(tau,rho,zeta: Current U+)" };
+    G->register_fct_d_ddd(m, func_sears_forward);
+    m = { "sears_backward", 3, "(tau,rho,zeta: Current U-)" };
+    G->register_fct_d_ddd(m, func_sears_backward);
 }
diff --git a/pub/lib/file_in.cpp b/pub/lib/file_in.cpp
index b8d27c805b704b8d516c27e940d80b32dc2fc2cf..2c356c38b2f394bc51c94a1c5d076a7b403d67c4 100644
--- a/pub/lib/file_in.cpp
+++ b/pub/lib/file_in.cpp
@@ -11,7 +11,7 @@
 
 #include <fstream>
 #include <string.h>
-
+#include <boost/filesystem.hpp>
 #include <yaml-cpp/yaml.h>
 
 #include "../readplus/ask.hpp"
@@ -24,14 +24,15 @@
 #include "olf.hpp"
 #include "slice.hpp"
 
+namespace fs = boost::filesystem;
+
 
 namespace NFileIn
 {
-void Load_yda(std::ifstream& F_in, string fnam);
-void Load_08(std::ifstream& F_in, string flong);
-void Load_01(FILE* F_in, string flong);
+void Load_yda(std::ifstream& F_in, string fshort);
+void Load_01(FILE* F_in, string fshort);
 void LoadSpec_01(FILE* F_in, PSpec& sout, int nz);
-void Load_96(FILE* F_in, string flong);
+void Load_96(FILE* F_in, string fshort);
 }
 
 
@@ -41,29 +42,31 @@ void NFileIn::load(void)
 {
     string pattern = sask("Load file(s)");
     vector<string> fNames = triv::glob_file_list(pattern, "yda y08 a01 i96");
+    if (!fNames.size())
+        throw "Found no file that matches '" + pattern + "'";
     for (string fnam : fNames) {
         try {
-            string fdir, fshort, fext;
-            triv::fname_divide(fnam, &fdir, &fshort, &fext);
-            if (fext == "y08" || fext == "yda") {
+            string fext = fs::path(fnam).extension().string();
+            string fshort = fs::path(fnam).filename().stem().string();
+            if (fext == ".y08" || fext == ".yda") {
                 std::ifstream FS(fnam.c_str(), std::ios_base::in);
                 if (FS.fail())
                     throw string("cannot open file");
                 cout << ".. loading file " << fnam << "\n";
                 Load_yda(FS, fshort);
                 FS.close();
-            } else if (fext == "a01" || fext == "i96") {
+            } else if (fext == ".a01" || fext == ".i96") {
                 FILE* F_in;
                 if (!(F_in = fopen(fnam.c_str(), "r")))
                     throw "cannot open file " + fnam;
-                if (fext == "a01") {
-                    Load_01(F_in, fnam.c_str());
-                } else if (fext == "i96") {
-                    Load_96(F_in, fnam.c_str());
+                if (fext == ".a01") {
+                    Load_01(F_in, fshort);
+                } else if (fext == ".i96") {
+                    Load_96(F_in, fshort);
                 }
                 fclose(F_in);
             } else
-                throw "unknown extension " + fext;
+                throw "unknown extension '" + fext + "'";
         } catch (string& ex) {
             throw "Cannot load " + fnam + ": " + ex;
         } catch (std::exception& ex) {
@@ -74,7 +77,7 @@ void NFileIn::load(void)
 
 //! Load a YAML file in yda format.
 
-void NFileIn::Load_yda(std::ifstream& FS, string fnam)
+void NFileIn::Load_yda(std::ifstream& FS, string fshort)
 {
     const YAML::Node doc = YAML::Load(FS);
     if (doc.Type() != YAML::NodeType::Map)
@@ -349,7 +352,7 @@ void NFileIn::Load_yda(std::ifstream& FS, string fnam)
         }
     }
 
-    fout->name = fnam;
+    fout->name = fshort;
     fout->as_on_disk = true;
     SMem::instance()->mem_store(move(fout));
 }
@@ -357,15 +360,13 @@ void NFileIn::Load_yda(std::ifstream& FS, string fnam)
 
 //! Load a .a01 formatted file.
 
-void NFileIn::Load_01(FILE* F_in, string flong)
+void NFileIn::Load_01(FILE* F_in, string fshort)
 {
-    string lin, key, val, fdir, fshort, fext;
+    string lin, key, val;
     int iz, nj = 0, j;
     CCoord co;
     POld fout(new COld);
 
-    triv::fname_divide(flong, &fdir, &fshort, &fext);
-
     if (triv::freadln(F_in, &lin) <= 0)
         throw "file empty or starting with empty line";
     if (lin != string("ASCII-01 JWu"))
@@ -484,16 +485,15 @@ void NFileIn::LoadSpec_01(FILE* F_in, PSpec& sout, int nz)
 
 //! Load a .i96 formatted file.
 
-void NFileIn::Load_96(FILE* F_in, string flong)
+void NFileIn::Load_96(FILE* F_in, string fshort)
 {
-    string lin, key, val, fdir, fshort, fext;
+    string lin, key, val;
     double r0, r1, r2;
     int n, nspec, ival;
     POld fout(new COld);
     CCoord co;
     PSpec sout;
 
-    triv::fname_divide(flong, &fdir, &fshort, &fext);
     fout->name = fshort;
 
     if (!triv::freadln(F_in, &lin))
diff --git a/pub/lib/file_out.cpp b/pub/lib/file_out.cpp
index ecc0a6c1907f6f7c9c0d2961da4a6db9816ab6e0..8055b0b7a309520e4d6f90c2e019c0e2c13e441a 100644
--- a/pub/lib/file_out.cpp
+++ b/pub/lib/file_out.cpp
@@ -13,6 +13,7 @@
 #include <yaml-cpp/yaml.h>
 
 #include "../readplus/ask.hpp"
+#include "../trivia/file_ops.hpp"
 #include "../trivia/yaml_out.hpp"
 
 #include "file_out.hpp"
@@ -25,7 +26,6 @@
 namespace NFileOut
 {
 void save_yda(std::ofstream& ofs, const COlo* f);
-void save_y08(FILE* file, const COlo* f);
 void save_csv(FILE* file, const COlo* f);
 void save_tab(FILE* file, const COlo* f);
 }
@@ -47,13 +47,8 @@ void NFileOut::save(string fmt, bool allow_overwrite)
         // document file save
         f->log_action("fs " + outfnam + " # " + triv::time2strg(time(0)));
         // prevent unintended overwriting
-        if (!allow_overwrite) {
-            FILE* file;
-            if ((file = fopen(outfnam.c_str(), "r"))) {
-                fclose(file);
-                throw "file " + outfnam + " exists, use fso to overwrite";
-            }
-        }
+        if (!allow_overwrite && triv::file_exists(outfnam))
+            throw "file " + outfnam + " exists, use command modifier '!' to overwrite";
         // save file
         if (fmt == "yda") {
             std::ofstream ofs;
@@ -64,9 +59,7 @@ void NFileOut::save(string fmt, bool allow_overwrite)
             FILE* file;
             if (!(file = fopen(outfnam.c_str(), "w")))
                 throw "cannot write to file " + outfnam;
-            if (fmt == "y08") {
-                save_y08(file, f);
-            } else if (fmt == "csv") {
+            if (fmt == "csv") {
                 save_csv(file, f);
             } else if (fmt == "tab") {
                 save_tab(file, f);
@@ -166,79 +159,6 @@ void NFileOut::save_yda(std::ofstream& ofs, const COlo* f)
 }
 
 
-//! Writes a file in format y08.
-
-void NFileOut::save_y08(FILE* file, const COlo* f)
-{
-    const COld* fd = dynamic_cast<const COld*>(f);
-    const COlc* fc = dynamic_cast<const COlc*>(f);
-
-    fprintf(
-        file, "Meta:\n"
-              "  format:  frida/y08 for yaml1\n"
-              "  type:    %s\n",
-        fd ? "generic tabular data" : "frida2 curve");
-
-    fprintf(file, "History:\n");
-    for (string lin : f->lDoc)
-        fprintf(file, "- %s\n", triv::yaml(lin).c_str());
-
-    fprintf(file, "Coord:\n");
-    fprintf(
-        file, "  x:\n    name: %s\n    unit: %s\n", triv::yaml(f->xco.name).c_str(),
-        triv::yaml(f->xco.unit).c_str());
-    fprintf(
-        file, "  y:\n    name: %s\n    unit: %s\n", triv::yaml(f->yco.name).c_str(),
-        triv::yaml(f->yco.unit).c_str());
-    for (int i = 0; i < f->ZCo.size(); i++)
-        fprintf(
-            file, "  z%i:\n    name: %s\n    unit: %s\n", i, triv::yaml(f->ZCo[i].name).c_str(),
-            triv::yaml(f->ZCo[i].unit).c_str());
-
-    fprintf(file, "Param:\n");
-    for (int i = 0; i < f->RPar.size(); i++)
-        fprintf(
-            file, "  -\n    name:  %s\n    unit:  %s\n    value: %20.15g\n",
-            triv::yaml(f->RPar[i].Co.name).c_str(), triv::yaml(f->RPar[i].Co.unit).c_str(),
-            f->RPar[i].val);
-
-    if (fc) {
-        fprintf(file, "Formula: %s\n", fc->expr.c_str());
-    }
-
-    fprintf(file, "Tables: # %i tables follow\n", f->nJ());
-
-    for (int j = 0; j < f->nJ(); j++) {
-        fprintf(file, "  - # table %i\n", j);
-        CSlice* s = f->V[j].get();
-        for (int i = 0; i < f->nZ(); i++) {
-            if (RObjNum pz = PCAST<const CObjNum>(s->z[i])) {
-                fprintf(file, "    z%i: %18.10g\n", i, pz->to_r());
-                if (RObjNum pdz = PCAST<const CObjEnu>(s->z[i]))
-                    fprintf(file, "    dz%i: %18.10g\n", i, pdz->to_dr());
-            } else
-                fprintf(file, "    z%i: %s\n", i, s->z[i]->to_s().c_str());
-        }
-        if (fd) {
-            const CSpec* s = fd->VS(j);
-            if (s->dy.size()) {
-                fprintf(file, "    xyd: |2 # %i entries\n", (int)s->size());
-                for (int i = 0; i < s->size(); i++)
-                    fprintf(file, "      %20.15g %20.15g %20.15g\n", s->x[i], s->y[i], s->dy[i]);
-            } else {
-                fprintf(file, "    xy: |2 # %i entries\n", (int)s->size());
-                for (int i = 0; i < s->size(); i++)
-                    fprintf(file, "      %20.15g %20.15g\n", s->x[i], s->y[i]);
-            }
-        } else {
-            CCurve* s = fc->VC(j);
-            for (int i = 0; i < fc->nP; i++)
-                fprintf(file, "    p%i: %18.10g\n", i, s->P[i]);
-        }
-    }
-}
-
-
 //! Writes y as tab-separated table.
 
 void NFileOut::save_csv(FILE* file, const COlo* f)
diff --git a/pub/lib/fit.cpp b/pub/lib/fit.cpp
index 492474808faeab85b525de9d21101a4bed11b23c..96b033c486e83bd41303a004a763da31744a65cc 100644
--- a/pub/lib/fit.cpp
+++ b/pub/lib/fit.cpp
@@ -19,6 +19,7 @@
 #include "fsel.hpp"
 #include "loop.hpp"
 #include "mem.hpp"
+#include "expr.hpp"
 #include "obj.hpp"
 #include "olf.hpp"
 #include "slice.hpp"
@@ -514,7 +515,7 @@ void NCurveFit::fit(bool _allow_slow_conv)
         for (int j = 0; j < fc->nJ(); ++j)
             fc->VC(j)->assert_attr();
 
-        const COld* fd = SMem::instance()->mem_get_D(fc->kd);
+        COld* fd = SMem::instance()->mem_get_D(fc->kd);
         if (fc->nJ() != fd->nJ())
             throw S("data file and curve file have different number of spectra");
         if (!fc->nJ())
@@ -522,32 +523,6 @@ void NCurveFit::fit(bool _allow_slow_conv)
         if ((fc->weighing == COlc::_VAR || fc->weighing == COlc::_VARD) && !fd->VS(0)->has_dy())
             throw S("Data have no error bars, cannot apply chosen fit weights");
 
-        if (fc->range_T) {
-            throw S("TODO: restore range evaluation");
-            /*
-            // overwrite fd with data that obye the range restriction:
-            POld fdr( fd->new_POld() );
-            for ( int j=0; j<fc->nJ(); j++ ) {
-                const CSpec *sin = fd->VS(j);
-                PSpec sout = PSpec( new CSpec );
-                sout->z = sin->z;
-                vector<double> range( sin->size() );
-                fc->range_T->tree_vec_val( &range, 0, fc->kd, j );
-                bool with_dy = sin->has_dy();
-                for ( int i=0; i<sin->size(); i++ ) {
-                    if ( range[i] ) {
-                        if( with_dy )
-                            sout->push_xyd( sin->x[i], sin->y[i], sin->dy[i] );
-                        else
-                            sout->push_xy( sin->x[i], sin->y[i] );
-                    }
-                }
-                fdr->V.push_back( sout );
-            }
-            fd.swap( fdr ); // TODO can we simplify ?
-            */
-        }
-
         control.epsilon = Epsilon;
         control.stepbound = Factor;
         control.patience = nCall;
diff --git a/pub/lib/fsel.cpp b/pub/lib/fsel.cpp
index c0c041682fda80de5bb8e41cba63d7727243af11..d5feb77bec0dd481edbe9f261af9cfd81dc8a276 100644
--- a/pub/lib/fsel.cpp
+++ b/pub/lib/fsel.cpp
@@ -58,6 +58,17 @@ int SFSel::nJ_max() const
     return ret;
 }
 
+//! Return the one and only D file in the current selection.
+const COld* SFSel::theOneD() const
+{
+    vector<int> ksel = selD();
+    if (ksel.size()==0)
+        throw "No data file selected";
+    else if (ksel.size()>1)
+        throw "More than one data file selected";
+    return dynamic_cast<const COld*>(SMem::instance()->mem_get(ksel[0]));
+}
+
 //**************************************************************************************************
 //*  Write to online file selection
 //**************************************************************************************************
diff --git a/pub/lib/fsel.hpp b/pub/lib/fsel.hpp
index 7d40e930521552b156014900c387d38bb3189cb8..028e994e1a2845e7032bbb56567deab6065e3adb 100644
--- a/pub/lib/fsel.hpp
+++ b/pub/lib/fsel.hpp
@@ -31,6 +31,7 @@ public:
     vector<int> selC() const;
     COlo* sel_first() const;
     int nJ_max() const;
+    const COld* theOneD() const;
 
     // Modify file selection:
     void sel_delete();
diff --git a/pub/lib/import.cpp b/pub/lib/import.cpp
index 921a052ff347e88ef28ef7f3cf533eb1ace4ebb0..57bd224d88b0f6b07675ce95bc16cf419eaaaa97 100644
--- a/pub/lib/import.cpp
+++ b/pub/lib/import.cpp
@@ -7,8 +7,9 @@
 //! \file  import.cpp
 //! \brief NImport: import tables or make data ex nihilo
 
-#include "defs.hpp"
+#include <boost/filesystem.hpp>
 
+#include "defs.hpp"
 
 #include "../readplus/ask.hpp"
 #include "../trivia/file_ops.hpp"
@@ -20,6 +21,8 @@
 #include "olf.hpp"
 #include "slice.hpp"
 
+namespace fs = boost::filesystem;
+
 
 //! Create a new online file from table.
 
@@ -63,7 +66,6 @@ void NImport::read_tab(string qualif)
     }
 
     FILE* fd;
-    string fdir, fshort, fext;
     for (int iF = 0; iF < inFiles.size(); ++iF) {
         if (!(fd = fopen(inFiles[iF].c_str(), "r")))
             throw "cannot open file " + inFiles[iF];
@@ -73,9 +75,8 @@ void NImport::read_tab(string qualif)
             fout->log_action("ft" + qualif + " " + script);
             fout->name = script;
         } else {
-            triv::fname_divide(inFiles[iF], &fdir, &fshort, &fext);
             fout->log_action("ft" + qualif + " " + inFiles[iF]);
-            fout->name = fshort;
+            fout->name = fs::path(inFiles[iF]).filename().stem().string();
             if (choosecol) {
                 fout->log_action("y from column " + S(iycol));
                 fout->name += "_" + S(iycol);
@@ -141,7 +142,7 @@ void NImport::read_tab(string qualif)
                 }
                 if (!horizontal) {
                     s = PSpec(new CSpec);
-                    s->z.resize(nz);
+                    s->z.resize(nzdat);
                     for (int iz = 0; iz < nzdat; ++iz)
                         s->z[iz] = RObjDbl(new CObjDbl(zdat[iz]));
                 }
@@ -182,12 +183,12 @@ void NImport::read_tab(string qualif)
                     if (dat.size() != (with_d ? 3 : 2)) {
                         throw "line " + S(n_in) + " (line " + S(nline) + " in block " + S(nblock)
                             + ") [" + lin + "] contains " + S(dat.size()) + " values; "
-                            + "at present, exactly " + S(with_d ? 3 : 2) + " are required";
+                            + " exactly " + S(with_d ? 3 : 2) + " are required";
                     }
                     if (with_d)
-                        s->push_xy(dat[0], dat[1]);
-                    else
                         s->push_xyd(dat[0], dat[1], dat[2]);
+                    else
+                        s->push_xy(dat[0], dat[1]);
                 }
             }
             ++nline;
diff --git a/pub/lib/manip.cpp b/pub/lib/manip.cpp
index 0d7ce66a07d4242ea40f0212113f5ee36709dccf..3c71184fa4c4e0c0cc133599ef2cb2b2e3d28b6a 100644
--- a/pub/lib/manip.cpp
+++ b/pub/lib/manip.cpp
@@ -77,7 +77,7 @@ void NManip::unfreeze_all_slices()
 
 //! Delete (or retain) points according to list of indices.
 
-void NManip::points_select(bool sel_del)
+void NManip::points_select(const bool sel_del)
 {
     FileIterator fiter(SFSel::instance()->selD());
     static string sel = "";
@@ -116,7 +116,7 @@ void NManip::points_select(bool sel_del)
 
 //! Bin points.
 
-void NManip::points_rebin()
+void NManip::points_rebin(const bool sampling_err)
 {
     FileIterator fiter(SFSel::instance()->selD());
 
@@ -142,7 +142,7 @@ void NManip::points_rebin()
                 throw S("First bin must start at 0");
             breaks.push_back(sin->size());
 
-            PSpec sout = sin->binned(breaks);
+            PSpec sout = sin->binned(breaks, sampling_err);
 
             fout->V.push_back(move(sout));
         }
@@ -153,7 +153,7 @@ void NManip::points_rebin()
 
 //! Bin points.
 
-void NManip::points_rebin_by_factor()
+void NManip::points_rebin_by_factor(const bool sampling_err)
 {
     FileIterator fiter(SFSel::instance()->selD());
     static int ng = 2;
@@ -175,7 +175,7 @@ void NManip::points_rebin_by_factor()
             for (int iout = 0; iout < nout + 1; ++iout)
                 breaks[iout] = iout * ng;
 
-            PSpec sout = sin->binned(breaks);
+            PSpec sout = sin->binned(breaks, sampling_err);
 
             fout->V.push_back(move(sout));
         }
@@ -186,16 +186,9 @@ void NManip::points_rebin_by_factor()
 
 //! Bin points to keep errors below a certain bound.
 
-void NManip::points_rebin_by_err(const string& subcmd)
+void NManip::points_rebin_by_err(const bool absolute)
 {
     FileIterator fiter(SFSel::instance()->selD());
-    bool mode_abs;
-    if (subcmd == "a")
-        mode_abs = true;
-    else if (subcmd == "r")
-        mode_abs = false;
-    else
-        throw S("invalid subcommand");
 
     static double errbound;
     errbound = dask("Keep error below", errbound);
@@ -212,15 +205,15 @@ void NManip::points_rebin_by_err(const string& subcmd)
             double xg = 0, yg = 0, vg = 0;
             int ng = 0, istart = 0;
             for (int i = 0; i < sin->size(); ++i) {
-                if (!mode_abs && sin->y[i] < 0)
+                if (!absolute && sin->y[i] < 0)
                     throw("negative counts not compatible with relative error bounds");
                 xg += sin->x[i];
                 yg += sin->y[i];
                 vg += SQR(sin->dy[i]);
                 ++ng;
                 double dg = sqrt(vg);
-                if ((mode_abs && dg / ng < errbound)
-                    || (!mode_abs && yg > 0 && dg / yg < errbound)) {
+                if ((absolute && dg / ng < errbound)
+                    || (!absolute && yg > 0 && dg / yg < errbound)) {
                     sout->push_xyd(xg / ng, yg / ng, dg / ng);
                     groupinfo += S(istart) + ",";
                     xg = 0;
@@ -233,7 +226,7 @@ void NManip::points_rebin_by_err(const string& subcmd)
             if (sout->size())
                 fout->V.push_back(move(sout));
         }
-        string docline = "mpae" + subcmd + " " + S(errbound);
+        string docline = S("mpa") + (absolute ? "e" : "r") + " " + S(errbound);
         if (fin->nJ() == 1)
             docline += " #=> groups " + groupinfo.substr(0, groupinfo.size() - 1);
         fout->log_action(docline);
@@ -580,7 +573,7 @@ void NManip::ScaRemoveConstantZ(COlo* fio)
 
 //! Delete (or retain) spectra according to list of indices.
 
-void NManip::slices_select(bool sel_del)
+void NManip::slices_select(const bool sel_del)
 {
     vector<int> JSel, JSelSorted;
     static string jSel = "";
@@ -604,7 +597,7 @@ void NManip::slices_select(bool sel_del)
 
 //! Bin spectra.
 
-void NManip::slices_rebin()
+void NManip::slices_rebin(const bool sampling_err)
 {
     FileIterator fiter(SFSel::instance()->sel());
     vector<int> JSel;
@@ -646,7 +639,7 @@ void NManip::slices_rebin()
             if (fd) {
                 PSpec sout(new CSpec());
                 bool in_with_dy = fd->VS(ji)->has_dy();
-                bool out_with_dy = in_with_dy || mj > 1;
+                bool out_with_dy = in_with_dy || (sampling_err && mj > 1);
                 int n = fd->nPts(ji);
                 sout->resize(n, out_with_dy);
                 // x grids must be equal:
@@ -684,10 +677,11 @@ void NManip::slices_rebin()
                             for (int jj = ji; jj < jf; jj++) {
                                 if (fd->VS(jj)->has_dy())
                                     vm_src += SQR(fd->VS(jj)->dy[i]);
-                                vm_grp += SQR(fd->VS(jj)->y[i] - ym);
+                                if (sampling_err)
+                                    vm_grp += SQR(fd->VS(jj)->y[i] - ym);
                             }
                             double vm = vm_src / mj / mj;
-                            if (mj > 1)
+                            if (sampling_err && mj > 1)
                                 vm += vm_grp / (mj - 1);
                             sout->dy[i] = sqrt(vm);
                         }
diff --git a/pub/lib/manip.hpp b/pub/lib/manip.hpp
index 350895313b3a3c97a86f23f7ee4dcec6d8bf4e9b..6d9f399b836e9e8b4d9714aee8ab92d010158a58 100644
--- a/pub/lib/manip.hpp
+++ b/pub/lib/manip.hpp
@@ -16,19 +16,19 @@ namespace NManip
 {
 void freeze_slices();
 void unfreeze_all_slices();
-void points_select(bool sel_del);
-void points_rebin();
-void points_rebin_by_factor();
-void points_rebin_by_err(const string& subcmd);
+void points_select(const bool sel_del);
+void points_rebin(const bool sampling_err);
 void points_rebin_duplicates();
+void points_rebin_by_factor(const bool sampling_err);
+void points_rebin_by_err(const bool absolute);
 void points_break_by_factor();
 void points_sort();
 void points_symmetrize();
 void points_remove_err();
 void points_interpolate();
 void points_redistribute();
-void slices_select(bool sel_del);
-void slices_rebin();
+void slices_select(const bool sel_del);
+void slices_rebin(const bool sampling_err);
 void slices_merge();
 void slices_break();
 void slices_spawn();
diff --git a/pub/lib/node.cpp b/pub/lib/node.cpp
index 658f99480d46cd962c0d8e464375951514c02615..2fc89f8c5a90f487b93d1ba9f5b91b1973ae0ae3 100644
--- a/pub/lib/node.cpp
+++ b/pub/lib/node.cpp
@@ -26,6 +26,7 @@
 
 extern bool allow_slow_conv; // set in curve.cpp
 
+const int debug = 0;
 
 //**************************************************************************************************
 //* CNodeWithArgs
@@ -33,12 +34,18 @@ extern bool allow_slow_conv; // set in curve.cpp
 
 bool CNodeWithArgs::has_dummy() const
 {
-    return std::any_of(arg.begin(), arg.end(), [](RNode a) { return a && a->has_dummy(); });
+    bool ret = std::any_of(arg.begin(), arg.end(), [](RNode a) { return a && a->has_dummy(); });
+    if (debug)
+        std::cerr << ("CNodeWithArgs{" + tree_info() + "}.has_dummy -> " + S(ret) + "\n");
+    return ret;
 }
 
 bool CNodeWithArgs::has_conv() const
 {
-    return std::any_of(arg.begin(), arg.end(), [](RNode a) { return a && a->has_conv(); });
+    bool ret = std::any_of(arg.begin(), arg.end(), [](RNode a) { return a && a->has_conv(); });
+    if (debug)
+        std::cerr << ("CNodeWithArgs{" + tree_info() + "}.has_conv -> " + S(ret) + "\n");
+    return ret;
 }
 
 int CNodeWithArgs::npar() const
@@ -47,22 +54,33 @@ int CNodeWithArgs::npar() const
     for (RNode a : arg)
         if (a)
             ret = std::max(ret, a->npar());
+    if (debug)
+        std::cerr << ("CNodeWithArgs{" + tree_info() + "}.npar -> " + S(ret) + "\n");
     return ret;
 }
 
 bool CNodeWithArgs::k_dependent() const
 {
-    return std::any_of(arg.begin(), arg.end(), [](RNode a) { return a && a->k_dependent(); });
+    bool ret = std::any_of(arg.begin(), arg.end(), [](RNode a) { return a && a->k_dependent(); });
+    if (debug)
+        std::cerr << ("CNodeWithArgs{" + tree_info() + "}.k_dep -> " + S(ret) + "\n");
+    return ret;
 }
 
 bool CNodeWithArgs::j_dependent() const
 {
-    return std::any_of(arg.begin(), arg.end(), [](RNode a) { return a && a->j_dependent(); });
+    bool ret = std::any_of(arg.begin(), arg.end(), [](RNode a) { return a && a->j_dependent(); });
+    if (debug)
+        std::cerr << ("CNodeWithArgs{" + tree_info() + "}.j_dep -> " + S(ret) + "\n");
+    return ret;
 }
 
 bool CNodeWithArgs::i_dependent() const
 {
-    return std::any_of(arg.begin(), arg.end(), [](RNode a) { return a && a->i_dependent(); });
+    bool ret = std::any_of(arg.begin(), arg.end(), [](RNode a) { return a && a->i_dependent(); });
+    if (debug)
+        std::cerr << ("CNodeWithArgs{" + tree_info() + "}.i_dep -> " + S(ret) + "\n");
+    return ret;
 }
 
 
@@ -70,12 +88,19 @@ bool CNodeWithArgs::i_dependent() const
 //* CNodeFun: function/operator node
 //**************************************************************************************************
 
-CNodeFun1::CNodeFun1(const CFunc* _fu, RNode _a0) : CNodeFun(1, _fu) { arg[0] = _a0; }
+CNodeFun1::CNodeFun1(const CFunc* _fu, RNode _a0) : CNodeFun(1, _fu)
+{
+    arg[0] = _a0;
+    if (debug)
+        std::cerr << ("CNodeFun1 := " + tree_info() + "\n");
+}
 
 CNodeFun2::CNodeFun2(const CFunc* _fu, RNode _a0, RNode _a1) : CNodeFun(2, _fu)
 {
     arg[0] = _a0;
     arg[1] = _a1;
+    if (debug)
+        std::cerr << ("CNodeFun2 := " + tree_info() + "\n");
 }
 
 CNodeFun3::CNodeFun3(const CFunc* _fu, RNode _a0, RNode _a1, RNode _a2) : CNodeFun(3, _fu)
@@ -83,12 +108,16 @@ CNodeFun3::CNodeFun3(const CFunc* _fu, RNode _a0, RNode _a1, RNode _a2) : CNodeF
     arg[0] = _a0;
     arg[1] = _a1;
     arg[2] = _a2;
+    if (debug)
+        std::cerr << ("CNodeFun1 := " + tree_info() + "\n");
 }
 
 //! Returns the result of function evaluation for given arguments.
 
 RObj CNodeFun::tree_val(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeFun{" + tree_info() + "}.tree_val ...\n");
     string basetypes;
     const CTypedFunc* tf = nullptr;
     try {
@@ -276,11 +305,16 @@ RObj CNodeFun::tree_val(const CContext& ctx) const
 }
 
 
-CCoord CNodeFun1::node_coord(int k) const { return fu->coord(arg[0]->node_coord(k)); }
+CCoord CNodeFun1::node_coord(int k) const
+{
+    return fu->coord(arg[0]->node_coord(k));
+}
+
 CCoord CNodeFun2::node_coord(int k) const
 {
     return fu->coord(arg[0]->node_coord(k), arg[1]->node_coord(k));
 }
+
 CCoord CNodeFun3::node_coord(int k) const
 {
     return fu->coord(arg[0]->node_coord(k), arg[1]->node_coord(k), arg[2]->node_coord(k));
@@ -288,7 +322,10 @@ CCoord CNodeFun3::node_coord(int k) const
 
 //! Returns string representation of this node.
 
-string CNodeFun1::tree_info() const { return fu->tag + "(" + arg[0]->tree_info() + ")"; }
+string CNodeFun1::tree_info() const
+{
+    return fu->tag + "(" + arg[0]->tree_info() + ")";
+}
 
 //! Returns string representation of this node.
 
@@ -310,11 +347,12 @@ string CNodeFun3::tree_info() const
 //* CNodeRange: range node
 //**************************************************************************************************
 
-
 //! Evaluates the range in context, and returns a vector object pointer.
 
 RObj CNodeRange::tree_val(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeRange{" + tree_info() + "}.tree_val ...\n");
     // evaluate arguments, determine types, assert they are scalar.
     vector<RObj> pa(narg);
     bool all_int = true;
@@ -348,7 +386,10 @@ RObj CNodeRange::tree_val(const CContext& ctx) const
     }
 }
 
-CCoord CNodeRange::node_coord(int k) const { return CCoord("range", ""); }
+CCoord CNodeRange::node_coord(int k) const
+{
+    return CCoord("range", "");
+}
 
 //! Returns string representation of this node.
 
@@ -363,7 +404,6 @@ string CNodeRange::tree_info() const
 //* CNodeList
 //**************************************************************************************************
 
-
 CNodeList::CNodeList(RNode _incremand, RNode _increment) : CNodeWithArgs(1)
 {
     if (auto old = PCAST<const CNodeList>(_incremand)) {
@@ -381,6 +421,8 @@ CNodeList::CNodeList(RNode _incremand, RNode _increment) : CNodeWithArgs(1)
 
 RObj CNodeList::tree_val(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeList{" + tree_info() + "}.tree_val ...\n");
     // evaluate arguments, determine types
     vector<RObj> pa(narg);
     bool all_int = true;
@@ -469,6 +511,8 @@ CNodeGeni::CNodeGeni(const class CGeni* _geni, RRef _ref) : CNodeWithArgs(_geni-
             arg[iarg] = RNode(new CNodePointX(ref));
         else if (geni->default_args[iarg] == "y")
             arg[iarg] = RNode(new CNodePointY(ref));
+        else if (geni->default_args[iarg] == "expr")
+            throw S("syntax error: functional(expr) does not have default argument");
         else
             throw S("BUG: unexpected default arg");
     }
@@ -495,6 +539,8 @@ CNodeGeni::CNodeGeni(const class CGeni* _geni, RNode _a0, RNode _a1) : CNodeWith
 
 RObj CNodeGeni::tree_val(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeGeni{" + tree_info() + "}.tree_val ...\n");
     try {
         if (ctx.dim == CContext::_VT)
             throw "Unexpected evaluation in curve context {context: " + ctx.context_info() + "}";
@@ -517,12 +563,11 @@ RObj CNodeGeni::tree_val(const CContext& ctx) const
                 throw S("vector arguments have different size");
         }
         // Now evaluate the function.
-        double val;
-        geni->eval(&val, nullptr, n, pav); // TODO: compute errors
+        RObjNum val = geni->eval(n, pav); // TODO: compute errors
         if (ctx.dim == CContext::_1)
-            return RObjDbl(new CObjDbl(val));
+            return val;
         else if (ctx.dim == CContext::_VI)
-            return RObjVecDbl(new CObjVecDbl(ctx.nv, val));
+            return val->to_vec(ctx.nv);
         else
             throw "BUG: unforeseen dimension {context: " + ctx.context_info() + "}";
 
@@ -593,6 +638,8 @@ CNodeCvin::CNodeCvin(const class CCvin* _cvin, RRef _ref, RNode _a0, RNode _a1)
 
 RObj CNodeCvin::tree_val(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeCvin{" + tree_info() + "}.tree_val ...\n");
     try {
         if (ctx.dim != CContext::_1)
             throw "Unexpected is_vec() {context: " + ctx.context_info() + "}";
@@ -660,7 +707,11 @@ CNodeVal::CNodeVal(int _val) : val(PObjInt(new CObjInt(_val))) {}
 
 bool CNodeVal::looks_like_indices() const { return PCAST<const CObjInt>(val) != nullptr; }
 
-RObj CNodeVal::tree_val(const CContext& ctx) const { return val; }
+RObj CNodeVal::tree_val(const CContext& ctx) const {
+    if (debug)
+        std::cerr << ("CNodeVal{" + tree_info() + "}.tree_val -> " + val->to_s() + "\n");
+    return val;
+}
 
 CCoord CNodeVal::node_coord(int k) const { return CCoord(val->to_s(), ""); }
 
@@ -677,21 +728,40 @@ RObj CNodeIdxI::tree_val(const CContext& ctx) const
     if (ctx.dim == CContext::_1) {
         if (ctx.i == -1)
             throw S("missing index i");
-        return RObjInt(new CObjInt(ctx.i));
+        RObjInt ret(new CObjInt(ctx.i));
+        if (debug)
+            std::cerr << ("CNodeIdxI{" + tree_info() + "}.tree_val[dim=1] -> "
+                          + ret->to_s() + "\n");
+        return ret;
     } else if (ctx.dim == CContext::_VI) {
         PObjVecInt pret(new CObjVecInt(ctx.nv));
         for (int i = 0; i < ctx.nv; ++i)
             pret->v[i] = i;
+        if (debug)
+            std::cerr << ("CNodeIdxI{" + tree_info() + "}.tree_val[dim=VI] -> "
+                          + pret->to_s() + "\n");
         return pret;
     } else
         throw S("index i not defined in this context");
 }
 
 
-RObj CNodeIdxJ::tree_val(const CContext& ctx) const { return RObjInt(new CObjInt(ctx.j)); }
+RObj CNodeIdxJ::tree_val(const CContext& ctx) const
+{
+    RObj ret = RObjInt(new CObjInt(ctx.j));
+    if (debug)
+        std::cerr << ("CNodeIdxJ{" + tree_info() + "}.tree_val -> " + ret->to_s() + "\n");
+    return ret;
+}
 
 
-RObj CNodeIdxK::tree_val(const CContext& ctx) const { return RObjInt(new CObjInt(ctx.k)); }
+RObj CNodeIdxK::tree_val(const CContext& ctx) const
+{
+    RObj ret = RObjInt(new CObjInt(ctx.k));
+    if (debug)
+        std::cerr << ("CNodeIdxK{" + tree_info() + "}.tree_val -> " + ret->to_s() + "\n");
+    return ret;
+}
 
 
 //**************************************************************************************************
@@ -700,7 +770,10 @@ RObj CNodeIdxK::tree_val(const CContext& ctx) const { return RObjInt(new CObjInt
 
 RObj CNodeSessionNK::tree_val(const CContext& ctx) const
 {
-    return RObjInt(new CObjInt(SMem::instance()->mem_size()));
+    RObj ret = RObjInt(new CObjInt(SMem::instance()->mem_size()));
+    if (debug)
+        std::cerr << ("CNodeNK{" + tree_info() + "}.tree_val -> " + ret->to_s() + "\n");
+    return ret;
 }
 
 
@@ -710,6 +783,8 @@ RObj CNodeSessionNK::tree_val(const CContext& ctx) const
 
 RObj CNodeFile::tree_val(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeFile{" + tree_info() + "}.tree_val ...\n");
     if (ctx.dim == CContext::_VI) {
         CContext myctx = ctx;
         myctx.dim = CContext::_1;
@@ -741,12 +816,16 @@ CCoord CNodeFile::node_coord(int _k) const
 
 RObj CNodeFileNJ::tree_val_scalar(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeFileNJ{" + tree_info() + "}.tree_val_scalar ...\n");
     const COlo* f = SMem::instance()->mem_get(ref->get_k(ctx));
     return RObjInt(new CObjInt(f->nJ()));
 }
 
 RObj CNodeFileR::tree_val_scalar(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeFileR{" + tree_info() + "}.tree_val_scalar ...\n");
     const COlo* f = SMem::instance()->mem_get(ref->get_k(ctx));
     if (num < 0 || num >= f->RPar.size())
         throw "file has no parameter r" + S(num);
@@ -768,6 +847,8 @@ CCoord CNodeFileR::file_coord(const COlo* f) const
 
 RObj CNodeSliceZ::tree_val_scalar(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeSliceZ{" + tree_info() + "}.tree_val_scalar ...\n");
     const COlo* f = SMem::instance()->mem_get(ref->get_k(ctx));
     int j = PCAST<const CRef2>(ref)->get_j(ctx, f->nJ());
     const CSlice* s = f->V[j].get();
@@ -786,6 +867,8 @@ CCoord CNodeSliceZ::file_coord(const COlo* f) const
 
 RObj CNodeSpecNI::tree_val_scalar(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeSpecNI{" + tree_info() + "}.tree_val_scalar ...\n");
     const COlo* f = SMem::instance()->mem_get(ref->get_k(ctx));
     const COld* fd = dynamic_cast<const COld*>(f);
     if (!fd)
@@ -796,6 +879,8 @@ RObj CNodeSpecNI::tree_val_scalar(const CContext& ctx) const
 
 RObj CNodeCurve::tree_val_scalar(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeCurve{" + tree_info() + "}.tree_val_scalar ...\n");
     const COlo* f = SMem::instance()->mem_get(ref->get_k(ctx));
     const COlc* fc = dynamic_cast<const COlc*>(f);
     if (!fc)
@@ -807,6 +892,8 @@ RObj CNodeCurve::tree_val_scalar(const CContext& ctx) const
 
 RObj CNodeCurveP::curve_val_scalar(const CCurve* c) const
 {
+    if (debug)
+        std::cerr << ("CNodeCurveP{" + tree_info() + "}.tree_val_scalar ...\n");
     if (num < 0 || num >= c->P.size())
         throw "curve has no p" + S(num);
     return RObjDbl(new CObjDbl(c->P[num]));
@@ -842,11 +929,14 @@ RObj CNodeCurveR2::curve_val_scalar(const CCurve* c) const
 
 RObj CNodePoint::tree_val(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodePoint{" + tree_info() + "}.tree_val ...\n");
     auto ref3 = PCAST<const CRef3>(ref);
     if (!ref3)
         throw S("BUG: NodePoint has no Ref3");
     if (ctx.dim == CContext::_VI) {
-        if (ref->k_depends_on_i() || ref3->j_depends_on_i()) {
+        if (ref->k_depends_on_i() || ref3->j_depends_on_i()
+            || (ref3->ti && ref3->ti->i_dependent())) {
             if (ctx.nv < 0)
                 throw S("BUG: i-dependent K or J with unspecified return array length");
             if (!ref3->ti) // Could be easily supported, but is forbidden to prevent accidental use
@@ -858,17 +948,37 @@ RObj CNodePoint::tree_val(const CContext& ctx) const
                 myctx.i = i;
                 tmp->v.push_back(tree_val_point(myctx, ref3->ti->tree_val_idx(myctx, "i")));
             }
-            return tmp->to_vecnum();
-        } else if (!ref3->ti || ref3->ti->i_dependent()) {
-            return tree_val_vector(ctx);
+            RObj ret = tmp->to_vecnum();
+            if (debug)
+                std::cerr << ("... CNodePoint{" + tree_info() + "}.tree_val[dim=VI,i2j||i2k] -> "
+                              + ret->to_s() + "\n");
+            return ret;
+        } else if (!ref3->ti) {
+            RObj ret = tree_val_vector(ctx);
+            if (debug)
+                std::cerr << ("... CNodePoint{" + tree_info() + "}.tree_val[dim=VI,i2nil] -> "
+                              + ret->to_s() + "\n");
+            return ret;
         } else {
-            return tree_val_point(ctx, ref3->ti->tree_val_idx(ctx, "i"));
+            RObj ret = tree_val_point(ctx, ref3->ti->tree_val_idx(ctx, "i"));
+            if (debug)
+                std::cerr << ("... CNodePoint{" + tree_info() + "}.tree_val[dim=VI,i2i] -> "
+                              + ret->to_s() + "\n");
+            return ret;
         }
     } else {
         if (ref3->ti) {
-            return tree_val_point(ctx, ref3->ti->tree_val_idx(ctx, "i"));
+            RObj ret = tree_val_point(ctx, ref3->ti->tree_val_idx(ctx, "i"));
+            if (debug)
+                std::cerr << ("... CNodePoint{" + tree_info() + "}.tree_val[dim!=VI,ti] -> "
+                              + ret->to_s() + "\n");
+            return ret;
         } else {
-            return tree_val_point(ctx, ctx.i);
+            RObj ret = tree_val_point(ctx, ctx.i);
+            if (debug)
+                std::cerr << ("... CNodePoint{" + tree_info() + "}.tree_val[dim!=VI,!ti] -> "
+                              + ret->to_s() + "\n");
+            return ret;
         }
     }
 }
@@ -876,6 +986,8 @@ RObj CNodePoint::tree_val(const CContext& ctx) const
 
 RObj CNodePoint::tree_val_point(const CContext& ctx, int i) const
 {
+    if (debug)
+        std::cerr << ("CNodePoint{" + tree_info() + "}.tree_val_point -> ...\n");
     const COlo* f = SMem::instance()->mem_get(ref->get_k(ctx));
     const COld* fd = dynamic_cast<const COld*>(f);
     if (!fd)
@@ -884,12 +996,18 @@ RObj CNodePoint::tree_val_point(const CContext& ctx, int i) const
     const CSpec* s = fd->VS(j);
     if (i < 0 || i >= s->size())
         throw "invalid data point index " + S(i) + ", spectrum has length " + S(s->size());
-    return spec_val_point(s, i, ctx.want_error);
+    RObj ret = spec_val_point(s, i, ctx.want_error);
+    if (debug)
+        std::cerr << ("... CNodePoint{" + tree_info() + "}.tree_val_point -> "
+                      + ret->to_s() + "\n");
+    return ret;
 }
 
 
 RObj CNodePoint::tree_val_vector(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodePoint{" + tree_info() + "}.tree_val_vector ...\n");
     if (ctx.dim != CContext::_VI)
         throw S("BUG: unexpected context in tree_val_vector");
     const COlo* f = SMem::instance()->mem_get(ref->get_k(ctx));
@@ -904,18 +1022,28 @@ RObj CNodePoint::tree_val_vector(const CContext& ctx) const
     else if (n > s->size())
         throw "requested " + S(n) + " points while spectrum " + S(j) + " only has " + S(s->size())
             + " points";
-    return spec_val_vector(s, n, ctx.want_error);
+    RObj ret = spec_val_vector(s, n, ctx.want_error);
+    if (debug)
+        std::cerr << ("... CNodePoint{" + tree_info() + "}.tree_val_vector -> "
+                      + ret->to_s() + "\n");
+    return ret;
 }
 
 
 RObj CNodePointX::spec_val_point(const CSpec* s, int i, bool want_error) const
 {
-    return RObjDbl(new CObjDbl(s->x[i]));
+    RObj ret = RObjDbl(new CObjDbl(s->x[i]));
+    if (debug)
+        std::cerr << ("CNodePointX{" + tree_info() + "}.spec_val_point -> " + ret->to_s() + "\n");
+    return ret;
 }
 
 RObj CNodePointX::spec_val_vector(const CSpec* s, int n, bool want_error) const
 {
-    return RObjVecDbl(new CObjVecDbl(vector<double>(s->x.begin(), s->x.begin() + n)));
+    RObj ret = RObjVecDbl(new CObjVecDbl(vector<double>(s->x.begin(), s->x.begin() + n)));
+    if (debug)
+        std::cerr << ("CNodePointX{" + tree_info() + "}.spec_val_vector -> " + ret->to_s() + "\n");
+    return ret;
 }
 
 CCoord CNodePointX::file_coord(const COlo* f) const
@@ -929,17 +1057,24 @@ CCoord CNodePointX::file_coord(const COlo* f) const
 
 RObj CNodePointY::spec_val_point(const CSpec* s, int i, bool want_error) const
 {
-    return want_error && s->has_dy() ? RObjEnu(new CObjEnu(s->y[i], s->dy[i]))
-                                     : RObjDbl(new CObjDbl(s->y[i]));
+    RObj ret = want_error && s->has_dy()
+        ? RObjEnu(new CObjEnu(s->y[i], s->dy[i]))
+        : RObjDbl(new CObjDbl(s->y[i]));
+    if (debug)
+        std::cerr << ("CNodePointY{" + tree_info() + "}.spec_val_point -> " + ret->to_s() + "\n");
+    return ret;
 }
 
 RObj CNodePointY::spec_val_vector(const CSpec* s, int n, bool want_error) const
 {
-    return want_error && s->has_dy()
+    RObj ret = want_error && s->has_dy()
         ? RObjVecEnu(new CObjVecEnu(
               vector<double>(s->y.begin(), s->y.begin() + n),
               vector<double>(s->dy.begin(), s->dy.begin() + n)))
         : RObjVecDbl(new CObjVecDbl(vector<double>(s->y.begin(), s->y.begin() + n)));
+    if (debug)
+        std::cerr << ("CNodePointY{" + tree_info() + "}.spec_val_vector -> " + ret->to_s() + "\n");
+    return ret;
 }
 
 CCoord CNodePointY::file_coord(const COlo* f) const
@@ -953,14 +1088,20 @@ CCoord CNodePointY::file_coord(const COlo* f) const
 
 RObj CNodePointDY::spec_val_point(const CSpec* s, int i, bool want_error) const
 {
-    return RObjDbl(new CObjDbl(s->dy[i]));
+    RObj ret = RObjDbl(new CObjDbl(s->dy[i]));
+    if (debug)
+        std::cerr << ("CNodePointDY{" + tree_info() + "}.spec_val_point -> " + ret->to_s() + "\n");
+    return ret;
 }
 
 RObj CNodePointDY::spec_val_vector(const CSpec* s, int n, bool want_error) const
 {
     if (!s->has_dy())
         throw S("requested dy does not exist");
-    return RObjVecDbl(new CObjVecDbl(vector<double>(s->dy.begin(), s->dy.begin() + n)));
+    RObj ret = RObjVecDbl(new CObjVecDbl(vector<double>(s->dy.begin(), s->dy.begin() + n)));
+    if (debug)
+        std::cerr << ("CNodePointDY{" + tree_info() + "}.spec_val_vector -> " + ret->to_s() + "\n");
+    return ret;
 }
 
 CCoord CNodePointDY::file_coord(const COlo* f) const
@@ -983,6 +1124,8 @@ RObj CNodeIdf::tree_val(const CContext& ctx) const
     PObj ret = SVariRegistry::instance()->find(idf);
     if (!ret)
         throw "uninitialized variable " + idf;
+    if (debug)
+        std::cerr << ("CNodeIdf{" + tree_info() + "}.tree_val -> " + ret->to_s() + "\n");
     return ret;
 }
 
@@ -1013,6 +1156,8 @@ RObj CNodeDummy::tree_val(const CContext& ctx) const
 
 RObj CNodeCev::tree_val(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeCev{" + tree_info() + "}.tree_val ...\n");
     try {
         // get k, curve, j from context:
         int k = ref->get_k(ctx);
@@ -1043,6 +1188,8 @@ CCoord CNodeCev::node_coord(int k) const { return CCoord("c", ""); } // primitiv
 
 RObj CNodeMixin::tree_val(const CContext& ctx) const
 {
+    if (debug)
+        std::cerr << ("CNodeMixin{" + tree_info() + "}.tree_val ...\n");
     // Shift:
     RObj res_shift = shift->tree_val(ctx);
     RObjNum par = PCAST<const CObjNum>(res_shift);
@@ -1324,4 +1471,7 @@ RObjVecDbl CNodeDirac::convolve(
     return ret;
 }
 
-CCoord CNodeDirac::node_coord(int k) const { return CCoord("resol", ""); }
+CCoord CNodeDirac::node_coord(int k) const
+{
+    return CCoord("resol", "");
+}
diff --git a/pub/lib/node.hpp b/pub/lib/node.hpp
index 230dcd22ea0f103710f8a193c00b6b67625be645..ff2db06879b7e65756912bf2fe0d77e8f799cee5 100644
--- a/pub/lib/node.hpp
+++ b/pub/lib/node.hpp
@@ -22,6 +22,7 @@ protected:
     vector<RNode> arg;
 
 public:
+    CNodeWithArgs() = delete;
     CNodeWithArgs(int _narg) : narg(_narg) { arg.resize(narg); }
     int npar() const;
     bool k_dependent() const;
@@ -41,6 +42,7 @@ protected:
     const class CFunc* fu;
 
 public:
+    CNodeFun() = delete;
     CNodeFun(int _narg, const class CFunc* _fu) : CNodeWithArgs(_narg), fu(_fu) {}
     RObj tree_val(const CContext& ctx) const;
     virtual CCoord node_coord(int k) const = 0;
@@ -53,6 +55,7 @@ public:
 class CNodeFun1 : public CNodeFun
 {
 public:
+    CNodeFun1() = delete;
     CNodeFun1(const class CFunc* _fu, RNode a0);
     CCoord node_coord(int k) const;
     string tree_info() const;
@@ -64,6 +67,7 @@ public:
 class CNodeFun2 : public CNodeFun
 {
 public:
+    CNodeFun2() = delete;
     CNodeFun2(const class CFunc* _fu, RNode a0, RNode a1);
     CCoord node_coord(int k) const;
     string tree_info() const;
@@ -75,6 +79,7 @@ public:
 class CNodeFun3 : public CNodeFun
 {
 public:
+    CNodeFun3() = delete;
     CNodeFun3(const class CFunc* _fu, RNode a0, RNode a1, RNode a2);
     CCoord node_coord(int k) const;
     string tree_info() const;
@@ -89,6 +94,7 @@ private:
     bool inclusive_end;
 
 public:
+    CNodeRange() = delete;
     CNodeRange(
         bool _inclusive_end, RNode _beg = nullptr, RNode _end = nullptr, RNode _step = nullptr)
         : CNodeWithArgs(3), inclusive_end(_inclusive_end)
@@ -109,6 +115,7 @@ public:
 class CNodeList : public CNodeWithArgs
 {
 public:
+    CNodeList() = delete;
     CNodeList(RNode _list, RNode _incr);
     vector<RNode> args() const { return arg; }
     RObj tree_val(const CContext& ctx) const;
@@ -126,6 +133,7 @@ private:
     const class CGeni* geni;
 
 public:
+    CNodeGeni() = delete;
     CNodeGeni(const class CGeni* _geni, RRef _ref = nullptr);
     CNodeGeni(const class CGeni* _geni, RNode a0);
     CNodeGeni(const class CGeni* _geni, RNode a0, RNode a1);
@@ -145,6 +153,7 @@ private:
     RRef ref;
 
 public:
+    CNodeCvin() = delete;
     CNodeCvin(const class CCvin* _cvin, RRef _ref, RNode a0, RNode a1);
     bool k_dependent() const { return true; }
     RObj tree_val(const CContext& ctx) const;
@@ -161,6 +170,7 @@ private:
     RObj val;
 
 public:
+    CNodeVal() = delete;
     CNodeVal(RObj _val) : val(_val) {}
     CNodeVal(double _val);
     CNodeVal(int _val);
@@ -240,6 +250,7 @@ protected:
     RRef ref;
 
 public:
+    CNodeFile() = delete;
     CNodeFile(RRef _ref) : ref(_ref) {}
     void set_ref(RRef& _ref) { ref = _ref; };
     bool k_dependent() const { return true; }
@@ -255,6 +266,7 @@ public:
 class CNodeFileNJ : public CNodeFile
 {
 public:
+    CNodeFileNJ() = delete;
     CNodeFileNJ(RRef _ref) : CNodeFile(_ref) {}
     string name() const { return "nj"; }
     RObj tree_val_scalar(const CContext& ctx) const;
@@ -269,6 +281,7 @@ private:
     int num;
 
 public:
+    CNodeFileR() = delete;
     CNodeFileR(int _num, RRef _ref) : CNodeFile(_ref), num(_num) {}
     CCoord file_coord(const COlo* f) const;
     string name() const { return "r" + S(num); }
@@ -281,6 +294,7 @@ public:
 class CNodeSlice : public CNodeFile
 {
 public:
+    CNodeSlice() = delete;
     CNodeSlice(RRef _ref) : CNodeFile(_ref) {}
 };
 
@@ -293,6 +307,7 @@ private:
     int num;
 
 public:
+    CNodeSliceZ() = delete;
     CNodeSliceZ(int _num, RRef _ref) : CNodeSlice(_ref), num(_num) {}
     CCoord file_coord(const COlo* f) const;
     string name() const { return "z" + S(num); }
@@ -305,6 +320,7 @@ public:
 class CNodeSpecNI : public CNodeSlice
 {
 public:
+    CNodeSpecNI() = delete;
     CNodeSpecNI(RRef _ref) : CNodeSlice(_ref) {}
     string name() const { return "ni"; }
     RObj tree_val_scalar(const CContext& ctx) const;
@@ -316,6 +332,7 @@ public:
 class CNodeCurve : public CNodeSlice
 {
 public:
+    CNodeCurve() = delete;
     CNodeCurve(RRef _ref) : CNodeSlice(_ref) {}
     RObj tree_val_scalar(const CContext& ctx) const;
     virtual RObj curve_val_scalar(const CCurve* c) const = 0;
@@ -330,6 +347,7 @@ private:
     int num;
 
 public:
+    CNodeCurveP() = delete;
     CNodeCurveP(int _num, RRef _ref) : CNodeCurve(_ref), num(_num) {}
     CCoord file_coord(const COlo* f) const;
     string name() const { return "p" + S(num); }
@@ -343,6 +361,7 @@ public:
 class CNodeCurveOutcome : public CNodeCurve
 {
 public:
+    CNodeCurveOutcome() = delete;
     CNodeCurveOutcome(RRef _ref) : CNodeCurve(_ref) {}
     string name() const { return "oc"; }
     RObj curve_val_scalar(const CCurve* c) const;
@@ -354,6 +373,7 @@ public:
 class CNodeCurveChi2 : public CNodeCurve
 {
 public:
+    CNodeCurveChi2() = delete;
     CNodeCurveChi2(RRef _ref) : CNodeCurve(_ref) {}
     string name() const { return "chi2"; }
     RObj curve_val_scalar(const CCurve* c) const;
@@ -365,6 +385,7 @@ public:
 class CNodeCurveR2 : public CNodeCurve
 {
 public:
+    CNodeCurveR2() = delete;
     CNodeCurveR2(RRef _ref) : CNodeCurve(_ref) {}
     string name() const { return "R2"; }
     RObj curve_val_scalar(const CCurve* c) const;
@@ -394,6 +415,7 @@ public:
 class CNodePointX : public CNodePoint
 {
 public:
+    CNodePointX() = delete;
     CNodePointX(RRef _ref) : CNodePoint(_ref) {}
     CCoord file_coord(const COlo* f) const;
     string name() const { return "x"; }
@@ -407,6 +429,7 @@ public:
 class CNodePointY : public CNodePoint
 {
 public:
+    CNodePointY() = delete;
     CNodePointY(RRef _ref) : CNodePoint(_ref) {}
     CCoord file_coord(const COlo* f) const;
     string name() const { return "y"; }
@@ -420,6 +443,7 @@ public:
 class CNodePointDY : public CNodePoint
 {
 public:
+    CNodePointDY() = delete;
     CNodePointDY(RRef _ref) : CNodePoint(_ref) {}
     CCoord file_coord(const COlo* f) const;
     string name() const { return "dy"; }
@@ -436,6 +460,7 @@ private:
     string idf;
 
 public:
+    CNodeIdf() = delete;
     CNodeIdf(string _s);
     RObj tree_val(const CContext& ctx) const;
     CCoord node_coord(int k) const;
@@ -468,6 +493,7 @@ private:
     RNode arg;
 
 public:
+    CNodeCev() = delete;
     CNodeCev(RRef _ref, RNode _arg) : ref(_ref), arg(_arg) {}
     bool k_dependent() const { return true; }
     bool has_dummy() const { return arg->has_dummy(); }
@@ -486,6 +512,7 @@ protected:
     RNode shift;
 
 public:
+    CNodeMixin() = delete;
     CNodeMixin(const RNode& _shift) : shift(_shift) {}
     int npar() const { return shift->npar(); }
     bool k_dependent() const { return shift->k_dependent(); }
@@ -507,9 +534,9 @@ protected:
     RNode theory;
 
 public:
-    CNodeConvBase(const RNode& _theory, const RNode& _shift) : CNodeMixin(_shift), theory(_theory)
-    {
-    }
+    CNodeConvBase() = delete;
+    CNodeConvBase(const RNode& _theory, const RNode& _shift)
+        : CNodeMixin(_shift), theory(_theory) {}
     int npar() const { return std::max(shift->npar(), theory->npar()); }
     bool k_dependent() const { return theory->k_dependent() || shift->k_dependent(); }
     bool j_dependent() const { return theory->j_dependent() || shift->j_dependent(); }
@@ -524,10 +551,9 @@ public:
 class CNodeConv : public CNodeConvBase
 {
 public:
+    CNodeConv() = delete;
     CNodeConv(const RNode& _theory, const RNode& _shift = RNode(new CNodeVal(0.0)))
-        : CNodeConvBase(_theory, _shift)
-    {
-    }
+        : CNodeConvBase(_theory, _shift) {}
     RObj copy_theory(const CContext& ctx, double theshift) const;
     RObjVecDbl convolve(
         const CContext& ctx, double theshift, const CSpec* sv, double conv_norm,
@@ -544,8 +570,9 @@ public:
 class CNodePConv : public CNodeConvBase
 {
 public:
+    CNodePConv() = delete;
     CNodePConv(const RNode& _theory, const RNode& _shift = RNode(new CNodeVal(0.0)))
-        : CNodeConvBase(_theory, _shift){};
+        : CNodeConvBase(_theory, _shift) {};
     RObj copy_theory(const CContext& ctx, double theshift) const;
     RObjVecDbl convolve(
         const CContext& ctx, double theshift, const CSpec* sv, double conv_norm,
diff --git a/pub/lib/obj.cpp b/pub/lib/obj.cpp
index 63d107d6989800f49d8b8da57af065fe58b7cd30..d60a1987e4f1704ff95ff37fbd56b3e3a4af0292 100644
--- a/pub/lib/obj.cpp
+++ b/pub/lib/obj.cpp
@@ -40,6 +40,10 @@ string CObjInt::to_s(int maxlen, int minlen, int prec) const
     return ret;
 }
 
+RObjVecNum CObjInt::to_vec(int repetitions) const
+{
+    return RObjVecInt(new CObjVecInt(vector<int>(repetitions, val)));
+}
 
 //**************************************************************************************************
 //  CObjDbl
@@ -65,6 +69,11 @@ string CObjDbl::result_info() const
         return "CObjDbl(" + to_s() + ")";
 }
 
+RObjVecNum CObjDbl::to_vec(int repetitions) const
+{
+    return RObjVecDbl(new CObjVecDbl(vector<double>(repetitions, val)));
+}
+
 
 //**************************************************************************************************
 //  CObjEnu
@@ -84,6 +93,12 @@ string CObjEnu::result_info() const
         return "CObjDbl(" + to_s() + ")";
 }
 
+RObjVecNum CObjEnu::to_vec(int repetitions) const
+{
+    return RObjVecEnu(new CObjVecEnu(vector<double>(repetitions, val),
+                                     vector<double>(repetitions, err)));
+}
+
 
 //**************************************************************************************************
 //  CObjVec
@@ -134,12 +149,21 @@ RObj CObjVecObj::to_vecnum() const
 
 string CObjVecObj::to_s(int maxlen, int minlen, int prec) const
 {
-    string ret;
+    string ret = "[";
     for (int i = 0; i < v.size(); ++i) {
         ret += v[i]->to_s();
         if (i < v.size() - 1)
             ret += ",";
     }
+    ret += "]";
+    return ret;
+}
+
+vector<double> CObjVecObj::to_rvec() const
+{
+    vector<double> ret(size());
+    for (int i = 0; i < v.size(); ++i)
+        ret[i] = v[i]->to_r();
     return ret;
 }
 
@@ -151,12 +175,13 @@ string CObjVecObj::to_s(int maxlen, int minlen, int prec) const
 
 string CObjVecInt::to_s(int maxlen, int minlen, int prec) const
 {
-    string ret;
+    string ret = "[";
     for (int i = 0; i < v.size(); ++i) {
         ret += S(v[i]);
         if (i < v.size() - 1)
             ret += ",";
     }
+    ret += "]";
     return ret;
 }
 
@@ -174,12 +199,13 @@ string CObjVecInt::result_info() const { return to_s(); }
 
 string CObjVecDbl::to_s(int maxlen, int minlen, int prec) const
 {
-    string ret;
+    string ret = "[";
     for (int i = 0; i < v.size(); ++i) {
         ret += S(v[i]);
         if (i < v.size() - 1)
             ret += ",";
     }
+    ret += "]";
     return ret;
 }
 
diff --git a/pub/lib/obj.hpp b/pub/lib/obj.hpp
index acfcea515ea140339e0cf8ed72d90c3b7563e9bd..616c831ce25353cb1c967021167fc2009a02acf3 100644
--- a/pub/lib/obj.hpp
+++ b/pub/lib/obj.hpp
@@ -20,7 +20,6 @@ class CObj
 {
 public:
     virtual ~CObj() {}
-    // virtual PObj clone() const =0;
     virtual bool is_vec() const = 0;
     virtual bool has_err() const = 0;
     virtual char base_type() const = 0;
@@ -50,6 +49,7 @@ public:
     bool is_vec() const { return false; }
     virtual double to_dr() const { return 0.; }
     virtual double to_dr(int i) const { return 0.; }
+    virtual RObjVecNum to_vec(int repetitions) const = 0;
 };
 
 //! Data container holding a single integer number.
@@ -59,7 +59,6 @@ class CObjInt : public CObjNum
 public:
     int val; //!< Scalar value.
     CObjInt(int _val) : CObjNum(), val(_val) {}
-    // PObj clone() const { return PObjInt( new CObjInt( *this ) ); }
     inline bool has_err() const { return false; }
     inline char base_type() const { return 'i'; }
     string result_info() const { return "CObjInt(" + S(val) + ")"; }
@@ -69,6 +68,7 @@ public:
     inline int to_i(int i) const { return val; }
     string to_s(int maxlen = 12, int minlen = 1, int prec = 6) const;
     inline bool to_b() const { return val; }
+    RObjVecNum to_vec(int repetitions) const final;
 };
 
 //! Data container holding a single floating-point number.
@@ -78,7 +78,6 @@ class CObjDbl : public CObjNum
 public:
     double val; //!< Scalar value.
     CObjDbl(double _val = NAN) : CObjNum(), val(_val) {}
-    // PObj clone() const { return PObjDbl( new CObjDbl( *this ) ); }
     inline bool has_err() const { return false; }
     inline char base_type() const { return 'd'; }
     string result_info() const;
@@ -86,17 +85,16 @@ public:
     inline double to_r(int i) const { return val; }
     string to_s(int maxlen = 12, int minlen = 1, int prec = 6) const;
     bool to_b() const { return val; }
+    virtual RObjVecNum to_vec(int repetitions) const;
 };
 
 //! Data container holding a single floating-point number with its error bar.
-//  STILL UNUSED!
 
 class CObjEnu : public CObjDbl
 {
 public:
     double err; //!< Error of scalar value.
     CObjEnu(double _val = NAN, double _err = NAN) : CObjDbl(_val), err(_err) {}
-    // PObj clone() const { return PObjEnu( new CObjEnu( *this ) ); }
     inline bool has_err() const { return true; }
     inline char base_type() const { return 'e'; }
     string result_info() const;
@@ -106,6 +104,7 @@ public:
     inline double to_dr(int i) const { return err; }
     string to_s(int maxlen = 12, int minlen = 1, int prec = 6) const;
     bool to_b() const { return val; }
+    RObjVecNum to_vec(int repetitions) const final;
 };
 
 //! Data container holding a string.
@@ -115,7 +114,6 @@ class CObjStr : public CObj
 public:
     string val;
     CObjStr(string _val) : CObj(), val(_val) {}
-    // PObj clone() const { return PObjStr( new CObjStr( *this ) ); }
     bool is_vec() const { return false; }
     bool has_err() const { return false; }
     char base_type() const { return 's'; }
@@ -150,6 +148,7 @@ public:
     inline string result_info() const { return to_s(); }
     inline RObj to_obj(int i) const { return v[i]; }
     string to_s(int maxlen = 12, int minlen = 1, int prec = 6) const;
+    vector<double> to_rvec() const;
     RObj to_vecnum() const;
 };
 
@@ -169,10 +168,9 @@ class CObjVecInt : public CObjVecNum
 {
 public:
     vector<int> v; //!< The data.
-    CObjVecInt(int n = 0) : CObjVecNum(), v(n, -1) {}
+    CObjVecInt(int n=0, int val=0) : CObjVecNum(), v(n, val) {}
     CObjVecInt(const vector<int>& _v) : CObjVecNum(), v(_v) {}
     inline int size() const { return v.size(); }
-    // PObj clone() const { return PObjVecInt( new CObjVecInt( *this ) ); }
     bool has_err() const { return false; }
     char base_type() const { return 'i'; }
     string result_info() const;
@@ -191,7 +189,6 @@ public:
     CObjVecDbl(int n = 0, double val = NAN) : CObjVecNum(), v(n, val) {}
     CObjVecDbl(const vector<double>& _v) : CObjVecNum(), v(_v) {}
     inline int size() const { return v.size(); }
-    // PObj clone() const { return PObjVecDbl( new CObjVecDbl( *this ) ); }
     bool has_err() const { return false; }
     char base_type() const { return 'd'; }
     string result_info() const;
@@ -209,7 +206,6 @@ public:
     CObjVecEnu(int n = 0) : CObjVecDbl(n), dv(n, NAN) {}
     CObjVecEnu(const vector<double>& _v, const vector<double>& _dv) : CObjVecDbl(_v), dv(_dv) {}
     inline int size() const { return v.size(); }
-    // PObj clone() const { return PObjVecEnu( new CObjVecEnu( *this ) ); }
     bool has_err() const { return true; }
     char base_type() const { return 'e'; }
     string result_info() const;
diff --git a/pub/lib/olf.cpp b/pub/lib/olf.cpp
index 23008a1d8dfe6e8472869dd6d5aa16966c785a72..1a2c7a0a64a28ddbd3c450d5b897a9c3fb1ff453 100644
--- a/pub/lib/olf.cpp
+++ b/pub/lib/olf.cpp
@@ -102,6 +102,14 @@ void COlo::check_integrity() const
 
 RObj COlo::z(int j, int iz) const { return V[j]->z[iz]; }
 
+//! Return vector of iz-th z-variables.
+
+RObjVecObj COlo::zvec(int iz) const {
+    PObjVecObj ret(new CObjVecObj(nJ()));
+    for (size_t j=0; j<nJ(); ++j)
+        ret->v[j] = V[j]->z[iz];
+    return ret;
+}
 
 //**************************************************************************************************
 //*  COld/COlc (member functions that are similar for both classes)
@@ -127,8 +135,8 @@ void COlc::copy_meta_C_from_other(const COlc* other)
     kd = other->kd;
     weighing = other->weighing;
     plot_to_grid = other->plot_to_grid;
-    range_expr = other->range_expr;
-    range_T = other->range_T;
+    prange_expr = other->prange_expr;
+    prange_T = other->prange_T;
     chi2 = other->chi2;
 }
 
@@ -375,11 +383,13 @@ int COld::nPts() const
 
 //! Returns true if all data points have nonzero dy.
 
-bool COld::has_nonzero_dy() const
+bool COld::dy_are_all_nonzero() const
 {
-    return std::all_of(V.cbegin(), V.cend(), [](const PSlice& s) {
-        return dynamic_cast<const CSpec*>(s.get())->has_nonzero_dy();
-    });
+    for (int j = 0; j < nJ(); ++j) {
+         if (!VS(j)->dy_are_all_nonzero())
+            return false;
+    }
+    return true;
 }
 
 //**************************************************************************************************
@@ -637,14 +647,35 @@ RObjVec COlc::eval_curve(const vector<double>& vt, int k, int j, bool want_error
 
 RObj COlc::eval_curve_scalar(double arg, int k, int j, bool want_error) const
 {
-    vector<double> vt(1, arg);
-    RObjVec cu = eval_curve(vt, k, j, want_error);
+    RObjVec cu = eval_curve({arg}, k, j, want_error);
     if (cu->size() != 1)
         throw "BUG: vector has " + S(cu->size()) + " elements while exactly one was expected";
     return cu->to_obj(0);
 }
 
 
+//! Vectorial evaluation of a curve's prange given by an expression tree.
+
+RObjVecInt COlc::eval_prange(const vector<double>& vt, int k, int j) const
+{
+    if (!prange_T)
+        return RObjVecInt( new CObjVecInt(vt.size(), 1) );
+    CContext ctx(k, j);
+    ctx.want_error = false;
+    RObj ret;
+    if (!prange_T->has_dummy()) { // curve does not depend on t
+        ret = prange_T->tree_val(ctx);
+    } else {
+        ctx.request_VT(&vt);
+        ret = prange_T->tree_val(ctx);
+    }
+    RObjVecInt ret2 = PCAST<const CObjVecInt>(ret);
+    if (!ret2)
+        throw S("BUG in eval_prange_expr: result is not an integer vector");
+    return ret2;
+}
+
+
 //**************************************************************************************************
 //*  class COlc - inspect
 //**************************************************************************************************
@@ -667,6 +698,8 @@ vector<string> COlc::info_settings() const
         txt += "conv file: " + S(kconv) + ", ";
     txt += "weighing: " + weight_str();
     ret.push_back(txt);
+    if (prange_expr!="")
+        ret.push_back("plot range: " + prange_expr);
     if (chi2 > 0)
         ret.push_back("global fit result: " + S(chi2));
     return ret;
diff --git a/pub/lib/olf.hpp b/pub/lib/olf.hpp
index e343cb38ed3a9ddf9a61dbd503c0ee88489a7cef..6fa957fba33e896ada1c9197aa4e8d0a55e94a66 100644
--- a/pub/lib/olf.hpp
+++ b/pub/lib/olf.hpp
@@ -47,6 +47,7 @@ public:
     int nJ() const { return V.size(); }
     int nZ() const { return ZCo.size(); }
     RObj z(int j, int iz) const;
+    RObjVecObj zvec(int iz) const;
     virtual PSlice copy_slice(int j) const = 0;
     virtual POlo new_POlo() const = 0;
     virtual CCoord coord(const CGenus& genus) const = 0;
@@ -80,7 +81,7 @@ public:
 
     int nPts(int j) const;
     int nPts() const; // 0 unless all spectra j have same nPts(j)
-    bool has_nonzero_dy() const;
+    bool dy_are_all_nonzero() const;
     virtual string type() const { return "data"; }
 };
 
@@ -118,8 +119,8 @@ public:
     static string wgtNames[];
     static TWgt name2wgt(string name);
     bool plot_to_grid; ///< Use grid from file 'kd' ?
-    string range_expr; ///< Restricts points to be fitted.
-    RNode range_T; ///< Parsed range_expr.
+    string prange_expr; ///< Restricts points to be plotted.
+    RNode prange_T; ///< Parsed range_expr.
     double chi2; ///< Global chi^2
 
     COlc()
@@ -130,7 +131,7 @@ public:
         , kd(-1)
         , weighing(_VAR)
         , plot_to_grid(false)
-        , range_expr("")
+        , prange_expr("")
         , chi2(0)
     {
     }
@@ -161,6 +162,7 @@ public:
     void curve_query(const string& quest);
     RObjVec eval_curve(const vector<double>& vt, int k, int j, bool want_error) const;
     RObj eval_curve_scalar(double arg, int k, int j, bool want_error) const;
+    RObjVecInt eval_prange(const vector<double>& vt, int k, int j) const;
     virtual string type() const { return "curve"; }
 };
 
diff --git a/pub/lib/opr.cpp b/pub/lib/opr.cpp
index fabae83fd1dc0b20fac1f8f96b753579715bf4ff..0b325e7c0f530b079dd0588388151e1b2557fc3e 100644
--- a/pub/lib/opr.cpp
+++ b/pub/lib/opr.cpp
@@ -283,9 +283,9 @@ void NOperate::Integral()
             else
                 fout = POld((dynamic_cast<const COld*>(fin))->new_POld());
             fout->log_action("oi " + expr);
-            fout->ZCo.pop_back();
             fout->xco = fin->ZCo.back();
             fout->yco = T->node_coord(k);
+            fout->ZCo.pop_back();
             sout = PSpec(new CSpec);
             sout->z = fin->V[0]->z;
             sout->z.pop_back();
@@ -300,14 +300,14 @@ void NOperate::Integral()
                 cout << "result: " << res->to_s() << "\n";
                 continue;
             }
-            xval = fin->V[j]->z[nz - 1]->to_r();
+            xval = fin->V[j]->z[nz-1]->to_r();
             sout->push_xyd(xval, res->to_r(), res->to_dr());
-            if (nz >= 2) { // new spectrum if jump in other z values
-                double zval = fin->V[j]->z[nz - 2]->to_r();
-                if (j + 1 < fin->nJ() && fin->V[j + 1]->z[nz - 2]->to_r() != zval) {
+            if (nz > 1) { // new spectrum if jump in other z values
+                if (j+1 < fin->nJ()
+		   && fin->V[j+1]->z[nz-2]->to_r() != fin->V[j]->z[nz-2]->to_r()) {
                     fout->V.push_back(move(sout));
                     sout = PSpec(new CSpec);
-                    sout->z = fin->V[j + 1]->z;
+                    sout->z = fin->V[j+1]->z;
                     sout->z.pop_back();
                 }
             }
@@ -350,8 +350,6 @@ void NOperate::IntXY(string mode)
         if (icold < 0)
             return;
     }
-    xco = CCoord("x", "");
-    yco = CCoord("y", "");
 
     while (const COld* fin = fiter.nextD()) {
         int nz = fin->ZCo.size();
@@ -362,10 +360,15 @@ void NOperate::IntXY(string mode)
             lin += " " + S(icold);
         fout->log_action(lin);
 
-        fout->xco = xco;
-        fout->yco = yco;
+        fout->xco = CCoord("x", "");
+        fout->yco = CCoord("y", "");
+        if (nz)
+            fout->ZCo.pop_back();
 
         PSpec sout(new CSpec);
+        sout->z = fin->V[0]->z;
+        if (nz)
+            sout->z.pop_back();
 
         for (int j = 0; j < fin->nJ(); j++) {
             int n = fin->nPts(j);
@@ -376,11 +379,14 @@ void NOperate::IntXY(string mode)
             else
                 sout->push_xy(fin->VS(j)->y[icolx], fin->VS(j)->y[icoly]);
             sout->z = fin->VS(j)->z;
-            if (nz > 2) { // new spectrum if jump in other z value
-                if (j + 1 < fin->nJ()
-                    && fin->V[j + 1]->z[nz - 2]->to_r() != fin->V[j]->z[nz - 2]->to_r()) {
+            if (nz > 1) { // new spectrum if jump in other z value
+                if (j+1 < fin->nJ()
+                    && fin->V[j+1]->z[nz-2]->to_r() != fin->V[j]->z[nz-2]->to_r()) {
                     fout->V.push_back(move(sout));
                     sout = PSpec(new CSpec);
+                    sout->z = fin->V[j+1]->z;
+                    if (nz)
+                        sout->z.pop_back();
                 }
             }
         }
@@ -389,7 +395,6 @@ void NOperate::IntXY(string mode)
     }
 }
 
-
 //**************************************************************************************************
 //*  functional operations
 //**************************************************************************************************
diff --git a/pub/lib/plot.cpp b/pub/lib/plot.cpp
index 098bca7a635d9ecefd2d9d18d08cc4c4dc64f2e8..bbd42fe7065af275e01736b45f50ca2792c70214 100644
--- a/pub/lib/plot.cpp
+++ b/pub/lib/plot.cpp
@@ -7,502 +7,608 @@
 //! \file  plot.cpp
 //! \brief NPlot: plot data and curves.
 
-#include "defs.hpp"
+#include <cmath>
+#include <algorithm>
+#include <boost/format.hpp>
 
+#include "defs.hpp"
 
-#include "../plot/dualplot.hpp"
 #include "../trivia/vector_ops.hpp"
+#include "../trivia/file_ops.hpp" // TODO rm file creation from plot2D
+#include "../plot/dualplot.hpp"
 
+#include "config.hpp"
 #include "curve.hpp"
 #include "fsel.hpp"
 #include "jsel.hpp"
 #include "loop.hpp"
+#include "expr.hpp"
 #include "mem.hpp"
 #include "obj.hpp"
 #include "olf.hpp"
 #include "plot.hpp"
 #include "slice.hpp"
+#include "variables.hpp"
 
+using boost::format;
+
+namespace {
+    void determine_Xrange(CPlot* plot, vector<int>& JSel);
+    void determine_Yrange(CPlot* plot, vector<int>& JSel);
+    int plot_data(CPlot* plot, const COld* fd, int k, int j, int pstyle);
+    int plot_curve_convolved(CPlot* plot, const COlc* fc, int k, int j, int cstyle);
+    int plot_curve_to_grid(CPlot* plot, const COlc* fc, int k, int j, int cstyle);
+    int plot_curve_equidist(CPlot* plot, const COlc* fc, int k, int j, int cstyle);
+    int plot_curve_refine(CPlot* plot, const COlc* fc, int k, int j, int cstyle);
+    void plot1D(class CPlot* plot, bool add, const string& mode);
+    void plot2D(class CPlot* plot);
 
 //**************************************************************************************************
 //*  Subroutines: determine data ranges
 //**************************************************************************************************
 
-
 //! Loop over selected data files to determine x range.
 
-void determine_Xrange(CPlot* plot, vector<int>& JSel)
-{
-    double inf, sup;
-    FileIterator fiter(SFSel::instance()->selD());
-    const vector<double>* vx;
-    bool first = true;
-    while (const COld* fd = fiter.nextD()) {
-        // JSel->evaluate( 0, fd->nJ()-1 );
-        for (int iv = 0; iv < JSel.size(); ++iv) {
-            vx = &(fd->VS(JSel[iv])->x);
-            for (int i = 0; i < vx->size(); ++i) {
-                if (plot->X.logflag && (*vx)[i] <= 0)
-                    continue;
-                if (first) {
-                    inf = (*vx)[i];
-                    sup = (*vx)[i];
-                    first = false;
-                } else {
-                    if ((*vx)[i] < inf)
+    void determine_Xrange(CPlot* plot, vector<int>& JSel)
+    {
+        double inf, sup;
+        FileIterator fiter(SFSel::instance()->selD());
+        const vector<double>* vx;
+        bool first = true;
+        while (const COld* fd = fiter.nextD()) {
+            // JSel->evaluate( 0, fd->nJ()-1 );
+            for (int iv = 0; iv < JSel.size(); ++iv) {
+                vx = &(fd->VS(JSel[iv])->x);
+                for (int i = 0; i < vx->size(); ++i) {
+                    if (plot->X.logflag && (*vx)[i] <= 0)
+                        continue;
+                    if (first) {
                         inf = (*vx)[i];
-                    if ((*vx)[i] > sup)
                         sup = (*vx)[i];
+                        first = false;
+                    } else {
+                        if ((*vx)[i] < inf)
+                            inf = (*vx)[i];
+                        if ((*vx)[i] > sup)
+                            sup = (*vx)[i];
+                    }
                 }
             }
         }
+        if (first)
+            throw S("x range is empty");
+        plot->X.set_rounded_limits(inf, sup);
     }
-    if (first)
-        throw S("x range is empty");
-    plot->X.set_rounded_limits(inf, sup);
-}
 
 
 //! Loop over selected files to determine y range for current x range.
 
-void determine_Yrange(CPlot* plot, vector<int>& JSel)
-{
-    double inf = INFINITY, sup = -INFINITY;
-    FileIterator fiter(SFSel::instance()->sel());
-    while (const COlo* f = fiter.next()) {
-        int k = fiter.k();
-        const COlc* fc = dynamic_cast<const COlc*>(f);
-        if (fc && fc->kconv != -1)
-            continue;
-        const COld* fd = dynamic_cast<const COld*>(f);
-        // JSel->evaluate( 0, f->nJ()-1 );
-        for (int iv = 0; iv < JSel.size(); ++iv) {
-            int j = JSel[iv];
-            CSpec* s;
-            if (fd) {
-                s = fd->VS(j);
-            } else {
-                PSpec tmp(new CSpec);
-                s = tmp.get();
-                plot->X.set_xgrid(s->x, 97);
-                RObjVec cu = fc->eval_curve(s->x, k, j, false);
-                s->y.resize(s->x.size());
-                for (int i = 0; i < s->size(); ++i)
-                    s->y[i] = cu->to_r(i);
-            }
-            for (int i = 0; i < s->size(); i++) {
-                if (!plot->X.contains(s->x[i]))
-                    continue;
-                if (plot->Y.logflag && s->y[i] <= 0)
-                    continue;
-                if (s->y[i] < inf)
-                    inf = s->y[i];
-                if (s->y[i] > sup)
-                    sup = s->y[i];
+    void determine_Yrange(CPlot* plot, vector<int>& JSel)
+    {
+        double inf = INFINITY, sup = -INFINITY;
+        FileIterator fiter(SFSel::instance()->sel());
+        while (const COlo* f = fiter.next()) {
+            int k = fiter.k();
+            const COlc* fc = dynamic_cast<const COlc*>(f);
+            if (fc && fc->kconv != -1)
+                continue;
+            const COld* fd = dynamic_cast<const COld*>(f);
+            // JSel->evaluate( 0, f->nJ()-1 );
+            for (int iv = 0; iv < JSel.size(); ++iv) {
+                int j = JSel[iv];
+                CSpec* s;
+                if (fd) {
+                    s = fd->VS(j);
+                } else {
+                    PSpec tmp(new CSpec);
+                    s = tmp.get();
+                    plot->X.set_xgrid(s->x, 97);
+                    RObjVec cu = fc->eval_curve(s->x, k, j, false);
+                    s->y.resize(s->x.size());
+                    for (int i = 0; i < s->size(); ++i)
+                        s->y[i] = cu->to_r(i);
+                }
+                for (int i = 0; i < s->size(); i++) {
+                    if (!plot->X.contains(s->x[i]))
+                        continue;
+                    if (plot->Y.logflag && s->y[i] <= 0)
+                        continue;
+                    if (s->y[i] < inf)
+                        inf = s->y[i];
+                    if (s->y[i] > sup)
+                        sup = s->y[i];
+                }
             }
         }
+        if (inf == INFINITY || sup == -INFINITY)
+            throw S("y range is empty");
+        plot->Y.set_rounded_limits(inf, sup);
     }
-    if (inf == INFINITY || sup == -INFINITY)
-        throw S("y range is empty");
-    plot->Y.set_rounded_limits(inf, sup);
-}
 
 
 //**************************************************************************************************
 //*  Subroutines: plot one scan
 //**************************************************************************************************
 
-
-//! Plot scan j of data file fd; return number of points plotted.
-
-int plot_data(CPlot* plot, const COld* fd, int k, int j, int pstyle)
-{
-    const CSpec* s = fd->VS(j);
-    int n = s->x.size();
-    if (n != s->y.size())
-        throw S("BUG: plot: x.size<>y.size");
-    // Filter: x,y -> xp,yp if inside frame
-    int np = 0, nxl = 0, nxh = 0, nyl = 0, nyh = 0;
-    vector<double> xp, yp, dyp;
-    for (int i = 0; i < n; i++) {
-        double x = s->x[i];
-        if (!plot->X.contains(x)) {
-            if (x <= plot->X.inf) {
-                x = plot->X.inf;
-                nxl++;
+//! Plot slice j of data file fd; return number of points plotted.
+
+    int plot_data(CPlot* plot, const COld* fd, int k, int j, int pstyle)
+    {
+        const CSpec* s = fd->VS(j);
+        int n = s->x.size();
+        if (n != s->y.size())
+            throw S("BUG: plot: x.size<>y.size");
+        // Filter: x,y -> xp,yp if inside frame
+        int np = 0, nxl = 0, nxh = 0, nyl = 0, nyh = 0;
+        vector<double> xp, yp, dyp;
+        for (int i = 0; i < n; i++) {
+            double x = s->x[i];
+            if (!plot->X.contains(x)) {
+                if (x <= plot->X.inf) {
+                    x = plot->X.inf;
+                    nxl++;
+                }
+                if (x >= plot->X.sup) {
+                    x = plot->X.sup;
+                    nxh++;
+                }
+                if (!plot->X.force)
+                    continue;
             }
-            if (x >= plot->X.sup) {
-                x = plot->X.sup;
-                nxh++;
+            double y = s->y[i];
+            if (!plot->Y.contains(y)) {
+                if (y <= plot->Y.inf) {
+                    y = plot->Y.inf;
+                    nyl++;
+                }
+                if (y >= plot->Y.sup) {
+                    y = plot->Y.sup;
+                    nyh++;
+                }
+                if (!plot->Y.force)
+                    continue;
             }
-            if (!plot->X.force)
-                continue;
+            if (np == plot->maxpoints && np < n)
+                cout << "reached maxpoints at " << s->x[i] << "\n";
+            xp.push_back(x);
+            yp.push_back(y);
+            if (s->has_dy())
+                dyp.push_back(s->dy[i]);
+            np = xp.size();
+            if (np > plot->maxpoints) // continue in large steps
+                i += plot->maxpoints;
         }
-        double y = s->y[i];
-        if (!plot->Y.contains(y)) {
-            if (y <= plot->Y.inf) {
-                y = plot->Y.inf;
-                nyl++;
-            }
-            if (y >= plot->Y.sup) {
-                y = plot->Y.sup;
-                nyh++;
-            }
-            if (!plot->Y.force)
-                continue;
+        if (np == 0) {
+            cout << "file " << k << " spec " << j << " all " << n << " points outside plot range:\n";
+            if (nxl)
+                cout << "  " << nxl << " points < xmin\n";
+            if (nxh)
+                cout << "  " << nxh << " points > xmax\n";
+            if (nyl)
+                cout << "  " << nyl << " points < ymin\n";
+            if (nyh)
+                cout << "  " << nyh << " points > ymax\n";
+        } else {
+            plot->add_spec(
+                false, true, pstyle, xp, yp, dyp, fd->V[j]->z_str(), fd->xco.str_std(),
+                fd->yco.str_std(), "data file " + S(k) + " spectrum " + S(j));
         }
-        if (np == plot->maxpoints && np < n)
-            cout << "reached maxpoints at " << s->x[i] << "\n";
-        xp.push_back(x);
-        yp.push_back(y);
-        if (s->has_dy())
-            dyp.push_back(s->dy[i]);
-        np = xp.size();
-        if (np > plot->maxpoints) // continue in large steps
-            i += plot->maxpoints;
+        return np;
     }
-    if (np == 0) {
-        cout << "file " << k << " spec " << j << " all " << n << " points outside plot range:\n";
-        if (nxl)
-            cout << "  " << nxl << " points < xmin\n";
-        if (nxh)
-            cout << "  " << nxh << " points > xmax\n";
-        if (nyl)
-            cout << "  " << nyl << " points < ymin\n";
-        if (nyh)
-            cout << "  " << nyh << " points > ymax\n";
-    } else {
-        plot->add_spec(
-            false, true, pstyle, xp, yp, dyp, fd->V[j]->z_str(), fd->xco.str_std(),
-            fd->yco.str_std(), "data file " + S(k) + " spectrum " + S(j));
-    }
-    return np;
-}
 
 
-//! Plot scan j of convolved curve file fc; return number of points plotted.
+//! Plot slice j of convolved curve file fc; return number of points plotted.
 
-int plot_curve_convolved(CPlot* plot, const COlc* fc, int k, int j, int cstyle)
-{
-    vector<double> novec;
-    int kconv, jconv;
-    const CSpec* sconv;
-    NCurveFile::get_conv(&sconv, &kconv, &jconv, k, j);
-    vector<double> xp;
-    for (int i = 0; i < sconv->size(); ++i) {
-        double x = sconv->x[i];
-        if (plot->X.contains(x))
-            xp.push_back(x);
-    }
-    RObjVec cu = fc->eval_curve(xp, k, j, false);
-    vector<double> xo, yo;
-    for (int i = 0; i < xp.size(); ++i) {
-        double yp = cu->to_r(i);
-        if (!(plot->X.contains(xp[i]) && plot->Y.contains(yp)))
-            continue;
-        xo.push_back(xp[i]);
-        yo.push_back(yp);
-    }
-    if (xo.size() == 0) {
-        cout << "curve k=" << S(k) << ", j=" << S(j) << " has no points in plot window\n";
+    int plot_curve_convolved(CPlot* plot, const COlc* fc, int k, int j, int cstyle)
+    {
+        vector<double> novec;
+        int kconv, jconv;
+        const CSpec* sconv;
+        NCurveFile::get_conv(&sconv, &kconv, &jconv, k, j);
+        vector<double> xp;
+        for (int i = 0; i < sconv->size(); ++i) {
+            double x = sconv->x[i];
+            if (plot->X.contains(x))
+                xp.push_back(x);
+        }
+        RObjVec cu = fc->eval_curve(xp, k, j, false);
+        vector<double> xo, yo;
+        for (int i = 0; i < xp.size(); ++i) {
+            double yp = cu->to_r(i);
+            if (!(plot->X.contains(xp[i]) && plot->Y.contains(yp)))
+                continue;
+            xo.push_back(xp[i]);
+            yo.push_back(yp);
+        }
+        if (xo.size() == 0) {
+            cout << "curve k=" << S(k) << ", j=" << S(j) << " has no points in plot window\n";
+        }
+        plot->add_spec(
+            true, true, cstyle, xo, yo, novec, fc->V[j]->z_str(), fc->xco.str_std(), fc->yco.str_std(),
+            "curve file " + S(k) + " spectrum " + S(j));
+        return xo.size();
     }
-    plot->add_spec(
-        true, true, cstyle, xo, yo, novec, fc->V[j]->z_str(), fc->xco.str_std(), fc->yco.str_std(),
-        "curve file " + S(k) + " spectrum " + S(j));
-    return xo.size();
-}
 
-//! Plot scan j of curve file fc, using grid from file kd.
-
-int plot_curve_to_grid(CPlot* plot, const COlc* fc, int k, int j, int cstyle)
-{
-    if (fc->kd == -1)
-        throw S("data reference not set, incompatible with cg+");
-    const COld* fd = SMem::instance()->mem_get_D(fc->kd);
-    if (!fd)
-        throw S("data reference not found");
-    if (j >= fd->nJ())
-        throw S("number of spectra does not match");
-    vector<double>* xc = &(fd->VS(j)->x);
-    vector<double> novec, xp, yp;
-    RObjVec cu = fc->eval_curve(*xc, k, j, false);
-    for (int i = 0; i < xc->size(); ++i) {
-        double yc = cu->to_r(i);
-        if (plot->X.contains((*xc)[i]) && plot->Y.contains(yc)) {
-            xp.push_back((*xc)[i]);
-            yp.push_back(yc);
+//! Plot slice j of curve file fc, using grid from file kd.
+
+    int plot_curve_to_grid(CPlot* plot, const COlc* fc, int k, int j, int cstyle)
+    {
+        if (fc->kd == -1)
+            throw S("data reference not set, incompatible with cg+");
+        const COld* fd = SMem::instance()->mem_get_D(fc->kd);
+        if (!fd)
+            throw S("data reference not found");
+        if (j >= fd->nJ())
+            throw S("number of spectra does not match");
+        vector<double>* xc = &(fd->VS(j)->x);
+        vector<double> novec, xp, yp;
+        RObjVec cu = fc->eval_curve(*xc, k, j, false);
+        for (int i = 0; i < xc->size(); ++i) {
+            double yc = cu->to_r(i);
+            if (plot->X.contains((*xc)[i]) && plot->Y.contains(yc)) {
+                xp.push_back((*xc)[i]);
+                yp.push_back(yc);
+            }
         }
+        plot->add_spec(
+            true, true, cstyle, xp, yp, novec, fc->V[j]->z_str(), fc->xco.str_std(), fc->yco.str_std(),
+            "curve file " + S(k) + " spectrum " + S(j));
+        return xp.size();
     }
-    plot->add_spec(
-        true, true, cstyle, xp, yp, novec, fc->V[j]->z_str(), fc->xco.str_std(), fc->yco.str_std(),
-        "curve file " + S(k) + " spectrum " + S(j));
-    return xp.size();
-}
 
 
-//! Plot scan j of non-convolved curve file fc on equidistant grid; return number of points plotted.
+//! Plot slice j of non-convolved curve file fc on equidistant grid; return number of points plotted.
 
-int plot_curve_equidist(CPlot* plot, const COlc* fc, int k, int j, int cstyle)
-{
-    vector<double> novec;
-    // equidistant grid
-
-    int npts = plot->equipoints;
-    vector<double> xc, xp, yp;
-    plot->X.set_xgrid(xc, npts);
-    RObjVec cu = fc->eval_curve(xc, k, j, false);
-    for (int i = 0; i < npts; ++i) {
-        double yc = cu->to_r(i);
-        if (plot->X.contains(xc[i]) && plot->Y.contains(yc)) {
-            xp.push_back(xc[i]);
-            yp.push_back(yc);
+    int plot_curve_equidist(CPlot* plot, const COlc* fc, int k, int j, int cstyle)
+    {
+        vector<double> novec;
+        // equidistant grid
+
+        int npts = plot->equipoints;
+        vector<double> xc, xp, yp;
+        plot->X.set_xgrid(xc, npts);
+        RObjVec cu = fc->eval_curve(xc, k, j, false);
+        for (int i = 0; i < npts; ++i) {
+            double yc = cu->to_r(i);
+            if (plot->X.contains(xc[i]) && plot->Y.contains(yc)) {
+                xp.push_back(xc[i]);
+                yp.push_back(yc);
+            }
         }
+        plot->add_spec(
+            true, true, cstyle, xp, yp, novec, fc->V[j]->z_str(), fc->xco.str_std(), fc->yco.str_std(),
+            "curve file " + S(k) + " spectrum " + S(j));
+        return xp.size();
     }
-    plot->add_spec(
-        true, true, cstyle, xp, yp, novec, fc->V[j]->z_str(), fc->xco.str_std(), fc->yco.str_std(),
-        "curve file " + S(k) + " spectrum " + S(j));
-    return xp.size();
-}
-
-//! Plots scan j of non-convolved curve file fc, refining the grid where necessary; return number of
-//! points plotted.
 
-int plot_curve_refine(CPlot* plot, const COlc* fc, int k, int j, int cstyle)
-{
-    // refinement cares to:
-    // - stop/start line when leaving/reentering/crossing(TODO) the frame
-    // - TODO interpolate when crossing the horizontal border
-    // - interpolate at discontinuities
-
-    vector<double> xc, yc, xn, yn;
-    vector<double> novec;
-
-    // start with equidistant grid:
-    int npts = plot->equipoints;
-    plot->X.set_xgrid(xc, npts);
-
-    // refinement loop:
-    for (int iref = 0;; ++iref) {
-        if (!xc.size()) {
-            if (!iref)
-                throw S("BUG: plot_curve_refine called with xc.size()=0");
-            break; // regular exit
-        }
-        // evaluate curve for grid xc:
-        RObjVecDbl cu = PCAST<const CObjVecDbl>(fc->eval_curve(xc, k, j, false));
-        for (int i = 0; i < xc.size(); ++i)
-            yc = cu->v;
-
-        // merge xc,yc and xn,yn:
-        if (iref == 0) {
-            xn = xc;
-            yn = yc;
-        } else {
-            vector<double> xa, ya;
-            int ic = 0, in = 0;
-            for (; ic < xc.size() && in < xn.size();) {
-                if (plot->X.close_enough(xc[ic], xn[ic], 1e-7)) {
-                    ++in; // skip new point
-                } else if (xc[ic] < xn[in]) {
-                    xa.push_back(xc[ic]);
-                    ya.push_back(yc[ic]);
-                    ++ic;
-                } else {
-                    xa.push_back(xn[in]);
-                    ya.push_back(yn[in]);
-                    ++in;
+//! Plots slice j of non-convolved curve file fc, refining the grid where necessary;
+//! return number of points plotted.
+
+    int plot_curve_refine(CPlot* plot, const COlc* fc, int k, int j, int cstyle)
+    {
+        class CP2 {
+        public:
+            double x;
+            double y;
+            CP2 operator-(const CP2 other) {
+                return { x-other.x, y-other.y }; };
+            double operator*(const CP2 other) {
+                return x*other.x + y*other.y; };
+        };
+
+        class CPt {
+        public:
+            double xd; // data point
+            double yd;
+            int code; // -1=nan 0=valid, 1=below, 2=above, 3=off_range
+            CP2 P; // plot point
+        };
+
+        auto x2p = [&](const vector<double>& x) -> vector<CPt>
+            {
+                vector<double> y = PCAST<const CObjVecDbl>(fc->eval_curve(x, k, j, false))->v;
+                vector<int> inRange = fc->eval_prange(x, k, j)->v;
+                vector<CPt> ret(x.size());
+                for (size_t i=0; i<x.size(); ++i) {
+                    double xp = plot->X.pc(x[i]);
+                    if (std::isnan(y[i]))
+                        ret[i] = {x[i], y[i], 1, {xp, NAN}};
+                    else if (y[i]<plot->Y.inf)
+                        ret[i] = {x[i], y[i], 1, {xp, NAN}};
+                    else if (y[i]>plot->Y.sup)
+                        ret[i] = {x[i], y[i], 2, {xp, NAN}};
+                    else if (!inRange[i])
+                        ret[i] = {x[i], y[i], 3, {xp, NAN}};
+                    else
+                        ret[i] = {x[i], y[i], 0, {xp, plot->Y.pc(y[i])}};
                 }
-            }
-            for (; ic < xc.size(); ++ic) {
-                xa.push_back(xc[ic]);
-                ya.push_back(yc[ic]);
-            }
-            for (; in < xn.size(); ++in) {
-                xa.push_back(xn[in]);
-                ya.push_back(yn[in]);
-            }
-            xn = xa;
-            yn = ya;
-        }
-        if (iref >= 10 || xn.size() >= plot->maxpoints)
-            break; // alternate exit: too many refinements or too many points
-
-        // eliminate points outside y range (except border points):
-        vector<double> xa, ya;
-        xa.push_back(xn[0]);
-        ya.push_back(yn[0]);
-        for (int i = 1; i < xn.size() - 1; ++i) {
-        new_segment:
-            xa.push_back(xn[i]);
-            ya.push_back(yn[i]);
-            if (!plot->Y.contains(yn[i])) {
-                for (int ii = i + 1; ii < xn.size() - 1; ++ii) {
-                    if (plot->Y.contains(yn[ii])) {
-                        if (ii - 1 > i) {
-                            xa.push_back(xn[ii - 1]);
-                            ya.push_back(yn[ii - 1]);
+                return ret;
+            };
+
+        auto pt_order = [](const CPt a, const CPt b) -> bool
+            { return a.xd<=b.xd; };
+
+        auto nonlinearity = [](const vector<CPt>::iterator b) -> double
+            {
+                auto a = b-1;
+                auto c = b+1;
+                CP2 BA = a->P-b->P;
+                CP2 AC = c->P-a->P;
+                // squared  deviation from linearity:
+                return BA*BA - pow(BA*AC,2)/(AC*AC);
+            };
+
+        // start with equidistant grid:
+        vector<double> xn;
+        plot->X.set_xgrid(xn, plot->equipoints);
+
+        // refinement loop:
+        vector<CPt> pp;
+        for (int iref=0; iref<49 && pp.size() < plot->maxpoints; ++iref) {
+            vector<CPt> pn = x2p(xn);
+            pp = triv::merge_sorted(pp, pn, pt_order);
+            xn.clear();
+
+            for (auto b = pp.begin()+1; b<pp.end(); ++b) {
+                auto a = b-1;
+                if (a->code!=0 || b->code!=0) {
+                    if (a->code!=b->code) {
+                        xn.push_back( (b->xd + a->xd)/2 );
+                    }
+                } else { // valid data
+                    auto c = b+1;
+                    if (c<pp.end() && c->code==0) {
+                        // squared  deviation from linearity:
+                        if ( nonlinearity(b) > 1e-8 ) {
+                            double dx = std::min(b->xd - a->xd, c->xd - b->xd)/2;
+                            xn.push_back( b->xd - dx );
+                            xn.push_back( b->xd + dx );
                         }
-                        i = ii;
-                        goto new_segment;
                     }
                 }
             }
+            if (!xn.size())
+                break;
+            xn = std::vector<double>( xn.begin(), std::unique(xn.begin(), xn.end()) );
         }
-        xa.push_back(xn.back());
-        ya.push_back(yn.back());
-        xn = xa;
-        yn = ya;
-
-        // set additional base points:
-        bool insert_next = false;
-        xc.clear();
-        for (int i = 1; i < xn.size() - 1; ++i) {
-            if (i < xn.size() - 2) {
-                double yi = ((xn[i + 1] - xn[i]) * yn[i - 1] + (xn[i] - xn[i - 1]) * yn[i + 1])
-                    / (xn[i + 1] - xn[i - 1]);
-                if (!plot->Y.close_enough(yn[i], yi, 0.005)) {
-                    xc.push_back((xn[i - 1] + xn[i]) / 2);
-                    insert_next = true;
-                    continue;
-                }
-            }
-            if (insert_next) {
-                xc.push_back((xn[i - 1] + xn[i]) / 2);
-                insert_next = false;
-                continue;
-            }
-            if ((plot->Y.contains(yn[i]) && !plot->Y.contains(yn[i - 1]))
-                || (!plot->Y.contains(yn[i]) && plot->Y.contains(yn[i - 1]))) {
-                xc.push_back((xn[i - 1] + xn[i]) / 2);
-                continue;
+
+        // remove points in straight lines
+        vector<CPt> po;
+        size_t nout = 0;
+        for (int iref=0; iref<49; ++iref) {
+            po.clear();
+            po.push_back( *pp.begin() );
+            bool even = false;
+            for (auto b = pp.begin()+1; b<pp.end()-1; ++b) {
+                if (even || b->code!=(b-1)->code!=0 || b->code!=(b+1)->code!=0
+                    || b->code==0 && nonlinearity(b)>1e-9)
+                    po.push_back(*b);
+                even = !even;
             }
+            po.push_back( *(pp.end()-1) );
+            if (po.size()==nout)
+                break;
+            nout = po.size();
+            pp = po;
         }
-        // temporary check
-        if (xc.size())
-            for (int i = 0; i < xc.size() - 1; ++i)
-                if (xc[i + 1] <= xc[i])
-                    throw "BUG: new base points not sorted at " + S(i) + ": " + S(xc[i]) + " "
-                        + S(xc[i + 1]);
-    }
 
-    // divide into segments and plot:
-    vector<double> xa, ya;
-    bool first_seg = true;
-    npts = 0;
-    for (int i = 0; i < xn.size(); ++i) {
-        if (plot->Y.contains(yn[i])) {
-            xa.push_back(xn[i]);
-            ya.push_back(yn[i]);
+        // divide into segments
+        vector<vector<CPt>> segments;
+        vector<CPt> seg;
+        for (CPt p: po) {
+            if (p.code==0)
+                seg.push_back(p);
+            else if (seg.size()) {
+                segments.push_back(seg);
+                seg.clear();
+            }
         }
-        if (!plot->Y.contains(yn[i]) || i == xn.size() - 1) {
-            npts += xa.size();
-            if (xa.size()) {
-                plot->add_spec(
-                    true, first_seg, cstyle, xa, ya, novec, fc->V[j]->z_str(), fc->xco.str_std(),
-                    fc->yco.str_std(), "curve file " + S(k) + " spectrum " + S(j));
-                xa.clear();
-                ya.clear();
-                first_seg = false;
+        if (seg.size())
+            segments.push_back(seg);
+
+        // plot segments
+        size_t npts = 0;
+        for (size_t is=0; is<segments.size(); ++is) {
+            vector<double> xf, yf;
+            for (CPt p: segments[is]) {
+                xf.push_back(p.xd);
+                yf.push_back(p.yd);
             }
+            plot->add_spec(
+                true, is==0, cstyle, xf, yf, vector<double>(), fc->V[j]->z_str(), fc->xco.str_std(),
+                fc->yco.str_std(), "curve file " + S(k) + " spectrum " + S(j));
+            npts += segments[is].size();
         }
-    }
-    return npts;
-}
 
+        return npts;
+    }
 
 //**************************************************************************************************
-//*  Plot routine is accessible from the main menu
+//*  plot1D
 //**************************************************************************************************
 
-//! Plot set of spectra, or add to open plot.
+    //! Plot set of spectra, or add to open plot.
 
-void NPlot::plot(class CPlot* plot, bool add, const string& mode)
-{
-    FileIterator fiter(SFSel::instance()->sel());
+    void plot1D(class CPlot* plot, bool add, const string& mode)
+    {
+        FileIterator fiter(SFSel::instance()->sel());
 
-    static vector<int> JSel;
-    static int pstyle = 1, cstyle = 1;
-    static string jSel = "";
+        static vector<int> JSel;
+        static int pstyle = 1, cstyle = 1;
+        static string jSel = "";
 
+        if (mode == "ask") {
+            JSelAsk("Plot which spectra", JSel);
+        } else {
+            if (mode == "next") {
+                triv::increment_indices(JSel, +1, SFSel::instance()->nJ_max());
+            } else if (mode == "prev") {
+                triv::increment_indices(JSel, -1, SFSel::instance()->nJ_max());
+            } else
+                throw "unexpected mode " + mode;
+            if (!JSel.size())
+                throw S("no spectra in range");
+            cout << "plotting spectra " << triv::indices_to_s(JSel) << "\n";
+        }
 
-    if (mode == "ask") {
-        JSelAsk("Plot which spectra", JSel);
-    } else {
-        if (mode == "next") {
-            triv::increment_indices(JSel, +1, SFSel::instance()->nJ_max());
-        } else if (mode == "prev") {
-            triv::increment_indices(JSel, -1, SFSel::instance()->nJ_max());
-        } else
-            throw "unexpected mode " + mode;
-        if (!JSel.size())
-            throw S("no spectra in range");
-        cout << "plotting spectra " << triv::indices_to_s(JSel) << "\n";
-    }
+        if (!add) { // prepare frame (ranges, labels)
+            pstyle = 1;
+            cstyle = 1;
+            if (!plot->X.finite())
+                determine_Xrange(plot, JSel);
+            if (!plot->Y.finite())
+                determine_Yrange(plot, JSel);
 
-    if (!add) { // prepare frame (ranges, labels)
-        pstyle = 1;
-        cstyle = 1;
-        if (!plot->X.finite())
-            determine_Xrange(plot, JSel);
-        if (!plot->Y.finite())
-            determine_Yrange(plot, JSel);
+            // build label: (zur Zeit nur vom ersten File; definiere +=)
+            CCoord xCo = SFSel::instance()->sel_first()->xco;
+            CCoord yCo = SFSel::instance()->sel_first()->yco;
 
-        // build label: (zur Zeit nur vom ersten File; definiere +=)
-        CCoord xCo = SFSel::instance()->sel_first()->xco;
-        CCoord yCo = SFSel::instance()->sel_first()->yco;
+            // draw new frame:
+            plot->start_frame1D("Frida version " VERSION, xCo.str_ps(), yCo.str_ps());
+        } else
+            plot->reopen_frame1D();
+
+        // plot:
+        while (const COlo* f = fiter.next()) {
+            int k = fiter.k();
+            const COld* fd = dynamic_cast<const COld*>(f);
+            const COlc* fc = dynamic_cast<const COlc*>(f);
+
+            plot->doc_TxLine(f->name);
+            for (int i = 0; i < f->lDoc.size(); i++)
+                plot->doc_TxLine("  " + f->lDoc[i]);
+            if (fc) {
+                for (string line : fc->info_settings())
+                    plot->doc_TxLine("  " + line);
+                plot->doc_TxLine("  " + fc->info_table_header());
+            }
 
-        // draw new frame:
-        plot->clear_frame();
-        plot->plot_frame(xCo.str_ps(), yCo.str_ps());
-    }
+            // JSel.evaluate( 0, f->nJ()-1 );
+            for (int iv = 0; iv < JSel.size(); ++iv) {
+                int j = JSel[iv];
 
-    // plot:
-    while (const COlo* f = fiter.next()) {
-        int k = fiter.k();
-        const COld* fd = dynamic_cast<const COld*>(f);
-        const COlc* fc = dynamic_cast<const COlc*>(f);
-
-        plot->doc_TxLine(f->name);
-        for (int i = 0; i < f->lDoc.size(); i++)
-            plot->doc_TxLine("  " + f->lDoc[i]);
-        if (fc) {
-            for (string line : fc->info_settings())
-                plot->doc_TxLine("  " + line);
-            plot->doc_TxLine("  " + fc->info_table_header());
+                if (fd) {
+                    if (!plot_data(plot, fd, k, j, pstyle))
+                        continue;
+                    plot->doc_PtTxLine("  " + f->info_line(j), pstyle);
+                    ++pstyle;
+
+                } else if (fc) {
+                    if (fc->kconv != -1) {
+                        if (!plot_curve_convolved(plot, fc, k, j, cstyle))
+                            continue;
+                    } else if (fc->plot_to_grid) {
+                        if (!plot_curve_to_grid(plot, fc, k, j, cstyle))
+                            continue;
+                    } else if (!plot->refine) {
+                        if (!plot_curve_equidist(plot, fc, k, j, cstyle))
+                            continue;
+                    } else {
+                        if (!plot_curve_refine(plot, fc, k, j, cstyle))
+                            continue;
+                    }
+                    plot->doc_CvTxLine("  " + f->info_line(j), cstyle);
+                    ++cstyle;
+                }
+            }
         }
+        plot->show_specs();
+    }
 
-        // JSel.evaluate( 0, f->nJ()-1 );
-        for (int iv = 0; iv < JSel.size(); ++iv) {
-            int j = JSel[iv];
+//**************************************************************************************************
+//*  plot2D
+//**************************************************************************************************
 
-            if (fd) {
-                if (!plot_data(plot, fd, k, j, pstyle))
-                    continue;
-            } else if (fc) {
-                if (fc->kconv != -1) {
-                    if (!plot_curve_convolved(plot, fc, k, j, cstyle))
-                        continue;
-                } else if (fc->plot_to_grid) {
-                    if (!plot_curve_to_grid(plot, fc, k, j, cstyle))
-                        continue;
-                } else if (!plot->refine) {
-                    if (!plot_curve_equidist(plot, fc, k, j, cstyle))
-                        continue;
-                } else {
-                    if (!plot_curve_refine(plot, fc, k, j, cstyle))
-                        continue;
+    //! Plot all spectra as 2D color plot
+
+    void plot2D(class CPlot* plot)
+    { // EMBEDDED DIALOG
+        const COld* fd = SFSel::instance()->theOneD();
+
+        size_t m = fd->nJ();
+        if (m<2)
+            throw "2d plot requires at least 2 slices";
+        // determine bin limits
+        vector<double> zval = fd->zvec(0)->to_rvec();
+        vector<double> zlim = triv::histogram_limits(zval);
+        vector<double> xlim = triv::histogram_limits(fd->VS(0)->x);
+        double xinf = xlim.front();
+        double xsup = xlim.back();
+        double yinf, ysup;
+        if (plot->Y.logflag)
+            triv::getPosminMax(fd->VS(0)->y, yinf, ysup);
+        else
+            triv::getMinMax(fd->VS(0)->y, yinf, ysup);
+        for (size_t j=1; j<m; ++j) {
+            xlim = triv::histogram_limits(fd->VS(j)->x);
+            xinf = std::min(xinf, xlim.front());
+            xsup = std::max(xsup, xlim.back());
+            double yyinf, yysup;
+            if (plot->Y.logflag)
+                triv::getPosminMax(fd->VS(j)->y, yyinf, yysup);
+            else
+                triv::getMinMax(fd->VS(j)->y, yyinf, yysup);
+            yinf = std::min(yinf, yyinf);
+            ysup = std::max(ysup, yysup);
+        }
+        if (!plot->X.finite())
+            plot->X.set_limits(xinf, xsup);
+        if (!plot->Z.finite())
+            plot->Z.set_limits(zlim.front(), zlim.back());
+        if (plot->Y.logflag && !(std::isfinite(yinf) && std::isfinite(ysup)))
+            throw "No nonzero y values";
+        if (!plot->Y.finite())
+            plot->Y.set_limits(yinf-1e-4*std::abs(yinf), ysup+1e-4*std::abs(ysup));
+        // plot
+        plot->start_frame2D("Frida version " VERSION);
+        bool recent_empty_line = false;
+        for (size_t j=0; j<m; ++j) {
+            const CSpec* s = fd->VS(j);
+            vector<double> xlim = triv::histogram_limits(s->x);
+            for (size_t i=0; i<s->size(); ++i) {
+                if (  (plot->Y.force || plot->Y.contains(s->y[i]))
+                    && plot->X.contains(xlim[i]) && plot->X.contains(xlim[i+1])
+                    && plot->Z.contains(zlim[j]) && plot->Z.contains(zlim[j+1])) {
+                    plot->ps_line(
+                        str(format("%13.7g wx %13.7g wx  %13.7g wy %13.7g wy  %13.7g wH t2d")
+                            % xlim[i] % xlim[i+1] % zlim[j] % zlim[j+1] % s->y[i] ) );
+                    recent_empty_line = false;
                 }
-            } else
-                throw S("PROGRAM ERROR plot: unexpected file type");
-
-            if (fd) {
-                plot->doc_PtTxLine("  " + f->info_line(j), pstyle);
-                ++pstyle;
-            } else if (fc) {
-                plot->doc_CvTxLine("  " + f->info_line(j), cstyle);
-                ++cstyle;
+            }
+            if (!recent_empty_line) {
+                plot->ps_line("");
+                recent_empty_line = true;
             }
         }
+        plot->close_frame2D(fd->xco.str_ps(), fd->ZCo[0].str_ps(), fd->yco.str_ps());
+        // doclines
+        plot->doc_TxLine(fd->name);
+        for (int i = 0; i < fd->lDoc.size(); i++)
+            plot->doc_TxLine("  " + fd->lDoc[i]);
+        // plot -> file
+        static string fname = "/tmp/P.ps";
+        plot->write_postscript(
+            triv::wordexp_unique(fname), "overwrite", true, SVariRegistry::instance()->to_sMap());
+        cout << "Plotted to " << fname << "\n";
+        PObj pViewer = SVariRegistry::instance()->find("ps_viewer");
+        if (pViewer)
+            system((pViewer->to_s()+" "+fname+"&").c_str());
     }
-    plot->show_specs();
+
+} // anonymous namespace
+
+//**************************************************************************************************
+//*  Main plot routine accessible from the main menu
+//**************************************************************************************************
+
+void NPlot::plot(class CPlot* plot, bool add, const string& mode)
+{
+    if (plot->p2D) {
+        if (add)
+            throw "Cannot 'add' to 2D plot";
+        if (mode=="next" || mode=="prev")
+            throw "Cannot scroll through 2D plot";
+        ::plot2D(plot);
+    } else
+        ::plot1D(plot, add, mode);
 }
diff --git a/pub/lib/plot.hpp b/pub/lib/plot.hpp
index 74849502c1941638ed96ed1a053c4e9e0a6db13d..c83a9fc87689ff5b0398d23726a4e284e392728f 100644
--- a/pub/lib/plot.hpp
+++ b/pub/lib/plot.hpp
@@ -10,11 +10,11 @@
 #ifndef PLOT_H
 #define PLOT_H
 
-
 //! Plot data and curves.
 
 namespace NPlot
 {
-void plot(class CPlot* plot, bool add, const string& mode = "ask");
+    void plot(class CPlot* plot, bool add, const string& mode = "ask");
 }
+
 #endif // PLOT_H
diff --git a/pub/lib/reduce_curv.cpp b/pub/lib/reduce_curv.cpp
index 69fb19b9dad764d608d2bbb8cdcbf288257cbfcc..b0abd50ebc3623b60c491f98806396e59a3584b3 100644
--- a/pub/lib/reduce_curv.cpp
+++ b/pub/lib/reduce_curv.cpp
@@ -10,6 +10,7 @@
 #include "defs.hpp"
 
 #include <boost/format.hpp>
+#include <map>
 
 #include "../readplus/ask.hpp"
 #include "../trivia/integrate.hpp"
@@ -114,8 +115,8 @@ void cvin_integrate(double* r, double* dr, const COlc* fc, int k, int j, const v
 
 namespace NCvin
 { // internals:
-map<string, const CCvin*> hmap; // unsorted hash, for expression evaluation
-vector<const CCvin*> hlist; // sorted array, for help text
+    std::map<string, const CCvin*> hmap; // unsorted hash, for expression evaluation
+    vector<const CCvin*> hlist; // sorted array, for help text
 }
 
 
diff --git a/pub/lib/reduce_spec.cpp b/pub/lib/reduce_spec.cpp
index aa43360860855fccad2f20cb7ca44c2793bde774..807d4b462042e94ea50347c9a69a098df8e2c26d 100644
--- a/pub/lib/reduce_spec.cpp
+++ b/pub/lib/reduce_spec.cpp
@@ -10,6 +10,7 @@
 #include "defs.hpp"
 
 #include <boost/format.hpp>
+#include <map>
 
 #include "../trivia/string_ops.hpp"
 
@@ -26,39 +27,37 @@ using boost::format;
 
 //! Compute minimum value of a vector.
 
-void geni_valmin(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_valmin(int n, const vector<RObjVecNum>& a)
 {
-    int idx = 0;
-    *r = a[0]->to_r(0);
+    double r = a[0]->to_r(0);
+    double dr = a[0]->to_dr(0);
     for (int i = 1; i < n; ++i) {
-        if (a[0]->to_r(i) < *r) {
-            *r = a[0]->to_r(i);
-            idx = i;
+        if (a[0]->to_r(i) < r) {
+            r = a[0]->to_r(i);
+            dr = a[0]->to_dr(i);
         }
     }
-    if (dr)
-        *dr = a[0]->to_dr(idx);
+    return RObjEnu(new CObjEnu(r,dr));
 }
 
 //! Compute maximum value of a vector.
 
-void geni_valmax(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_valmax(int n, const vector<RObjVecNum>& a)
 {
-    int idx = 0;
-    *r = a[0]->to_r(0);
+    double r = a[0]->to_r(0);
+    double dr = a[0]->to_dr(0);
     for (int i = 1; i < n; ++i) {
-        if (a[0]->to_r(i) > *r) {
-            *r = a[0]->to_r(i);
-            idx = i;
+        if (a[0]->to_r(i) > r) {
+            r = a[0]->to_r(i);
+            dr = a[0]->to_dr(i);
         }
     }
-    if (dr)
-        *dr = a[0]->to_dr(idx);
+    return RObjEnu(new CObjEnu(r,dr));
 }
 
 //! Return x[i] with i for which y[i] is minimal.
 
-void geni_argmin(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_argmin(int n, const vector<RObjVecNum>& a)
 {
     int idx = 0;
     double extr = a[1]->to_r(0);
@@ -68,14 +67,12 @@ void geni_argmin(double* r, double* dr, int n, const vector<RObjVecNum>& a)
             idx = i;
         }
     }
-    *r = a[0]->to_r(idx);
-    if (dr)
-        *dr = 0; // TODO better estimate
+    return RObjDbl(new CObjDbl(a[0]->to_r(idx)));
 }
 
 //! Return x[i] with i for which y[i] is maximal.
 
-void geni_argmax(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_argmax(int n, const vector<RObjVecNum>& a)
 {
     int idx = 0;
     double extr = a[1]->to_r(0);
@@ -85,14 +82,12 @@ void geni_argmax(double* r, double* dr, int n, const vector<RObjVecNum>& a)
             idx = i;
         }
     }
-    *r = a[0]->to_r(idx);
-    if (dr)
-        *dr = 0; // TODO better estimate
+    return RObjDbl(new CObjDbl(a[0]->to_r(idx)));
 }
 
 //! Return i for which x[i] is minimal.
 
-void geni_idxmin(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_idxmin(int n, const vector<RObjVecNum>& a)
 {
     int idx = 0;
     double extr = a[0]->to_r(0);
@@ -102,14 +97,12 @@ void geni_idxmin(double* r, double* dr, int n, const vector<RObjVecNum>& a)
             idx = i;
         }
     }
-    *r = idx;
-    if (dr)
-        *dr = 0; // TODO better estimate
+    return RObjInt(new CObjInt(idx));
 }
 
 //! Return i for which x[i] is maximal.
 
-void geni_idxmax(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_idxmax(int n, const vector<RObjVecNum>& a)
 {
     int idx = 0;
     double extr = a[0]->to_r(0);
@@ -119,39 +112,36 @@ void geni_idxmax(double* r, double* dr, int n, const vector<RObjVecNum>& a)
             idx = i;
         }
     }
-    *r = idx;
-    if (dr)
-        *dr = 0; // TODO better estimate
+    return RObjInt(new CObjInt(idx));
 }
 
 //! Sum.
 
-void geni_sum(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_sum(int n, const vector<RObjVecNum>& a)
 {
-    *r = 0;
+    double r = 0;
     for (int i = 0; i < n; i++)
-        *r += a[0]->to_r(i);
-    if (dr)
-        *dr = 0; // TODO better estimate
+        r += a[0]->to_r(i);
+    return RObjNum(new CObjDbl(r));
+    // TODO error estimate
 }
 
 //! Average.
 
-void geni_avge(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_avge(int n, const vector<RObjVecNum>& a)
 {
-    *r = 0;
+    double r = 0;
     if (!n)
         throw S("Cannot compute average of empty vector");
     for (int i = 0; i < n; i++)
-        *r += a[0]->to_r(i);
-    *r /= n;
-    if (dr)
-        *dr = 0; // TODO better estimate
+        r += a[0]->to_r(i);
+    return RObjNum(new CObjDbl(r/n));
+    // TODO error estimate
 }
 
 //! Sample variance.
 
-void geni_variance(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_variance(int n, const vector<RObjVecNum>& a)
 {
     if (n < 2)
         throw S("Cannot compute sample variance for sample size < 2");
@@ -161,52 +151,49 @@ void geni_variance(double* r, double* dr, int n, const vector<RObjVecNum>& a)
         q += (a[0]->to_r(i) - p) * (a[0]->to_r(i) - pp);
         p = pp;
     }
-    *r = q / (n - 1);
-    if (dr)
-        *dr = 0; // TODO better estimate
+    return RObjDbl(new CObjDbl(q / (n - 1)));
+    // TODO error estimate
 }
 
 //! Sample standard deviation.
 
-void geni_stdv(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_stdv(int n, const vector<RObjVecNum>& a)
 {
-    geni_variance(r, dr, n, a);
-    *r = sqrt(*r);
-    if (dr)
-        *dr = 0; // TODO better estimate
+    RObjNum var = geni_variance(n, a);
+    return RObjDbl(new CObjDbl(var->to_r()));
+    // TODO error estimate
 }
 
 //! Integral.
 
-void geni_integral(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_integral(int n, const vector<RObjVecNum>& a)
 {
-    *r = 0;
+    double r = 0;
     for (int i = 0; i < n - 1; i++) {
         if (a[0]->to_r(i + 1) <= a[0]->to_r(i))
             throw S("a not sorted");
-        *r += (a[0]->to_r(i + 1) - a[0]->to_r(i)) * (a[1]->to_r(i + 1) + a[1]->to_r(i)) / 2;
+        r += (a[0]->to_r(i + 1) - a[0]->to_r(i)) * (a[1]->to_r(i + 1) + a[1]->to_r(i)) / 2;
     }
-    if (dr)
-        *dr = 0; // TODO better estimate
+    return RObjDbl(new CObjDbl(r));
+    // TODO error estimate
 }
 
 //! Center of gravity in x, weighed by y.
 
-void geni_cog(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_cog(int n, const vector<RObjVecNum>& a)
 {
     double r0 = 0, r1 = 0;
     for (int i = 0; i < n; i++) {
         r0 += a[1]->to_r(i);
         r1 += a[1]->to_r(i) * a[0]->to_r(i);
     }
-    *r = r0 > 0 ? r1 / r0 : 0;
-    if (dr)
-        *dr = 0; // TODO better estimate
+    return RObjDbl(new CObjDbl(r0 > 0 ? r1 / r0 : 0));
+    // TODO error estimate
 }
 
 //! Standard deviation in x, weighed by y.
 
-void geni_width(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_width(int n, const vector<RObjVecNum>& a)
 {
     double r0 = 0, r1 = 0, r2 = 0;
     for (int i = 0; i < n; i++) {
@@ -219,13 +206,12 @@ void geni_width(double* r, double* dr, int n, const vector<RObjVecNum>& a)
     for (int i = 0; i < n; i++) {
         r2 += a[1]->to_r(i) * SQR(a[0]->to_r(i) - center);
     }
-    *r = sqrt(r2 / r0);
-    if (dr)
-        *dr = 0; // TODO better estimate
+    return RObjDbl(new CObjDbl(sqrt(r2 / r0)));
+    // TODO error estimate
 }
 
 //! Correlation coefficient.
-void geni_corr(double* r, double* dr, int n, const vector<RObjVecNum>& a)
+RObjNum geni_corr(int n, const vector<RObjVecNum>& a)
 {
     double r0 = 0, r1 = 0, s0 = 0, s1 = 0, v = 0;
     for (int i = 0; i < n; i++) {
@@ -237,9 +223,26 @@ void geni_corr(double* r, double* dr, int n, const vector<RObjVecNum>& a)
         s1 += SQR(a[1]->to_r(i) - r1) / n;
         v += (a[0]->to_r(i) - r0) * (a[1]->to_r(i) - r1) / n;
     }
-    *r = v / sqrt(s0 * s1);
-    if (dr)
-        *dr = 0; // TODO better estimate
+    return RObjDbl(new CObjDbl( v / sqrt(s0 * s1) ));
+    // TODO error estimate
+}
+
+//! First index for which expr is true.
+RObjNum geni_firstwith(int n, const vector<RObjVecNum>& a)
+{
+    for (int i = 0; i < n; ++i)
+        if (a[0]->to_i(i))
+            return RObjInt(new CObjInt(i));
+    return RObjInt(new CObjInt(-1));
+}
+
+//! Last index for which expr is true.
+RObjNum geni_lastwith(int n, const vector<RObjVecNum>& a)
+{
+    for (int i = n-1; i>= 0; --i)
+        if (a[0]->to_i(i))
+            return RObjInt(new CObjInt(i));
+    return RObjInt(new CObjInt(-1));
 }
 
 
@@ -249,8 +252,8 @@ void geni_corr(double* r, double* dr, int n, const vector<RObjVecNum>& a)
 
 namespace NGeni
 { // internals:
-map<string, const CGeni*> gmap; // unsorted hash, for expression evaluation
-vector<const CGeni*> glist; // sorted array, for help text
+    std::map<string, const CGeni*> gmap; // unsorted hash, for expression evaluation
+    vector<const CGeni*> glist; // sorted array, for help text
 }
 
 CGeni::CGeni(
@@ -308,4 +311,8 @@ void SGeniRegistry::initialize()
          "corr", 2, "x,y", geni_corr, "?", // TODO: unit?
          "correlation coefficient of x and y"))
         ->register_me();
+    (new CGeni("firstwith", 1, "expr", geni_firstwith, "-",
+               "first index for which expr is true"))->register_me();
+    (new CGeni("lastwith", 1, "expr", geni_firstwith, "-",
+               "last index for which expr is true"))->register_me();
 }
diff --git a/pub/lib/reduce_spec.hpp b/pub/lib/reduce_spec.hpp
index eda55bb9c35ecf65971444a9fe20594b698bc14f..6404344faf3949d71b3109a30fcc46e9fe726887 100644
--- a/pub/lib/reduce_spec.hpp
+++ b/pub/lib/reduce_spec.hpp
@@ -14,7 +14,7 @@
 
 //!  Function type: Evaluate generalized integral for given vector(s).
 
-typedef void (*geni_eval)(double*, double*, int, const vector<RObjVecNum>&);
+typedef RObjNum (*geni_eval)(int, const vector<RObjVecNum>&);
 
 
 //! A wrapper holding a functional.
diff --git a/pub/lib/registry.hpp b/pub/lib/registry.hpp
index 27eec53cf7e8b059f8d63774adf34b49fc0f3a73..5dd25570908b6eeec662c567cba29f04077655ae 100644
--- a/pub/lib/registry.hpp
+++ b/pub/lib/registry.hpp
@@ -10,6 +10,7 @@
 #ifndef IREGISTRY_H
 #define IREGISTRY_H
 
+#include <map>
 #include "../trivia/singleton.hpp"
 
 //! Mixin interface for registries holding objects of type T; temporary version for SFuncRegistry.
@@ -18,7 +19,7 @@ template <class T> class IRegistryTmp
 {
 protected:
     virtual string type_name() const = 0;
-    map<string, /*const*/ T*> FMap; //! unsorted hash, for expression evaluation
+    std::map<string, /*const*/ T*> FMap; //! unsorted hash, for expression evaluation
     vector<const T*> FList; //! sorted array, for help text
 public:
     virtual ~IRegistryTmp()
@@ -53,7 +54,7 @@ template <class T> class IRegistry
 {
 protected:
     virtual string type_name() const = 0;
-    map<string, const T*> FMap; //! unsorted hash, for expression evaluation
+    std::map<string, const T*> FMap; //! unsorted hash, for expression evaluation
     vector<const T*> FList; //! sorted array, for help text
 public:
     virtual ~IRegistry()
diff --git a/pub/lib/rssm.cpp b/pub/lib/rssm.cpp
index c45e4ae7e24fccbdf04efb83fd927eb552c63cb4..1e83eae4472c5c0bcc42ea41270a1b3b754c6ead 100644
--- a/pub/lib/rssm.cpp
+++ b/pub/lib/rssm.cpp
@@ -11,11 +11,10 @@
 
 #include <cstring>
 #include <fstream>
-
+#include <boost/filesystem.hpp>
 #include <yaml-cpp/yaml.h>
 
 #include "../readplus/ask.hpp"
-#include "../trivia/file_ops.hpp"
 #include "../trivia/string_ops.hpp"
 
 #include "mem.hpp"
@@ -24,6 +23,8 @@
 #include "rssm.hpp"
 #include "slice.hpp"
 
+namespace fs = boost::filesystem;
+
 
 //! All relevant information extracted from one raw-data file from SPHERES.
 
@@ -223,8 +224,7 @@ void NRSSM::read_spec(int flag)
 //   16 no normalization
 
 {
-    string file_f, name;
-    file_f = wask("Read SPHERES data from file");
+    string file_f = wask("Read SPHERES data from file");
     CRawfileSpheres R;
     std::ifstream F_in;
 
@@ -247,7 +247,7 @@ void NRSSM::read_spec(int flag)
         olf[iolf]->yco = CCoord("cts", "sec-1");
         olf[iolf]->ZCo.push_back(CCoord("det", ""));
     }
-    triv::fname_divide(file_f, 0, &name, 0);
+    string name = fs::path(file_f).filename().stem().string();
     olf[0]->name = name + "left";
     olf[1]->name = name + "right";
     olf[2]->name = name + "open_left";
@@ -379,7 +379,7 @@ void NRSSM::read_series(int flag)
 
 {
     char tstrg[30];
-    string fser, fnam, name;
+    string fser, fnam;
     time_t t;
     int isub;
     vector<CRawfileSpheres> RR;
@@ -446,7 +446,7 @@ void NRSSM::read_series(int flag)
         olf[iolf]->ZCo.push_back(CCoord("#sub", ""));
         olf[iolf]->ZCo.push_back(CCoord("det", ""));
     }
-    triv::fname_divide(fser, 0, &name, 0);
+    string name = fs::path(fser).filename().stem().string();
     olf[0]->name = name;
     olf[1]->name = name + "open";
     olf[0]->log_action("refl, average over both halfspaces");
diff --git a/pub/lib/slice.cpp b/pub/lib/slice.cpp
index 4ca860e4a4e623bd67f82599539e32f1fc908406..f735b467d348dc05470f75c49797cfd6162467bb 100644
--- a/pub/lib/slice.cpp
+++ b/pub/lib/slice.cpp
@@ -243,14 +243,14 @@ string CSpec::info_line() const
 
 //! Returns true if all data points have nonzero dy.
 
-bool CSpec::has_nonzero_dy() const
+bool CSpec::dy_are_all_nonzero() const
 {
     if (!has_dy())
         return false;
     return std::all_of(dy.cbegin(), dy.cend(), [](double dv) { return dv > 0; });
 }
 
-PSpec CSpec::binned(const vector<int>& breaks) const
+PSpec CSpec::binned(const vector<int>& breaks, const bool sampling_error) const
 {
     PSpec sout(new CSpec());
     sout->z = z;
@@ -269,10 +269,11 @@ PSpec CSpec::binned(const vector<int>& breaks) const
         for (int i = igi; i < igf; ++i) {
             if (has_dy())
                 vg_src += SQR(dy[i]);
-            vg_grp += SQR(y[i] - yg);
+            if (sampling_error)
+                vg_grp += SQR(y[i] - yg);
         }
         double vg = vg_src / ng / ng;
-        if (ng > 1)
+        if (sampling_error && ng > 1)
             vg += vg_grp / (ng - 1);
         sout->push_xyd(xg, yg, sqrt(vg));
     }
diff --git a/pub/lib/slice.hpp b/pub/lib/slice.hpp
index 3f2fada86d569a5b692f2973cd237a541169e41a..1ff7a6a4506fcd0af071cb49eff0d1fc67ca1ad4 100644
--- a/pub/lib/slice.hpp
+++ b/pub/lib/slice.hpp
@@ -47,8 +47,8 @@ public:
     bool has_step(double step) const;
     string info_line() const;
     inline bool has_dy() const { return dy.size() != 0; }
-    bool has_nonzero_dy() const;
-    PSpec binned(const vector<int>& breaks) const;
+    bool dy_are_all_nonzero() const;
+    PSpec binned(const vector<int>& breaks, const bool sampling_error) const;
 };
 
 
diff --git a/pub/lib/special.cpp b/pub/lib/special.cpp
index cf8eba150c371b191203fbd038e3c0f6e71ebde9..389c89dee40ce677caa5c463351686e63d99d4dc 100644
--- a/pub/lib/special.cpp
+++ b/pub/lib/special.cpp
@@ -9,10 +9,14 @@
 
 #include "defs.hpp"
 
-
+#include <fstream>
+#include <vector>
 #include <fftw3.h>
+#include <boost/format.hpp>
 
-
+#include "../trivia/file_ops.hpp"
+#include "../trivia/vector_ops.hpp"
+#include "../readplus/ask.hpp"
 #include "fsel.hpp"
 #include "loop.hpp"
 #include "mem.hpp"
@@ -21,6 +25,9 @@
 #include "slice.hpp"
 #include "special.hpp"
 
+using boost::format;
+using std::vector;
+
 namespace NSpecial
 {
 void q_eval(double* par, int m_dat, double* fvec, void* data, int* info);
diff --git a/pub/lib/toplevel.cpp b/pub/lib/toplevel.cpp
index 9b5d6ec27dbfe401ec601a4c6704ac6af24915da..350192fbf93eeaacb3277cc311689de6f3f05e92 100644
--- a/pub/lib/toplevel.cpp
+++ b/pub/lib/toplevel.cpp
@@ -58,7 +58,7 @@ void atexit_handler() {}
 
 //! Executes one Frida command.
 
-void CFrida::execute_cmd(const string cmdline)
+void CFrida::execute_cmd(const string& cmdline)
 {
     // Empty input, comment lines.
     if (cmdline == "" || cmdline[0] == '#') {
@@ -178,6 +178,10 @@ void CFrida::interactive()
         string cmdline;
         try {
             cmdline = NMacro::readln(triv::indices_to_s(SFSel::instance()->sel()) + " > ");
+            if (cmdline=="EOF") {
+                cout << "\n";
+                exit(0);
+            }
             execute_cmd(cmdline);
         } catch (string& ex) {
             cout << "'" << cmdline << "' failed:\n  " << ex << "\n";
@@ -199,7 +203,7 @@ void CFrida::interactive()
 
 //! Reads a script file and executes it line by line.
 
-void CFrida::execute_file(const string fnam)
+void CFrida::execute_file(const string& fnam, bool batchMode)
 {
     int lineno = 0;
     try {
@@ -212,7 +216,19 @@ void CFrida::execute_file(const string fnam)
             try {
                 execute_cmd(cmdline);
             } catch (string& ex) {
-                throw "'" + cmdline + "':\n  " + ex;
+                string msg = "'" + cmdline + "':\n  " + ex;
+                if (batchMode) {
+                    std::cerr << msg << "\n";
+                    exit(1);
+                }
+                throw msg;
+            } catch (...) {
+                string msg = "'" + cmdline + "':\n  unforeseen exception type";
+                if (batchMode) {
+                    std::cerr << msg << "\n";
+                    exit(1);
+                }
+                throw msg;
             }
         }
     } catch (string& ex) {
diff --git a/pub/lib/toplevel.hpp b/pub/lib/toplevel.hpp
index 2e347a0b7a649bd056b674bbac6fdbcac198c782..78511f004d058799b39d3681d6cd3dea5ceb02b6 100644
--- a/pub/lib/toplevel.hpp
+++ b/pub/lib/toplevel.hpp
@@ -16,7 +16,7 @@
 class CFrida
 {
 private:
-    void execute_cmd(const std::string cmdline);
+    void execute_cmd(const std::string& cmdline);
     // Time spent in frida, for optimizing numerical routines:
     clock_t clock_start;
     clock_t clock_cmd_i;
@@ -25,7 +25,7 @@ private:
 public:
     CFrida();
     static std::string prompt();
-    void execute_file(const std::string fname);
+    void execute_file(const std::string& fname, bool batchMode);
     void interactive();
 };
 
diff --git a/pub/lib/variables.cpp b/pub/lib/variables.cpp
index b7d5c761bd42fdc85c6bfb70e5477d3088d91ab6..9e6068eb64ccd9607c55aec284c61b581cc13acc 100644
--- a/pub/lib/variables.cpp
+++ b/pub/lib/variables.cpp
@@ -7,18 +7,21 @@
 //! \file  variables.cpp
 //! \brief Implements class SVariRegistry.
 
+#include <algorithm>
+
 #include "variables.hpp"
 #include "defs.hpp"
+#include "obj.hpp"
 #include "ptr.hpp"
 
 
-PObj SVariRegistry::find(string key) const
+PObj SVariRegistry::find(const string& key) const
 {
     auto pos = Map.find(key);
     return pos == Map.end() ? nullptr : pos->second;
 }
 
-PObj SVariRegistry::find_or_fail(string key) const
+PObj SVariRegistry::find_or_fail(const string& key) const
 {
     PObj ret = find(key);
     if (!ret)
@@ -27,36 +30,21 @@ PObj SVariRegistry::find_or_fail(string key) const
 }
 
 
-void SVariRegistry::display_functions() const
+void SVariRegistry::display_all() const
 {
-    /*
-    // this implementation works only, if flist is strictly ordered:
-    // first operators by precedence, then functions.
-
-    cout << "Operators by precedence:\n";
-    int precedence = -1;
-    for( int i=0; i<FList.size(); ++i ){
-        const CFunc *f;
-        f = FList[i];
-        if( f->precedence ) { // operators
-            if( f->precedence!=precedence )
-                cout << "\n ";
-            cout << " " << f->key;
-        } else { // functions
-            if( f->precedence!=precedence )
-                cout << "\nBuilt-in functions:\n";
-            cout << "  " << f->key << f->explanation << "\n";
-            }
-        precedence = f->precedence;
-    }
-    */
+    vector<string> keys;
+    for (const auto& it: Map)
+        keys.push_back(it.first);
+    sort(keys.begin(), keys.end());
+    for (const string& key: keys)
+        cout << "  " << key << " = " << Map.at(key)->to_s() << "\n";
 }
 
-void SVariRegistry::register_scalar(string key, PObj val) { Map[key] = val; }
+void SVariRegistry::register_scalar(const string& key, PObj val) { Map[key] = val; }
 
 //! Undefines a key (removes entry from registry); returns true unless the key wasn't defined.
 
-bool SVariRegistry::undef(string key)
+bool SVariRegistry::undef(const string& key)
 {
     auto pos = Map.find(key);
     if (pos == Map.end())
@@ -64,3 +52,12 @@ bool SVariRegistry::undef(string key)
     Map.erase(pos);
     return true;
 }
+
+std::map<const string, string> SVariRegistry::to_sMap() const
+{
+    std::map<const string, string> ret;
+    for (const auto& it: Map) {
+        ret[it.first] = it.second->to_s();
+    }
+    return ret;
+}
diff --git a/pub/lib/variables.hpp b/pub/lib/variables.hpp
index 96b3a7432c685674df89dc68aaa803660a9f36c1..f05ef77f0844b60e33125213145c22df5b83691b 100644
--- a/pub/lib/variables.hpp
+++ b/pub/lib/variables.hpp
@@ -10,8 +10,8 @@
 #ifndef VARIABLES_H
 #define VARIABLES_H
 
+#include <map>
 #include "../trivia/singleton.hpp"
-
 #include "defs.hpp"
 #include "ptr.hpp"
 
@@ -20,16 +20,17 @@
 class SVariRegistry : public triv::ISingleton<SVariRegistry>
 {
 private:
-    map<string, PObj> Map; //! unsorted hash, for expression evaluation
+    std::map<const string, PObj> Map; //! unsorted hash, for expression evaluation
 
 public:
-    PObj find(string key) const;
-    PObj find_or_fail(string key) const;
+    PObj find(const string& key) const;
+    PObj find_or_fail(const string& key) const;
 
-    void display_functions() const;
+    void display_all() const;
 
-    void register_scalar(string key, PObj val);
-    bool undef(string key);
+    void register_scalar(const string& key, PObj val);
+    bool undef(const string& key);
+    std::map<const string, string> to_sMap() const;
 };
 
 #endif // VARIABLES_H
diff --git a/pub/plot/CMakeLists.txt b/pub/plot/CMakeLists.txt
index a00656e46c995849c0685ecd998e3374c76dfc2b..9f68fe7e486aa515ae261fa906fafb9fe252047d 100644
--- a/pub/plot/CMakeLists.txt
+++ b/pub/plot/CMakeLists.txt
@@ -1,23 +1,31 @@
 # frida: trivia/CMakeLists.txt
 
+set(library_name fridaplot)
+set(${library_name}_LIBRARY ${library_name} PARENT_SCOPE)
+set(${library_name}_LIBRARY_TYPE SHARED)
+
 include_directories(${Frida_SOURCE_DIR}/plot ${CMAKE_CURRENT_BINARY_DIR})
 
 set(src_files
-axis.cpp
-dualplot.cpp
-plowin.cpp
-)
+    axis.cpp
+    dualplot.cpp
+    gnuplotter.cpp
+    ps_plotter.cpp
+    plowin.cpp
+    )
 
 set(inc_files
-axis.hpp
-dualplot.hpp
-plowin.hpp
-)
+    axis.hpp
+    dualplot.hpp
+    gnuplotter.hpp
+    ps_plotter.hpp
+    plowin.hpp
+    )
 
-add_library(libfridaplot SHARED ${src_files})
+add_library(${library_name} SHARED ${src_files})
 
-set_target_properties(libfridaplot PROPERTIES OUTPUT_NAME fridaplot)
+set_target_properties(${library_name} PROPERTIES OUTPUT_NAME ${library_name})
 
-target_link_libraries(libfridaplot)
+target_link_libraries(${library_name} ${Readline_LIBRARIES})
 
-install(TARGETS libfridaplot DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
+install(TARGETS ${library_name} LIBRARY DESTINATION ${destination_lib})
diff --git a/pub/plot/axis.cpp b/pub/plot/axis.cpp
index 82dfe64c2a6e5e958d8be6f59e53c207f8ba1b35..01a50438a7f894c204bbd94d4f634c87480eb7c1 100644
--- a/pub/plot/axis.cpp
+++ b/pub/plot/axis.cpp
@@ -165,7 +165,6 @@ void CAxis::set_rounded_limits(double _inf, double _sup)
             if (inf2 < 0 && inf > 0)
                 inf2 = 0;
             mydigits += 0.1;
-            // printf("DEB [%g,%g] -> [%g,%g] (%g)\n", inf, sup, inf2, sup2, mydigits);
             if (mydigits > 17) {
                 std::cerr << std::setprecision(17)
                           << "PLEASE REPORT THIS BUG: escaping from endless loop in Axis::"
@@ -309,116 +308,150 @@ double CAxis::pc(double v) const { return 10 * value2plotcoord(v); }
 double CAxis::pcerr(double v, double dv) const { return 10 * value2ploterror(v, dv); }
 
 
-//! Sets Tacks, *ntpt, *ticklim to a nice division of the plot range.
+//! Sets Tacks, ntpt, nt4t, *ticklim to a nice division of the plot range.
 
-void CAxis::calc_ticks(vector<double>& Tacks, int* ntpt, double* ticklim) const
+void CAxis::calc_ticks(vector<double>& Tacks, int& ntpt, int& nt4t, double* ticklim) const
 {
-    if (inf >= sup)
-        throw "BUG detected by calc_ticks: inf=" + S(inf) + " >= sup=" + S(sup);
+    if (logflag)
+        calc_logticks(Tacks, ntpt, nt4t, ticklim);
+    else
+        calc_linticks(Tacks, ntpt, nt4t, ticklim);
+}
+
+
+//! Sets Tacks, ntpt, nt4t, *ticklim to a nice division of the plot range.
+
+void CAxis::calc_linticks(vector<double>& Tacks, int& ntpt, int& nt4t, double* ticklim) const
+{
+    double dtack;
+    calc_lintacks(Tacks, ntpt, dtack);
+    if (!Tacks.size())
+        throw "Empty Tack vector for "+name+" axis ["+S(inf)+","+S(sup)+"]";
+    ticklim[0] = Tacks.front() - dtack;
+    ticklim[1] = Tacks.back() + dtack;
+    nt4t = Tacks.size() + 2;
+}
+
+//! Sets Tacks, *ntpt, and dtack
+
+void CAxis::calc_lintacks(vector<double>& Tacks, int& ntpt, double& dtack) const
+{
+    double range = sup-inf;
+    if (range <= 0)
+        throw "BUG detected by calc_linticks: inf=" + S(inf) + " >= sup=" + S(sup);
+    double r = log10(range);
+    int ir = (int)((r < 0) ? r - 1 : r);
+    double rd = r - ir; // fractional part of r
+    double rdr = pow(10., rd);
+    if (rdr > 9.99999) {
+        dtack = 2.5 * pow(10., ir); // spacing between tacks
+        ntpt = 5; // ticks per tack
+    } else if (rdr > 5.00001) {
+        dtack = 2 * pow(10., ir);
+        ntpt = 4;
+    } else if (rdr > 2.500005) {
+        dtack = 1 * pow(10., ir);
+        ntpt = 5;
+    } else if (rdr > 1.600003) {
+        dtack = .5 * pow(10., ir);
+        ntpt = 5;
+    } else if (rdr > 1.250002) {
+        dtack = .4 * pow(10., ir);
+        ntpt = 4;
+    } else {
+        dtack = .25 * pow(10., ir);
+        ntpt = 5;
+    }
+    // Sets tack vector, taking extra precaution to avoid rounding errors.
     Tacks.clear();
+    double dlow = dtack * (floor(inf/dtack)-1);
+    double dhig = dtack * (ceil(sup/dtack)+1);
+    double drange = dhig-dlow;
+    int nTacks = drange/dtack + 1.5;
+    if (nTacks<2)
+        throw "BUG: calc_lintacks -> nTacks<2";
+    for (int i=0; i<nTacks; ++i) {
+        double d = (i*dhig + (nTacks-1-i)*dlow)/(nTacks-1);
+        if (std::abs(d)<1e-15*drange)
+            d = 0;
+        if (inf-1e-4*range <= d && d <= sup+1e-4*range)
+            Tacks.push_back(d);
+    }
+}
 
-    if (!logflag) {
-        double r = log10(sup - inf);
-        int ir = (int)((r < 0) ? r - 1 : r);
-        double rd = r - ir; // fractional part of r
-        double rdr = pow(10., rd);
-        double dtack;
-        if (rdr > 9.99999) {
-            dtack = 2.5 * pow(10., ir); // spacing between tacks
-            *ntpt = 5; // ticks per tack
-        } else if (rdr > 5.00001) {
-            dtack = 2 * pow(10., ir);
-            *ntpt = 4;
-        } else if (rdr > 2.500005) {
-            dtack = 1 * pow(10., ir);
-            *ntpt = 5;
-        } else if (rdr > 1.600003) {
-            dtack = .5 * pow(10., ir);
-            *ntpt = 5;
-        } else if (rdr > 1.250002) {
-            dtack = .4 * pow(10., ir);
-            *ntpt = 4;
-        } else {
-            dtack = .25 * pow(10., ir);
-            *ntpt = 5;
-        }
-        double d = inf / dtack;
-        double tack0 = dtack * (int)(d <= 0 ? d - 1 : d);
-        d = sup / dtack;
-        double tackn = dtack * ((int)(d < 0 ? d - 1 : d) + 1);
-        double vsub = inf - (sup - inf) * 1.e-4;
-        double vsup = sup + (sup - inf) * 1.e-4;
-        int nt = (int)((tackn - tack0) / dtack) + 3; // allocate enough
-        for (int i = 0; i < nt; i++) {
-            d = tack0 + i * dtack;
-            if (vsub <= d && d <= vsup)
-                Tacks.push_back(d);
-        }
 
-        int ntack = Tacks.size();
-        ticklim[0] = tack0;
-        ticklim[1] = Tacks[ntack - 1] + dtack;
+//! Sets Tacks, ntpt, nt4t, *ticklim to a nice division of the plot range.
+
+void CAxis::calc_logticks(vector<double>& Tacks, int& ntpt, int& nt4t, double* ticklim) const
+{
+    if (inf >= sup)
+        throw "BUG detected by calc_logticks: inf=" + S(inf) + " >= sup=" + S(sup);
+    if (inf <= 0)
+        throw S("BUG detected by calc_logticks: negative log argument");
 
-    } else { // log scale
-        static double eins = 1 + 1e-6 - 1e-12;
+    static double eins = 1 + 1e-6 - 1e-12;
 
-        if (inf <= 0)
-            throw S("BUG in CAxis::calc_ticks: negative log argument");
+    double rlgmin = log10(inf);
+    double rlgmax = log10(sup);
+    double rlgrel = rlgmax - rlgmin;
+    if (!std::isfinite(rlgrel) || rlgrel > 100)
+        throw "Excessive log range " + S(inf) + " .. " + S(sup);
 
-        double rlgmin = log10(inf);
-        double rlgmax = log10(sup);
-        double rlgrel = rlgmax - rlgmin;
-        if (rlgrel > 100)
-            throw S("Excessive log range");
+    int incr; // -> decades per tack
+    if (rlgrel <= 10) {
+        incr = 1;
+    } else {
+        incr = (int)(rlgrel / 7 + 1);
+        if (incr > 3)
+            incr = 3 * (incr / 3); // preferred values 3, 6, ...
+    }
 
-        // incr := #decades per tack
-        int incr;
-        if (rlgrel <= 10) {
-            incr = 1;
-        } else {
-            incr = (int)(rlgrel / 7 + 1);
-            if (incr > 3)
-                incr = 3 * (incr / 3); // preferred values 3, 6, ...
-        }
+    // first and last tack
+    int minexp = (int)(rlgmin > 0 ? rlgmin + 1e-6 : rlgmin - 1e-6 - 1);
+    int maxexp = (int)(rlgmax > 0 ? rlgmax + 1e-6 : rlgmax - 1e-6 - 1);
+    if (incr > 1) {
+        minexp -= minexp % incr;
+        maxexp -= maxexp % incr;
+    }
 
-        // first and last tack
-        int minexp = (int)(rlgmin > 0 ? rlgmin + 1e-6 : rlgmin - 1e-6 - 1);
-        int maxexp = (int)(rlgmax > 0 ? rlgmax + 1e-6 : rlgmax - 1e-6 - 1);
-        if (incr > 1) {
-            minexp -= minexp % incr;
-            maxexp -= maxexp % incr;
-        }
+    // set Tacks
+    double d1 = inf / eins;
+    double d2 = sup * eins;
+    Tacks.clear();
+    for (int i = minexp; i <= maxexp; i += incr) {
+        double r0 = pow(10., i);
+        if (d1 <= r0 && r0 <= d2)
+            Tacks.push_back(r0);
+    }
+    nt4t = Tacks.size() + 2;
 
-        // set Tacks
-        double d1 = inf / eins;
-        double d2 = sup * eins;
-        for (int i = minexp; i <= maxexp; i += incr) {
-            double r0 = pow(10., i);
-            if (d1 <= r0 && r0 <= d2)
-                Tacks.push_back(r0);
-        }
+    // set tick limits (may exceed actual tick range)
+    int ntack = Tacks.size();
+    if (ntack >= 1) {
+        ticklim[0] = Tacks.front() / pow(10., incr);
+        ticklim[1] = Tacks.back()  * pow(10., incr);
+    } else {
+        // untested. just to allow plots when no tacks in window
+        ticklim[0] = pow(10., minexp);
+        ticklim[1] = pow(10., maxexp + 1);
+    }
 
-        // set tick limits (may exceed actual tick range)
-        int ntack = Tacks.size();
-        if (ntack >= 1) {
-            ticklim[0] = Tacks[0] / pow(10., incr);
-            ticklim[1] = Tacks[ntack - 1] * pow(10., incr);
-        } else {
-            // untested. just to allow plots when no tacks in window
-            ticklim[0] = pow(10., minexp);
-            ticklim[1] = pow(10., maxexp + 1);
-        }
+    // determine #ticks / tack
+    if (incr == 1) {
+        if (rlgrel <= 3)
+            ntpt = 9;
+        else if (rlgrel <= 7)
+            ntpt = 3; // 1-2-5-10 - Schritte
+        else
+            ntpt = 1;
+    } else {
+        ntpt = -incr; // this one has special semantics: it means 'incr' ticks per tack
+    }
 
-        // determine #ticks / tack
-        if (incr == 1 && rlgrel <= 3) {
-            *ntpt = 9;
-        } else if (incr == 1 && rlgrel <= 7) {
-            *ntpt = 3; // 1-2-5-10 - Schritte
-        } else if (incr == 1) {
-            *ntpt = 1;
-        } else {
-            *ntpt = -incr;
-            // this one has special semantics: it means 'incr' ticks per tack
-        }
+    // for narrow ranges, overwrite tacks
+    if (ntack<2) {
+        double dtack;
+        int ntpt_dummy;
+        calc_lintacks(Tacks, ntpt_dummy, dtack);
     }
 }
diff --git a/pub/plot/axis.hpp b/pub/plot/axis.hpp
index 3aea8cdcb4db2a716d62a5b42c47d9494e1f3e48..e01fbc45c71b8deff4a01396d168f81b6276b9d9 100644
--- a/pub/plot/axis.hpp
+++ b/pub/plot/axis.hpp
@@ -7,6 +7,9 @@
 //! \file  axis.hpp
 //! \brief CAxis: One axis of a coordinate frame.
 
+#include <string>
+#include <vector>
+
 //! One axis of a coordinate frame, for use in plotting.
 
 class CAxis
@@ -40,5 +43,9 @@ public:
     void set_xgrid(std::vector<double>& x, int n) const;
     double pc(double v) const;
     double pcerr(double v, double dv) const;
-    void calc_ticks(std::vector<double>& Tacks, int* ntpt, double* ticklim) const;
+    void calc_ticks(std::vector<double>& Tacks, int& ntpt, int& nt4t, double* ticklim) const;
+private:
+    void calc_linticks(std::vector<double>& Tacks, int& ntpt, int& nt4t, double* ticklim) const;
+    void calc_lintacks(std::vector<double>& Tacks, int& ntpt, double& dtack) const;
+    void calc_logticks(std::vector<double>& Tacks, int& ntpt, int& nt4t, double* ticklim) const;
 };
diff --git a/pub/plot/dualplot.cpp b/pub/plot/dualplot.cpp
index 7c1667947f870dc81e903cf85648859bf8d1fe2b..b4ec369a678a66a6167e3991ac0f396eccb35dc4 100644
--- a/pub/plot/dualplot.cpp
+++ b/pub/plot/dualplot.cpp
@@ -5,94 +5,52 @@
 //**************************************************************************************************
 
 //! \file  dualplot.cpp
-//! \brief Collection NPlot of plot frames CPlot.
+//! \brief Implements class CPlot.
 
-#include <boost/format.hpp>
-#include <cmath>
-#include <cstring>
-#include <fcntl.h>
 #include <iostream>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
 
-#include "../trivia/file_ops.hpp"
 #include "../trivia/string_convs.hpp"
-
 #include "dualplot.hpp"
+#include "gnuplotter.hpp"
+#include "ps_plotter.hpp"
+
+#define S(a) triv::strg((a))
 
 using std::string;
 using std::vector;
 using std::cout;
-using boost::format;
-
-#define S(a) triv::strg((a))
-
-static const int mLin = 80; // max num of chars in PostScript line
-
 
 //! Constructor for plot window: setup for gnuplot and postscript.
 
-CPlot::CPlot(int _iPlot, bool _logx, bool _logy)
+CPlot::CPlot(int _iPlot, bool _logx, bool _logy, bool _p2D, bool _logz)
     : iPlot(_iPlot)
     , X("x", _logx)
     , Y("y", _logy)
+    , Z("UNUSED", _logz)
     , maxpoints(20000)
     , with_errors(true)
-    , equipoints(49)
+    , equipoints(120)
     , refine(true)
+    , gnuPlotter(new CGnuPlotter(iPlot))
+    , ps_Plotter(new CPS_Plotter)
 {
-    // == Initialization for Gnuplot ==
-
-    // Create a named pipe (FIFO) that will transmit our commands to Gnuplot.
-    string fn_fifo = "/tmp/gnuplot-" + S(getpid());
-    triv::system("rm -f " + fn_fifo);
-    if (mkfifo(fn_fifo.c_str(), 0666))
-        throw "SYSTEM ERROR cannot make fifo " + fn_fifo + ": will not be able to print";
-
-    // Check that Gnuplot supports X11.
-    string out = triv::system_read("gnuplot -e 'help X11' 2>&1 < /dev/null");
-    if (out.substr(0, 5) == "Sorry" || out.length() < 80) {
-        cout << "Gnuplot seems not to support X11\n";
-        exit(1);
-    }
-
-    // Start a Gnuplot that will read from our pipe.
-    triv::system("gnuplot -title " + S(iPlot) + " -noraise < " + fn_fifo + "&");
-
-    // Open our pipe so that we can write commands to it
-    //   (we use 'open' instead of 'fopen' or 'ofstream', because we need non-blocking mode).
-    if ((gp_fifo = open(fn_fifo.c_str(), O_WRONLY)) == -1)
-        throw "SYSTEM ERROR: cannot open fifo " + fn_fifo + " (" + strerror(errno) + ")";
-    fcntl(gp_fifo, F_SETFL, O_NONBLOCK);
-
-    // Now the initialization _within_ Gnuplot.
-    gp_write(string("set terminal x11"));
-
-    // == Initialization for PostScript ==
-    ps_fnum = 0;
+    set_dims(_p2D);
 }
 
+//! Sets 1D or 2D; sets axis names accordingly.
 
-//! Clear plot frame and buffer.
-
-void CPlot::clear_frame()
+void CPlot::set_dims(const bool _p2D)
 {
-    // clear gnuplot tmp files
-    gp_fno = 0;
-    gp_fnames = "";
-
-    // reset buffers for postscript output
-    string cmd;
-    ps_accu.clear();
-    ps_accu.push_back("\n%% output created by frida2\n");
-    ps_snum = 0;
-    ps_pnum = 0;
-    ps_cnum = 0;
-    ps_Doc.clear();
+    p2D = _p2D;
+    if (p2D) {
+        Y.name = "h";
+        Z.name = "y";
+    } else {
+        Y.name = "y";
+        Z.name = "UNUSED";
+    }
 }
 
-
 //! Change one setup parameter per command.
 
 void CPlot::set_aux(const string& cmd)
@@ -104,6 +62,7 @@ void CPlot::set_aux(const string& cmd)
         X.set_log(true);
     else if (cmd == "gxl-")
         X.set_log(false);
+
     else if (cmd == "gyl") {
         Y.set_log(!Y.logflag);
         printf("set y %s\n", Y.logflag ? "log" : "lin");
@@ -111,6 +70,15 @@ void CPlot::set_aux(const string& cmd)
         Y.set_log(true);
     else if (cmd == "gyl-")
         Y.set_log(false);
+
+    else if (cmd == "gzl") {
+        Z.set_log(!Z.logflag);
+        printf("set z %s\n", Z.logflag ? "log" : "lin");
+    } else if (cmd == "gzl+")
+        Z.set_log(true);
+    else if (cmd == "gzl-")
+        Z.set_log(false);
+
     else if (cmd == "gxf") {
         X.force = !X.force;
         printf("force x %s\n", X.force ? "on" : "off");
@@ -125,184 +93,98 @@ void CPlot::set_aux(const string& cmd)
         Y.force = true;
     else if (cmd == "gyf-")
         Y.force = false;
+
     else if (cmd == "ge")
         with_errors = !with_errors;
     else if (cmd == "ge+")
         with_errors = true;
     else if (cmd == "ge-")
         with_errors = false;
+
+    else if (cmd == "gt")
+        set_dims(!p2D);
+    else if (cmd == "gt+")
+        set_dims(true);
+    else if (cmd == "gt-")
+        set_dims(false);
+
     else
         throw "unknown command " + cmd;
 }
 
 
+//! Clear 1D plot canvas, and plot coordinate frame (axes, ticks, labels).
+
+void CPlot::start_frame1D(const string& caller, const string& xlabel, const string& ylabel)
+{
+    gnuPlotter->start_frame(X, Y);
+    ps_Plotter->start_frame1D(caller, X, Y, xlabel, ylabel);
+    open1D = true;
+}
+
+//! Start adding to plot.
+
+void CPlot::reopen_frame1D()
+{
+    if (!open1D)
+        throw S("plot frame is not open for adding");
+}
+
+//! Clear 2D plot canvas, and print coordinate ranges
+
+void CPlot::start_frame2D(const string& caller)
+{
+    ps_Plotter->start_frame2D(caller, X, Z, Y);
+}
+
+
 //! Plot coordinate frame (axes, ticks, labels).
 
-void CPlot::plot_frame(const string& xlabel, const string& ylabel)
+void CPlot::close_frame2D(const string& xlabel, const string& zlabel, const string& ylabel)
 {
-    gp_write("set nologscale");
-    string whichlog = "";
-    if (X.logflag)
-        whichlog += "x";
-    if (Y.logflag)
-        whichlog += "y";
-    if (whichlog != "")
-        gp_write("set logscale " + whichlog);
-
-    // wups:
-    char outlin[mLin];
-    snprintf(outlin, mLin, "\n%i %g %g xSetCoord\n", X.logflag, X.inf, X.sup);
-    ps_accu.push_back(outlin);
-    snprintf(outlin, mLin, "%i %g %g ySetCoord\n", Y.logflag, Y.inf, Y.sup);
-    ps_accu.push_back(outlin);
-    snprintf(outlin, mLin, "%% %i %g %g %i zSetCoord\n\n", 0, 0., 0., 0);
-    ps_accu.push_back(outlin);
-
-    int ntpt;
-    double ticklim[2];
-    vector<double> Tacks;
-    ps_accu.push_back("\n/xPlotFrame {\n");
-    if (X.logflag && X.inf <= 0)
-        throw "BUG: x log incompatible with limits " + X.str();
-    X.calc_ticks(Tacks, &ntpt, ticklim);
-    ps_ticktack(Tacks, ntpt, ticklim, &X);
-    snprintf(outlin, mLin - 4, "  {(%s", xlabel.c_str());
-    strncat(outlin, ")}\n", mLin);
-    ps_accu.push_back(outlin);
-    ps_accu.push_back("   0 10   0  0     0  90 "
-                      "OneAxx Axx Tic Tac xNumL %% low x axis\n");
-    ps_accu.push_back("   0 10   0 10     0 270 "
-                      "OneAxx Axx Tic Tac       %% top x axis\n");
-    ps_accu.push_back("  xCL\n");
-    ps_accu.push_back("} def\n");
-
-    ps_accu.push_back("\n/yPlotFrame {\n");
-    if (Y.logflag && Y.inf <= 0)
-        throw "BUG: y log incompatible with limits " + Y.str();
-    Y.calc_ticks(Tacks, &ntpt, ticklim);
-    ps_ticktack(Tacks, ntpt, ticklim, &Y);
-    snprintf(outlin, mLin - 4, "   {(%s", ylabel.c_str());
-    strncat(outlin, ")}\n", mLin);
-    ps_accu.push_back(outlin);
-    ps_accu.push_back("   0 10   0  0    90   0 "
-                      "OneAxx Axx Tic Tac yNumL %% left y axis\n");
-    ps_accu.push_back("   0 10  10  0    90 180 "
-                      "OneAxx Axx Tic Tac       %% right y axis\n");
-    ps_accu.push_back("  yCL\n");
-    ps_accu.push_back("} def\n");
-    ps_accu.push_back("\n%% modeDD\nplotbefore\n");
+    ps_Plotter->close_frame2D(X, Z, Y, xlabel, zlabel, ylabel);
 }
 
 
 //! Plot one spectrum.
 
 void CPlot::add_spec(
-    bool as_line, bool new_style, int style_no, const vector<double>& xp, const vector<double>& yp,
-    const vector<double>& dyp, const vector<string>& z, const string& xco, const string& yco,
-    const string& info)
+    bool as_line, bool new_slice, int style_no, const vector<double>& xp, const vector<double>& yp,
+    const vector<double>& dyp, const vector<string>& zentries,
+    const string& xco, const string& yco, const string& info)
 {
-    static const int mColor = 6;
-    static int color[mColor] = { 0x880000, 0x008800, 0x000088, 0x006666, 0x660066, 0x666600 };
-    // Checks:
-    int np = xp.size();
-    if (!np)
-        throw S("invalid call to CPLot::addSpec: no data points");
-    if (np != yp.size())
-        throw S("invalid call to CPLot::addSpec: x.size<>y.size");
-
-    // Prepare for live display, to be shown by showSpecs():
-    string gp_fnam = str(format("/tmp/%s-%i-%03i.gnu") % getenv("LOGNAME") % iPlot % gp_fno++);
-    if (gp_fnames != "")
-        gp_fnames += ", ";
-    gp_fnames += string("\"") + gp_fnam + "\" notitle";
-    if (as_line)
-        gp_fnames += str(format(" with lines lt 1 lc rgb \"#%6x\"") % color[style_no % mColor]);
-    else if (with_errors && dyp.size())
-        gp_fnames += " with errorbars";
-    FILE* gp_fd;
-    if (!(gp_fd = fopen(gp_fnam.c_str(), "w")))
-        throw "cannot save gnuplot data to " + gp_fnam;
-    int nout = 0;
-    try {
-        for (int i = 0; i < np; i++) {
-            if (std::isinf(xp[i]) || std::isinf(yp[i]))
-                throw "Data point number " + S(i) + " is invalid: x=" + S(xp[i]) + ", y="
-                    + S(yp[i]);
-            if (xp[i] < X.inf || xp[i] > X.sup)
-                throw "CPlot::addSpec: x[" + S(i) + "]=" + S(xp[i]) + " out of range";
-            if (yp[i] < Y.inf || yp[i] > Y.sup)
-                throw "CPlot::addSpec: y[" + S(i) + "]=" + S(yp[i]) + " out of range";
-            if (with_errors && dyp.size())
-                fprintf(gp_fd, "%20.13g %20.13g %20.13g\n", xp[i], yp[i], dyp[i]);
-            else
-                fprintf(gp_fd, "%20.13g %20.13g\n", xp[i], yp[i]);
-            nout++;
-        }
-    } catch (string& s) {
-        fclose(gp_fd);
-        throw s;
-    } catch (...) {
-        fclose(gp_fd);
-        throw "BUG: unexpected exception type";
-    }
-    fclose(gp_fd);
-    if (!nout)
-        throw "no points in frame: " + info;
-
-    // Postscript copy:
-    char outlin[mLin];
-    if (new_style) {
-        snprintf(outlin, mLin, "\n%3u [", ++ps_snum);
-        ps_accu.push_back(outlin);
-        for (int i = 0; i < z.size(); i++) {
-            snprintf(outlin, mLin, " %s", z[i].c_str());
-            ps_accu.push_back(outlin);
-        }
-        snprintf(outlin, mLin, " ] zValues\n");
-        ps_accu.push_back(outlin);
-        if (as_line)
-            snprintf(outlin, mLin, "%2i cstyle", style_no);
-        else
-            snprintf(outlin, mLin, "%2i pstyle", style_no);
-        ps_accu.push_back(outlin);
-        snprintf(outlin, mLin - 2, " %% (%s -> %s)", xco.c_str(), yco.c_str());
-        strncat(outlin, "\n", mLin);
-        ps_accu.push_back(outlin);
-    } else {
-        ps_accu.push_back("\n");
-    }
-    for (int i = 0; i < np; i++) {
-        snprintf(
-            outlin, mLin, "%8.5f %8.5f %8.5f t%c %% %13.7g wx %13.7g wy\n", X.pc(xp[i]),
-            Y.pc(yp[i]), dyp.size() ? Y.pcerr(yp[i], dyp[i]) : 0,
-            i == 0 ? 'i' : i == np - 1 ? 'f' : ' ', xp[i], yp[i]);
-        ps_accu.push_back(outlin);
-    }
+    gnuPlotter->add_spec(
+        as_line, new_slice, with_errors,
+        style_no, xp, yp, dyp, zentries, xco, yco, info);
+    ps_Plotter->add_spec(
+        as_line, new_slice,
+        style_no, xp, yp, dyp, zentries, xco, yco, info);
 }
 
-
-//! Live display as prepared by addSpec.
+//! Plot one bin of 2D plot.
+void CPlot::ps_line(const string& line)
+{
+    ps_Plotter->main_line(line);
+}
 
 void CPlot::show_specs()
 {
-    if (gp_fnames != "")
-        gp_write(
-            "plot "
-            + str(format("[%12.8g:%12.8g] [%12.8g:%12.8g] ") % X.inf % X.sup % Y.inf % Y.sup)
-            + gp_fnames);
+    gnuPlotter->show_specs();
 }
 
-
 //! Add documentation line to postscript output.
 
-void CPlot::doc_TxLine(const string& line) { ps_Doc.push_back("  {(" + line + ")} TxLine"); }
+void CPlot::doc_TxLine(const string& line)
+{
+    ps_Plotter->doc_line("  {(" + line + ")} TxLine");
+}
 
 
 //! Add documentation line explaining a plot symbol to postscript output.
 
 void CPlot::doc_PtTxLine(const string& line, int num)
 {
-    ps_Doc.push_back("  " + S(num) + " {(" + line + ")} PtTxLine");
+    ps_Plotter->doc_line("  " + S(num) + " {(" + line + ")} PtTxLine");
 }
 
 
@@ -310,65 +192,27 @@ void CPlot::doc_PtTxLine(const string& line, int num)
 
 void CPlot::doc_CvTxLine(const string& line, int num)
 {
-    ps_Doc.push_back("  " + S(num) + " {(" + line + ")} CvTxLine");
+    ps_Plotter->doc_line("  " + S(num) + " {(" + line + ")} CvTxLine");
 }
 
 
 //! Write buffered plot to postscript file.
 
-void CPlot::write_postscript(const string& ps_outdir, const string& ps_head, const string& ps_dict)
+void CPlot::write_postscript(
+    const string& fname, const string& mode, const bool withDefs,
+    std::map<const string, string>&& settings)
 {
-    // construct output file name:
-    FILE* pssav;
-    string cmd, outf;
-    while (1) {
-        if (ps_fnum >= 999)
-            throw S("graph file number overflow");
-        outf = triv::wordexp_unique(
-            ps_outdir + str(format("l%i") % ++ps_fnum) + "." + (ps_dict == "" ? "psa" : "ps"));
-        if (!triv::file_exists(outf.c_str()))
-            break; // legal exit
-    }
-    cout << "save plot in " << outf << "\n";
-
-    // copy headers to output file:
-    cmd = string("cat ") + ps_dict + " " + // ps_dict may be ""
-        ps_head + " > " + outf + "\n";
-    triv::system(cmd);
-
-    // append specific output to output file:
-    if (!(pssav = fopen(outf.c_str(), "a+")))
-        throw "cannot append contents to file " + outf;
-    for (string lin : ps_accu) {
-        // fprintf does not work here because output line may contain "%"
-        fwrite(lin.c_str(), 1, lin.size(), pssav);
-    }
-
-    // additional output (do not append this to ps_accu to allow
-    // further incrementation of ps_accu):
-    fprintf(pssav, "\n{ black 0 -4 13 1.65 NewList\n");
-    for (string lin : ps_Doc)
-        fprintf(pssav, "%s\n", lin.c_str());
-    fprintf(pssav, "} oooinfo 1 eq { exec } { pop } ifelse\n");
-
-    fprintf(
-        pssav, "\n{(%s)}  /filename exch def 10 -2.8 18 showfilename\n\n"
-               " EndFrame\n",
-        outf.c_str());
-
-    // output completed:
-    fclose(pssav);
+    ps_Plotter->copy_header(fname, mode, withDefs, settings);
+    ps_Plotter->write_data(fname);
 }
 
-
 //! Info line to characterize this plot window.
 
 string CPlot::info() const
 {
-    string ret;
-    ret = "x: " + X.info();
-    ret += "  y: " + Y.info();
-    return ret;
+    if ( p2D )
+        return "2D  x: " + X.info() +  "  z: " + Z.info() + "  y: " + Y.info();
+    return "1D  x: " + X.info() +  "  y: " + Y.info();
 }
 
 
@@ -376,40 +220,5 @@ string CPlot::info() const
 
 void CPlot::gp_write(const string& in)
 {
-    string out = in + "\n";
-    // cout << "monitor gnuplot driver: '" << out << "'\n";
-    if (write(gp_fifo, out.c_str(), out.size()) <= 0)
-        throw S("could not write to gp_fifo");
-}
-
-
-//! Format ticks and tacks for postscript file.
-
-void CPlot::ps_ticktack(
-    const vector<double>& Tacks, int ntpt, const double* ticklim, const CAxis* A)
-{
-    char outlin[mLin];
-    int i, ntack;
-    ntack = Tacks.size();
-    if (ntack > 0) {
-        ps_accu.push_back("  [\n");
-        if (A->logflag && (Tacks[0] < 1e-3 || Tacks[ntack - 1] > 1e3)) {
-            for (i = 0; i < ntack; i++) {
-                snprintf(
-                    outlin, mLin, "   %9.6f {(10)(%i)sp()} %%{(%g)}\n", A->pc(Tacks[i]),
-                    (int)(log10(Tacks[i])), (float)Tacks[i]);
-                ps_accu.push_back(outlin);
-            }
-        } else {
-            for (i = 0; i < ntack; i++) {
-                snprintf(outlin, mLin, "   %9.6f {(%g)}\n", A->pc(Tacks[i]), (float)Tacks[i]);
-                ps_accu.push_back(outlin);
-            }
-        }
-        ps_accu.push_back("  ] SetTacVec\n");
-    }
-    snprintf(
-        outlin, mLin, "  %g %g %i %i SetTicVec%s\n", A->pc(ticklim[0]), A->pc(ticklim[1]),
-        ntack + 2, ntpt, (A->logflag ? "Log" : "Lin"));
-    ps_accu.push_back(outlin);
+    gnuPlotter->write(in);
 }
diff --git a/pub/plot/dualplot.hpp b/pub/plot/dualplot.hpp
index ad1bc784fa5a43d48db4a182c8a04bcf140729d5..ea79c7afb80e7b8c8710861db01fe494c9f24d66 100644
--- a/pub/plot/dualplot.hpp
+++ b/pub/plot/dualplot.hpp
@@ -5,19 +5,28 @@
 //**************************************************************************************************
 
 //! \file  dualplot.hpp
-//! \brief Collection NPlot of plot frames CPlot.
+//! \brief Declares class CPlot.
 
+#include <map>
+#include <memory>
 #include "axis.hpp"
 
-
 //! One plot frame.
 
 class CPlot
 {
 public:
+    CPlot(int _iPlot, bool _logx, bool _logy, bool _p2D, bool _logz);
+    CPlot(int _iPlot, bool _logx, bool _logy) : CPlot(_iPlot, _logx, _logy, false, false) {}
+    CPlot(int _iPlot) : CPlot(_iPlot, false, false) {}
+    CPlot(CPlot const&) = delete;
+    CPlot& operator=(CPlot const&) = delete;
+
     int iPlot; //!< The index of this frame in NPloWin::Plots.
+    bool p2D; //!< Two-dimensional color plot?
     CAxis X; //!< Limits, log flag &c for x axis.
     CAxis Y; //!< Limits, log flag &c for y axis.
+    CAxis Z; //!< Limits, log flag &c for z axis in 2D plot.
     // For data plotting:
     int maxpoints; //!< Maximum # points to be plotted without reduction.
     bool with_errors; //!< Plot error bars?
@@ -25,38 +34,33 @@ public:
     int equipoints; //!< Start curve plot with this # grid points.
     bool refine; //!< Refine curve plot when appropriate?
 
-    CPlot(int _iPlot, bool _logx, bool _logy);
+    void set_dims(const bool _p2D);
+    void set_aux(const std::string& cmd);
 
     void gp_write(const std::string& in);
-    void clear_frame();
-    void plot_frame(const std::string& xlabel, const std::string& ylabel);
+    void start_frame1D(
+        const std::string& caller, const std::string& xlabel, const std::string& ylabel);
+    void reopen_frame1D();
+    void start_frame2D(const std::string& caller);
+    void close_frame2D(
+        const std::string& xlabel, const std::string& zlabel, const std::string& ylabel);
     void add_spec(
-        bool as_line, bool new_style, int style_no, const std::vector<double>& xp,
+        bool as_line, bool new_slice, int style_no, const std::vector<double>& xp,
         const std::vector<double>& yp, const std::vector<double>& dyp,
-        const std::vector<std::string>& z, const std::string& xco, const std::string& yco,
+        const std::vector<std::string>& zentries, const std::string& xco, const std::string& yco,
         const std::string& info);
+    void ps_line(const std::string& line);
     void show_specs();
     void doc_TxLine(const std::string& line);
     void doc_PtTxLine(const std::string& line, int num);
     void doc_CvTxLine(const std::string& line, int num);
     void write_postscript(
-        const std::string& ps_outdir, const std::string& ps_head, const std::string& ps_dict);
-    void set_aux(const std::string& cmd);
+        const std::string& fname, const std::string& mode, const bool withDefs,
+        std::map<const std::string, std::string>&& settings);
     std::string info() const;
 
 private:
-    // TODO: some of this could be made local static, if class instances
-    // are created anew instead of calling clearFrame().
-    int gp_fifo; //!< Pipe to Gnuplot.
-    int gp_fno; //!< Number of Gnuplot input file.
-    std::string gp_fnames; //!< List of currently plotted Gnuplot input file names.
-
-    int ps_fnum; //!< Postscript output file number.
-    int ps_snum; //!< Slice number in Postscript file.
-    int ps_pnum; //!< Spectrum number, for setting pstyle.
-    int ps_cnum; //!< Curve number, for setting cstyle.
-    void
-    ps_ticktack(const std::vector<double>& Tacks, int ntpt, const double* ticklim, const CAxis* A);
-    std::vector<std::string> ps_accu; //!< Main Postscript cache.
-    std::vector<std::string> ps_Doc; //!< Special Postscript cache for doc lines ?.
+    std::shared_ptr<class CGnuPlotter> gnuPlotter;
+    std::shared_ptr<class CPS_Plotter> ps_Plotter;
+    bool open1D = false;
 };
diff --git a/pub/plot/gnuplotter.cpp b/pub/plot/gnuplotter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..346942b05650da619c5f4cb7a225aec112e2fa2d
--- /dev/null
+++ b/pub/plot/gnuplotter.cpp
@@ -0,0 +1,146 @@
+//**************************************************************************************************
+//*  FRIDA: fast reliable interactive data analysis
+//*  (C) Joachim Wuttke 1990-, v2(C++) 2001-
+//*  http://apps.jcns.fz-juelich.de/frida
+//**************************************************************************************************
+
+//! \file  gnuplotter.cpp
+//! \brief Implements class CGnuPlotter.
+
+#include <cmath>
+#include <cstring>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <boost/format.hpp>
+
+#include "../trivia/file_ops.hpp"
+#include "../trivia/string_convs.hpp"
+
+#include "axis.hpp"
+#include "gnuplotter.hpp"
+
+#define S(a) triv::strg((a))
+
+using std::string;
+using std::vector;
+using boost::format;
+
+
+CGnuPlotter::CGnuPlotter(int _iPlot)
+    : iPlot(_iPlot)
+{
+    // Create a named pipe (FIFO) that will transmit our commands to Gnuplot.
+    string fn_fifo = "/tmp/gnuplot-" + S(getpid());
+    triv::system("rm -f " + fn_fifo);
+    if (mkfifo(fn_fifo.c_str(), 0666))
+        throw "SYSTEM ERROR cannot make fifo " + fn_fifo + ": will not be able to print";
+
+    // Check that Gnuplot supports X11.
+    string out = triv::system_read("gnuplot -e 'help X11' 2>&1 < /dev/null");
+    if (out.substr(0, 5) == "Sorry" || out.length() < 80)
+        throw "Gnuplot seems not to support X11";
+
+    // Start a Gnuplot that will read from our pipe.
+    triv::system("gnuplot -title " + S(iPlot) + " -noraise < " + fn_fifo + "&");
+
+    // Open our pipe so that we can write commands to it
+    //   (we use 'open' instead of 'fopen' or 'ofstream', because we need non-blocking mode).
+    if ((gp_fifo = open(fn_fifo.c_str(), O_WRONLY)) == -1)
+        throw "SYSTEM ERROR: cannot open fifo " + fn_fifo + " (" + strerror(errno) + ")";
+    fcntl(gp_fifo, F_SETFL, O_NONBLOCK);
+
+    // Now the initialization _within_ Gnuplot.
+    write("set terminal x11");
+}
+
+//! Send one line to gnuplot fifo.
+
+void CGnuPlotter::write(const string& in)
+{
+    string out = in + "\n";
+    if (::write(gp_fifo, out.c_str(), out.size()) <= 0)
+        throw S("could not write to gp_fifo");
+}
+
+void CGnuPlotter::start_frame(const CAxis& _X, const CAxis& _Y)
+{
+    X = &_X;
+    Y = &_Y;
+    gp_fno = 0;
+    gp_fnames = "";
+    write("set nologscale");
+    string whichlog = "";
+    if (X->logflag)
+        whichlog += "x";
+    if (Y->logflag)
+        whichlog += "y";
+    if (whichlog != "")
+        write("set logscale " + whichlog);
+}
+
+void CGnuPlotter::add_spec(
+    bool as_line, bool new_slice, bool plot_errorbars, int style_no,
+    const vector<double>& xp, const vector<double>& yp, const vector<double>& dyp,
+    const vector<string>& zentries,
+    const string& xco, const string& yco, const string& info)
+{
+    static const int mColor = 6;
+    static int color[mColor] = { 0x880000, 0x008800, 0x000088, 0x006666, 0x660066, 0x666600 };
+    // Checks:
+    int np = xp.size();
+    if (!np)
+        throw S("invalid call to CPLot::addSpec: no data points");
+    if (np != yp.size())
+        throw S("invalid call to CPLot::addSpec: x.size<>y.size");
+
+    // Prepare for live display, to be shown by showSpecs():
+    string gp_fnam = str(format("/tmp/%s-%i-%03i.gnu") % getenv("LOGNAME") % iPlot % gp_fno++);
+    if (gp_fnames != "")
+        gp_fnames += ", ";
+    gp_fnames += string("\"") + gp_fnam + "\" notitle";
+    if (as_line)
+        gp_fnames += str(format(" with lines lt 1 lc rgb \"#%6x\"") % color[style_no % mColor]);
+    else if (plot_errorbars && dyp.size())
+        gp_fnames += " with errorbars";
+    FILE* gp_fd;
+    if (!(gp_fd = fopen(gp_fnam.c_str(), "w")))
+        throw "cannot save gnuplot data to " + gp_fnam;
+    int nout = 0;
+    try {
+        for (int i = 0; i < np; i++) {
+            if (std::isinf(xp[i]) || std::isinf(yp[i]))
+                throw "Data point number " + S(i) + " is invalid: x=" + S(xp[i]) + ", y="
+                    + S(yp[i]);
+            if (xp[i] < X->inf || xp[i] > X->sup)
+                throw "CPlot::addSpec: x[" + S(i) + "]=" + S(xp[i]) + " out of range";
+            if (yp[i] < Y->inf || yp[i] > Y->sup)
+                throw "CPlot::addSpec: y[" + S(i) + "]=" + S(yp[i]) + " out of range";
+            if (plot_errorbars && dyp.size())
+                fprintf(gp_fd, "%20.13g %20.13g %20.13g\n", xp[i], yp[i], dyp[i]);
+            else
+                fprintf(gp_fd, "%20.13g %20.13g\n", xp[i], yp[i]);
+            nout++;
+        }
+    } catch (string& s) {
+        fclose(gp_fd);
+        throw s;
+    } catch (...) {
+        fclose(gp_fd);
+        throw "BUG: unexpected exception type";
+    }
+    fclose(gp_fd);
+    if (!nout)
+        throw "no points in frame: " + info;
+}
+
+//! Live display as prepared by addSpec.
+
+void CGnuPlotter::show_specs()
+{
+    if (gp_fnames == "")
+        return;
+    write(str(format("plot [%12.8g:%12.8g] [%12.8g:%12.8g] ") % X->inf % X->sup % Y->inf % Y->sup)
+          + gp_fnames);
+}
diff --git a/pub/plot/gnuplotter.hpp b/pub/plot/gnuplotter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c214c03a93483ee9c7af16c504f28f0512ac7436
--- /dev/null
+++ b/pub/plot/gnuplotter.hpp
@@ -0,0 +1,35 @@
+//**************************************************************************************************
+//*  FRIDA: fast reliable interactive data analysis
+//*  (C) Joachim Wuttke 1990-, v2(C++) 2001-
+//*  http://apps.jcns.fz-juelich.de/frida
+//**************************************************************************************************
+
+//! \file  gnuplotter.hpp
+//! \brief Declares class CGnuPlotter
+
+#include <string>
+#include <vector>
+
+class CAxis;
+
+class CGnuPlotter {
+public:
+    CGnuPlotter(int _iPlot);
+    CGnuPlotter(CGnuPlotter const&) = delete;
+    CGnuPlotter& operator=(CGnuPlotter const&) = delete;
+    void write(const std::string& in);
+    void start_frame(const CAxis& _X, const CAxis& _Y);
+    void add_spec(
+        bool as_line, bool new_slice, bool plot_errorbars, int style_no,
+        const std::vector<double>& xp, const std::vector<double>& yp,
+        const std::vector<double>& dyp, const std::vector<std::string>& zentries,
+        const std::string& xco, const std::string& yco, const std::string& info);
+    void show_specs();
+private:
+    const CAxis* X;
+    const CAxis* Y;
+    int iPlot;
+    int gp_fifo; //!< Pipe to Gnuplot.
+    int gp_fno; //!< Number of Gnuplot input file.
+    std::string gp_fnames; //!< List of currently plotted Gnuplot input file names.
+};
diff --git a/pub/plot/plowin.cpp b/pub/plot/plowin.cpp
index 9bba7e13504091af26cedcca980888aeda1bc68e..73d1efda7d53504249f1e9df62098cc1753c7306 100644
--- a/pub/plot/plowin.cpp
+++ b/pub/plot/plowin.cpp
@@ -25,6 +25,7 @@ void SPloWin::initialize()
     m->Plots.push_back(new CPlot(m->nPlot(), true, false));
     m->Plots.push_back(new CPlot(m->nPlot(), false, true));
     m->Plots.push_back(new CPlot(m->nPlot(), true, true));
+    m->Plots.push_back(new CPlot(m->nPlot(), false, false, true, false));
     m->iPlot = 0; // current plot window
 }
 
@@ -36,7 +37,7 @@ void SPloWin::select(int i)
         iPlot = i;
     else if (i == nPlot()) {
         iPlot = i;
-        Plots.push_back(new CPlot(nPlot(), false, false));
+        Plots.push_back(new CPlot(nPlot()));
     } else
         throw std::string("invalid graphic window number");
 }
diff --git a/pub/plot/ps_plotter.cpp b/pub/plot/ps_plotter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..caf204fa120e8cef35256f161fccbe4c916da932
--- /dev/null
+++ b/pub/plot/ps_plotter.cpp
@@ -0,0 +1,284 @@
+//**************************************************************************************************
+//*  FRIDA: fast reliable interactive data analysis
+//*  (C) Joachim Wuttke 1990-, v2(C++) 2001-
+//*  http://apps.jcns.fz-juelich.de/frida
+//**************************************************************************************************
+
+//! \file  gnuplotter.cpp
+//! \brief Implements class CPS_Plotter.
+
+#include <cmath>
+#include <fstream>
+#include <iostream>
+#include <boost/format.hpp>
+
+#include "../trivia/file_ops.hpp"
+#include "../trivia/string_convs.hpp"
+
+#include "axis.hpp"
+#include "ps_plotter.hpp"
+
+using std::string;
+using std::vector;
+using boost::format;
+
+namespace {
+    string ps_ticktack(const CAxis* A);
+    string ps_coord(const CAxis* A);
+    string ps_axis(const CAxis* A);
+    string ps_horiz(const string& label);
+    string ps_verti(const string& label);
+    string ps_colorscale(const string& label);
+    string ps_slice_header(
+        bool as_line, int slice_no, int style_no, const vector<string>& zentries,
+        const string& xco, const string& yco);
+    string ps_data_block(
+        const CAxis* X, const CAxis* Y,
+        const vector<double>& xp, const vector<double>& yp, const vector<double>& dyp);
+    string ps_footer(
+        const string& fname, const string& doc_lines);
+}
+
+void CPS_Plotter::start_frame1D(
+    const string& caller, const CAxis& _X, const CAxis& _Y,
+    const string& xlabel, const string& ylabel)
+{
+    p2D = false;
+    X = &_X;
+    Y = &_Y;
+    ps_snum = 0;
+    ps_Doc = "";
+    ps_accu = "\n%% output created by " + caller + "\n\n";
+    ps_accu += ps_coord(X);
+    ps_accu += ps_coord(Y);
+    ps_accu += "\n";
+    ps_accu += ps_axis(X) + ps_horiz(xlabel);
+    ps_accu += ps_axis(Y) + ps_verti(ylabel);
+    ps_accu += "\n";
+}
+
+void CPS_Plotter::start_frame2D(
+    const std::string& caller, const CAxis& _X, const CAxis& _Z, const CAxis& _Y)
+{
+    p2D = true;
+    X = &_X;
+    Z = &_Z;
+    Y = &_Y;
+    ps_snum = 0;
+    ps_Doc = "";
+    ps_accu = "\n%% output created by " + caller + "\n\n";
+    ps_accu += ps_coord(X);
+    ps_accu += ps_coord(Z);
+    ps_accu += ps_coord(Y);
+    ps_accu += "\n%% 2D image begin\n";
+}
+
+void CPS_Plotter::close_frame2D(
+    const CAxis& _X, const CAxis& _Z, const CAxis& _Y,
+    const std::string& xlabel, const std::string& zlabel, const std::string& ylabel)
+{
+    ps_accu += "%% 2D image end\n\n";
+    ps_accu += "/linsetTic {white 1 setline} def\n";
+    ps_accu += "/linsetTac {white 1.3 setline} def\n\n";
+
+    ps_accu += ps_axis(X) + ps_horiz(xlabel);
+    ps_accu += ps_axis(Z) + ps_verti(zlabel);
+    ps_accu += ps_axis(Y) + ps_colorscale(ylabel);
+}
+
+void CPS_Plotter::add_spec(
+    bool as_line, bool new_slice, int style_no,
+    const vector<double>& xp, const vector<double>& yp,
+    const vector<double>& dyp, const vector<string>& zentries,
+    const string& xco, const string& yco, const string& info)
+{
+
+    // Postscript copy:
+    if (new_slice)
+        ps_accu += ps_slice_header(as_line, ++ps_snum, style_no, zentries, xco, yco);
+    else
+        ps_accu += "\n";
+
+    ps_accu += ps_data_block(X, Y, xp, yp, dyp);
+}
+
+void CPS_Plotter::main_line(const string& line)
+{
+    ps_accu += line + "\n";
+}
+
+void CPS_Plotter::doc_line(const string& line)
+{
+    ps_Doc += line + "\n";
+}
+
+void CPS_Plotter::copy_header(
+    const string& fname, const string& mode, const bool withDefs,
+    std::map<const string, string>& settings)
+{
+    // copy headers to output file
+    string cmd;
+    if (mode=="append") {
+        if (!triv::file_exists(fname))
+            throw "Cannot append graphic: file " + fname + " not found";
+        cmd = "cat " + settings.at("ps_continuation") + " >> " + fname;
+    } else {
+        if (mode=="create") {
+            if (triv::file_exists(fname))
+                throw "File " + fname + " already exists. "
+                    + "Use command suffix '!' to overwrite";
+        } else if (mode=="overwrite") {
+        } else
+            throw "BUG: unexpected mode";
+        cmd = "cat ";
+        if (withDefs)
+            cmd += settings.at("ps_definitions") + " ";
+        cmd += settings.at(string("ps_setup") + (p2D ? "2" : "1") + "D") + " > " + fname;
+    }
+    triv::system(cmd);
+}
+
+void CPS_Plotter::write_data(const string& fname)
+{
+    // append specific output to output file:
+    if (!triv::file_exists(fname))
+        throw "BUG: after copying headers, graphic output file " + fname + " still doesn't exist";
+    std::fstream fs(fname, std::fstream::out | std::fstream::app);
+    fs << ps_accu;
+    fs << ps_footer(fname, ps_Doc);
+    fs.close();
+}
+
+//**************************************************************************************************
+//  static functions
+//**************************************************************************************************
+
+namespace {
+
+    //! Format ticks and tacks for postscript file.
+    string ps_ticktack(const CAxis* A)
+    {
+        vector<double> Tacks;
+        int ticks_per_tack;
+        int ntacks4ticks;
+        double ticklim[2];
+        A->calc_ticks(Tacks, ticks_per_tack, ntacks4ticks, ticklim);
+
+        string ret;
+        int ntack = Tacks.size();
+        ret += "[\n";
+        if (!ntack)
+            ; // do nothing
+        else if (A->logflag && (Tacks.front() < 1e-3 || Tacks.back() > 1e3)) {
+            for (int i = 0; i < ntack; i++)
+                ret += str(format("  %g w%s {(10)(%i)sp()} %%{(%g)}\n")
+                           % (float)Tacks[i]
+                           % A->name
+                           % (int)(log10(Tacks[i]))
+                           % (float)Tacks[i]);
+        } else {
+            for (int i = 0; i < ntack; i++)
+                ret += str(format("  %g w%s {(%g)}\n")
+                           % (float)Tacks[i]
+                           % A->name
+                           % (float)Tacks[i]);
+        }
+        ret += "  ] SetTacVec\n";
+        ret += str(format("%g w%s %g w%s %i %i SetTicVec%s\n")
+                   % (float)ticklim[0]
+                   % A->name
+                   % (float)ticklim[1]
+                   % A->name
+                   % ntacks4ticks
+                   % ticks_per_tack
+                   % (A->logflag ? "Log" : "Lin"));
+        return ret;
+    }
+
+    string ps_coord(const CAxis* A)
+    {
+        return str(format("%1i %g %g %cSetCoord\n")
+                   % A->logflag % A->inf % A->sup % A->name);
+    }
+
+    string ps_axis(const CAxis* A)
+    {
+        string ret = "% " + A->name + " axis:\n";
+        if (A->logflag && A->inf <= 0)
+            throw "BUG: log incompatible with limits " + A->str();
+        ret += ps_ticktack(A);
+        return ret;
+    }
+
+    string ps_horiz(const string& label)
+    {
+        return
+            " 0 10   0  0     0  90 OneAxx Axx Tic Tac xNumL %% low x axis\n"
+            " 0 10   0 10     0 270 OneAxx Axx Tic Tac       %% top x axis\n"
+            "{(" + label + ")} xCL\n\n";
+    }
+
+    string ps_verti(const string& label)
+    {
+        return
+            " 0 10   0  0    90   0 OneAxx Axx Tic Tac yNumL %% left y axis\n"
+            " 0 10  10  0    90 180 OneAxx Axx Tic Tac       %% right y axis\n"
+            "{(" + label + ")} yCL\n\n";
+    }
+
+    string ps_colorscale(const string& label)
+    {
+        return
+            "ColorLegend\n"
+            " hxlow hxhig 0  0     0  90 OneAxx Axx %% low x line\n"
+            " hxlow hxhig 0 10     0  90 OneAxx Axx %% low x line\n"
+            " 0 10  hxlow 0    90   0 OneAxx Tic Tac Axx       %% left y axis\n"
+            " 0 10  hxhig 0    90 180 OneAxx Tic Tac Axx yNumH %% right y axis\n"
+            "{(" + label + ")} hxhig YCH\n\n";
+    }
+
+    string ps_slice_header(
+        bool as_line, int slice_no, int style_no, const vector<string>& zentries,
+        const string& xco, const string& yco)
+    {
+        string ret;
+        ret += str(format("%3u [") % slice_no);
+        for (string zentry: zentries)
+            ret += " " + zentry;
+        ret += " ] zValues\n";
+        ret += str(format("%2i %cstyle %% (%s -> %s)\n")
+                   % style_no
+                   % (as_line ? 'c' : 'p')
+                   % xco
+                   % yco);
+        return ret;
+    }
+
+    string ps_data_block(
+        const CAxis* X, const CAxis* Y,
+        const vector<double>& xp, const vector<double>& yp, const vector<double>& dyp)
+    {
+        string ret;
+        int np = xp.size();
+        for (int i = 0; i < np; i++)
+            ret += str(format("%8.5f %8.5f %8.5f t%c %% %13.7g wx %13.7g wy\n")
+                       % X->pc(xp[i])
+                       % Y->pc(yp[i])
+                       % (dyp.size() ? Y->pcerr(yp[i], dyp[i]) : 0)
+                       % (i == 0 ? 'i' : i == np - 1 ? 'f' : ' ')
+                       % xp[i]
+                       % yp[i]);
+        ret += "\n";
+        return ret;
+    }
+
+    string ps_footer(const string& fname, const string& doc_lines)
+    {
+        return "{ black 0 -3 13 1.65 NewList\n"
+            + doc_lines
+            + "  {(plot -> " + fname + ")} TxLine\n"
+            + "} oooinfo 1 eq { exec } { pop } ifelse\n\n"
+            + "EndFrame\n";
+    }
+
+} // anonymous namespace
diff --git a/pub/plot/ps_plotter.hpp b/pub/plot/ps_plotter.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..edc39be074064a123d01d459ee919fbc58bb92a2
--- /dev/null
+++ b/pub/plot/ps_plotter.hpp
@@ -0,0 +1,48 @@
+//**************************************************************************************************
+//*  FRIDA: fast reliable interactive data analysis
+//*  (C) Joachim Wuttke 1990-, v2(C++) 2001-
+//*  http://apps.jcns.fz-juelich.de/frida
+//**************************************************************************************************
+
+//! \file  ps_plotter.hpp
+//! \brief Declares class CPS_Plotter
+
+#include <map>
+#include <string>
+#include <vector>
+
+class CAxis;
+
+class CPS_Plotter {
+public:
+    CPS_Plotter() {}
+    CPS_Plotter(CPS_Plotter const&) = delete;
+    CPS_Plotter& operator=(CPS_Plotter const&) = delete;
+    void start_frame1D(
+        const std::string& caller, const CAxis& _X, const CAxis& _Y,
+        const std::string& xlabel, const std::string& ylabel);
+    void start_frame2D(
+        const std::string& caller, const CAxis& _X, const CAxis& _Z, const CAxis& _Y);
+    void close_frame2D(
+        const CAxis& _X, const CAxis& _Z, const CAxis& _Y,
+        const std::string& xlabel, const std::string& zlabel, const std::string& ylabel);
+    void add_spec(
+        bool as_line, bool new_slice, int style_no,
+        const std::vector<double>& xp, const std::vector<double>& yp,
+        const std::vector<double>& dyp, const std::vector<std::string>& zentries,
+        const std::string& xco, const std::string& yco, const std::string& info);
+    void main_line(const std::string& line);
+    void doc_line(const std::string& line);
+    void copy_header(
+        const std::string& fname, const std::string& mode, const bool withDefs,
+        std::map<const std::string, std::string>& settings);
+    void write_data(const std::string& fname);
+private:
+    bool p2D;
+    const CAxis* X;
+    const CAxis* Y;
+    const CAxis* Z;
+    int ps_snum; //!< Slice number in Postscript file.
+    std::string ps_accu; //!< Main Postscript cache.
+    std::string ps_Doc; //!< Special Postscript cache for doc lines ?.
+};
diff --git a/pub/readplus/CMakeLists.txt b/pub/readplus/CMakeLists.txt
index b710eefa48576d9a6e9f1c4fece375b12fb691fc..45d7b4c348782d40b1b87cc89f75207101f57979 100644
--- a/pub/readplus/CMakeLists.txt
+++ b/pub/readplus/CMakeLists.txt
@@ -1,23 +1,27 @@
 # frida: readplus/CMakeLists.txt
 
+set(library_name readplus)
+set(${library_name}_LIBRARY ${library_name} PARENT_SCOPE)
+set(${library_name}_LIBRARY_TYPE SHARED)
+
 include_directories(${Frida_SOURCE_DIR}/readplus READLINE_INCLUDE_DIR ${Boost_INCLUDE_DIRS})
 
 set(src_files
-ask.cpp
-macro.cpp
-readln.cpp
-)
+    ask.cpp
+    macro.cpp
+    readln.cpp
+    )
 
 set(inc_files
-ask.hpp
-macro.hpp
-readln.hpp
-)
+    ask.hpp
+    macro.hpp
+    readln.hpp
+    )
 
-add_library(libreadplus SHARED ${src_files})
+add_library(${library_name} SHARED ${src_files})
 
-set_target_properties(libreadplus PROPERTIES OUTPUT_NAME readplus)
+set_target_properties(${library_name} PROPERTIES OUTPUT_NAME ${library_name})
 
-target_link_libraries(libreadplus ${Readline_LIBRARIES})
+target_link_libraries(${library_name} ${Readline_LIBRARIES})
 
-install(TARGETS libreadplus DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
+install(TARGETS ${library_name} LIBRARY DESTINATION ${destination_lib} COMPONENT Libraries)
diff --git a/pub/readplus/readln.cpp b/pub/readplus/readln.cpp
index 52f62087a75864f0412f6438159f7a824e2f0fc7..7d77d6788e90f1b25ae789f6e90c2f0813bb1607 100644
--- a/pub/readplus/readln.cpp
+++ b/pub/readplus/readln.cpp
@@ -103,7 +103,9 @@ string NReadln::readline(const string& prompt)
     char* inp;
     string ret;
     inp = ::readline(prompt.c_str()); // from libreadline
-    if (inp && *inp)
+    if (!inp)
+        return "EOF";
+    if (*inp)
         add_history(inp); // from libhistory
     ret = inp;
     free(inp);
diff --git a/pub/share/CMakeLists.txt b/pub/share/CMakeLists.txt
index 6530debb965f05eafae0562a2f2c9627c429ae89..6868d3575fdb3f87a3b2bc1630071fde1327c462 100644
--- a/pub/share/CMakeLists.txt
+++ b/pub/share/CMakeLists.txt
@@ -1,4 +1,10 @@
 configure_file(frida.ini.in frida.ini)
-set(share_files ${CMAKE_CURRENT_BINARY_DIR}/frida.ini g3.ps wups11a.ps gnuplot-default-symbols.eps)
+set(share_files
+    ${CMAKE_CURRENT_BINARY_DIR}/frida.ini
+    wups17a.ps
+    setup1D.ps
+    setup2D.ps
+    continuation.ps
+    gnuplot-default-symbols.eps
+    )
 install(FILES ${share_files} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/frida)
-
diff --git a/pub/share/continuation.ps b/pub/share/continuation.ps
new file mode 100644
index 0000000000000000000000000000000000000000..b445711a3a7e9ee8ad3edfbb8a10c8d527ecf797
--- /dev/null
+++ b/pub/share/continuation.ps
@@ -0,0 +1,12 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Next frame: customizable plot setup
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+WuGdict17a begin
+
+Resets
+BoxBackground
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Mark "ecu", end of the customization section
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/pub/share/frida.ini.in b/pub/share/frida.ini.in
index 2c6e0013b5fa53a3f771d121361d23b4109deebc..7981537aafecc16aaf6833deaf9ccddec4695275 100644
--- a/pub/share/frida.ini.in
+++ b/pub/share/frida.ini.in
@@ -1,8 +1,11 @@
 pop($silent=1)
-psdir="~/gnew/"
-pshead="${CMAKE_INSTALL_PREFIX}/share/frida/g3.ps"
-psdict="${CMAKE_INSTALL_PREFIX}/share/frida/wups11a.ps"
+ps_outdir="~/gnew/"
+ps_setup1D="${CMAKE_INSTALL_PREFIX}/share/frida/setup1D.ps"
+ps_setup2D="${CMAKE_INSTALL_PREFIX}/share/frida/setup2D.ps"
+ps_continuation="${CMAKE_INSTALL_PREFIX}/share/frida/continuation.ps"
+ps_definitions="${CMAKE_INSTALL_PREFIX}/share/frida/wups17a.ps"
 psgsym="${CMAKE_INSTALL_PREFIX}/share/frida/gnuplot-default-symbols.eps"
+ps_viewer="evince"
 FK01="pv"
 FK02="pn"
-undef("$silent")
\ No newline at end of file
+undef("$silent")
diff --git a/pub/share/setup1D.ps b/pub/share/setup1D.ps
new file mode 100644
index 0000000000000000000000000000000000000000..de913f620ed9569e910bc1c477f0050b55b46b6e
--- /dev/null
+++ b/pub/share/setup1D.ps
@@ -0,0 +1,49 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Customizable plot setup, copied from g4.ps (editör: use latin-1)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+WuGdict17a begin
+
+8 dup autolabel defsiz
+1 dup geld stdred
+2 -11 setnewpage newpage
+
+2 4 12.6 -12.6 setpagegrid
+2 8 24 abcset % usage: {(text)} abc
+/EndFrame { nextFrame end } def
+
+1 1 language
+1 infSet % plot info block?
+1 dup 2 SymGSet % srad slin serr(2=from pset) : graph symbols, global preset
+% /setboxbackgroundcolor { 0.93 setgray } def % default is white
+% setPalatino
+
+{ 7 aCol5 iColA } /ipCol x bind def % number of colours and colour style
+/pStyles [
+   { 11 0 0 1. 1. pset  0 ipCol }
+   { 12 1 0 1. 1. pset  1 ipCol }
+   { 13 1 0 1. 1. pset  2 ipCol }
+   {  1 0 0 1. 1. pset  3 ipCol }
+   {  1 1 0 .7 1. pset  4 ipCol }
+   {  3 0 0 1. 1. pset  5 ipCol }
+   {  3 1 0 .7 1. pset  6 ipCol }
+   {  4 0 0 1. 1. pset  7 ipCol }
+   {  4 1 0 .7 1. pset  0 ipCol }
+   {  5 0 0 1. 1. pset  1 ipCol }
+   {  5 1 0 .7 1. pset  2 ipCol }
+   {  2 0 0 1. 1. pset  3 ipCol }
+   {  2 1 0 .7 1. pset  4 ipCol }
+   ] def
+
+{ 8 aCol2 iColA } /icCol x bind def % number of colours and colour style
+/cStyles [
+   { 1. [] lset black }
+   { 1. [] lset 0 icCol }
+   ] def
+
+Resets
+BoxBackground
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Mark "ecu", end of the customization section
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/pub/share/setup2D.ps b/pub/share/setup2D.ps
new file mode 100644
index 0000000000000000000000000000000000000000..70d226ada703328fb41ba5f81d6f3b4507d0482a
--- /dev/null
+++ b/pub/share/setup2D.ps
@@ -0,0 +1,31 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Customizable plot setup, copied from g4.ps (editör: use latin-1)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+WuGdict17a begin
+
+10 dup autolabel defsiz
+1 dup geld stdred
+2 -11 setnewpage newpage
+
+2 4 13 -14 setpagegrid
+2 8 24 abcset % usage: {(text)} abc
+/EndFrame { nextFrame end } def
+
+1 1 language
+1 infSet % plot info block?
+1 dup 2 SymGSet % srad slin serr(2=from pset) : graph symbols, global preset
+/setboxbackgroundcolor { black } def
+% setPalatino
+
+{ 10 aCol6 {black} {white} iColAA } /icCol x bind def % number of colours and colour style
+
+/hxlow 11.3 def
+/hxhig 12.3 def
+
+Resets
+BoxBackground
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Mark "ecu", end of the customization section
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/pub/share/wups17a.ps b/pub/share/wups17a.ps
new file mode 100644
index 0000000000000000000000000000000000000000..4336be936504ad6d02248761e1b5e79c38554d64
--- /dev/null
+++ b/pub/share/wups17a.ps
@@ -0,0 +1,1484 @@
+%!PS-Adobe-2.0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  FRIDA: fast reliable interactive data analysis                           %%
+%%  wups17a.ps: graphic macros                                               %%
+%%  (C) Joachim Wuttke 1990-2017                                             %%
+%%  http://www.messen-und-deuten.de/frida                                    %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/WuGdict17a 400 dict def
+WuGdict17a begin
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Generic and math operators
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%  Shortcuts:
+
+/np { newpath }   bind def
+/mv { moveto }    bind def
+/rm { rmoveto }   bind def
+/rl { rlineto }   bind def
+/li { lineto }    bind def
+/cp { closepath } bind def
+/st { stroke }    bind def
+/x  { exch }      bind def
+/gs { gsave }     bind def
+/gr { grestore }  bind def
+/G  { gsave exec grestore } bind def
+
+/F false def
+/T true  def
+
+%%  Math operators:
+
+/twopi { 6.2831853072 } def
+
+/rnd  { rand cvr 1 30 bitshift div 2 div 0 max 1 min } def % -> between 0 and 1
+
+/min { 2 copy gt { x } if pop } def
+/max { 2 copy lt { x } if pop } def
+
+/tan { dup sin x cos div } def
+/cot { dup cos x sin div } def
+/pol2xy{ 2 copy cos mul 3 1 roll sin mul } def % r phi | x y
+
+/eexp { 2.71828 x exp } def % "exp" is x^y, eexp is e^x
+/tanh { 2.71828 x 2 copy exp 3 1 roll neg exp 2 copy sub 3 1 roll add div } def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Page coordinates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/pt {  .018567 mul} bind def % for line widths and font sizes, reason unclear
+/cm {28.346456 mul} bind def % typographic_point -> cm
+
+/cmtranslate { % x y cmtranslate | -
+   cm x cm x translate } bind def
+
+% Move origin from lower left (PostScript default) to upper left
+/setnewpage { % xoff yoff
+   /yoffnewpage x def
+   /xoffnewpage x def
+} def
+/originUpperLeft_A4{ .7 28.3 cmtranslate } bind def
+/goffsetA4 { ungscale originUpperLeft_A4 gscale } def
+/newpage {
+   goffsetA4
+   xoffnewpage yoffnewpage offset
+} def
+
+% Set absolute global scale and relative symbol size
+/defsiz { % size(cm) symbolsize(rel) | -
+   /ftot x def
+   /gsiz x cm 10 div def
+   gscale % within 'size', coordinates run from 0 to 10
+   } def
+/gscale {
+   gsiz dup scale
+   } def
+/ungscale {
+   1 gsiz div dup scale
+   } def
+
+% Symbol (and label?) size as sublinear function of figure size
+/autolabel { % size(cm) | symbolsize(rel)
+   dup 7 div 2 add 4 mul % the simplest sublinear increase
+   x div % anticipate overall rescaling
+   } def
+
+% Aspect ratios
+/gyld {0.447214 mul} bind def /Gyld {0.447214 div} bind def % sqrt(5)
+/guld {0.547723 mul} bind def /Guld {0.547723 div} bind def % sqrt(3)
+/gold {0.618034 mul} bind def /Gold {0.618034 div} bind def % goldener Schnitt
+/gild {0.707107 mul} bind def /Gild {0.707107 div} bind def % sqrt(2) : DIN
+/geld {0.759836 mul} bind def /Geld {0.759836 div} bind def % sqrt(sqrt(3))
+/gald {0.817765 mul} bind def /Gald {0.817765 div} bind def % sqrt sqrt sqrt 5
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Several frames per page
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/setpagegrid { % ncol nrow xoffnewframe yoffnewframe
+   /yoffnewframe x def
+   /xoffnewframe x def
+   /nrowpage x def
+   /ncolpage x def
+} def
+/iFrame 0 def
+/nextFrame {
+   /iFrame iFrame 1 add def
+   iFrame nrowpage ncolpage mul mod 0 eq {
+     showpage gscale newpage
+     } {
+     iFrame ncolpage mod 0 eq {
+       xoffnewframe ncolpage 1 sub neg mul yoffnewframe offset
+     } {
+       xoffnewframe 0 offset
+       } ifelse
+     } ifelse
+   } def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Frame coordinates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/defred { % x_reduction y_reduction label_reduction | -
+   /fmm x ftot mul def
+   /ymm x def
+   /xmm x def
+
+   % conversion frame_coordinate -> global_coord
+   /xm {xmm mul} bind def
+   /ym {ymm mul} bind def
+   /fm {fmm mul} bind def
+   /xym {ym x xm x} bind def
+
+   % prefer rescaling over explicit conversion (make more use of this !)
+   /mmscale { xmm ymm scale } bind def
+   /mmunscale { 1 xmm div 1 ymm div scale } bind def
+
+   % graphic commands in frame coordinates
+   /offset { xym translate } bind def
+   /currentxy { currentpoint ymm div x xmm div x } bind def
+   /setline { pt fm setlinewidth [] 0 setdash } bind def
+   } def
+
+/stdred { % x_reduction y_reduction | -
+   2 copy mul sqrt defred
+   } def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  World (= user application) coordinates
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/xSetCoord { % log min max | -
+   /wxmax x def
+   /wxmin x def
+   /wxlog x 0 eq not def
+   /wxdel wxmax wxmin wxlog { div log } { sub } ifelse def
+   /wxd { % dx(world) | dx(frame)
+      wxlog { log } if wxdel div 10 mul
+      } bind def
+   /wx { % x(world) | x(frame)
+      wxmin wxlog { div } { sub } ifelse
+      wxd
+      } bind def
+   } def
+/ySetCoord { % log min max | -
+   /wymax x def
+   /wymin x def
+   /wylog x 0 eq not def
+   /wydel wymax wymin wylog { div log } { sub } ifelse def
+   /wyd { % dy(world) | dy(frame)
+      wylog { log } if wydel div 10 mul
+      } bind def
+   /wy { % y(world) | y(frame)
+      wymin wylog { div } { sub } ifelse
+      wyd
+      } bind def
+   } def
+/hSetCoord { % log min max | - % for use in 2D plot
+   /whmax x def
+   /whmin x def
+   /whlog x 0 eq not def
+   /wH { % h(world) | h(col)
+      dup whmin lt {
+         pop -1
+      } {
+         dup whmax gt {
+	       pop 11
+	    } {
+	       wh
+	    } ifelse
+      } ifelse
+   } bind def
+   whlog {
+      /whdel whmax whmin div log def
+      /wh { whmin div log whdel div 10 mul } bind def % h(world) | h(col)
+   } {
+      /whdel whmax whmin sub def
+      /wh { whmin sub whdel div 10 mul } bind def % h(world) | h(col)
+      } ifelse
+   } def
+
+% pair conversion
+/wxy { % x,y(world) -> x,y(frame)
+   wy x wx x
+   } def
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Colors                                                                   %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%  Color operators:
+
+/setRGBcolor {
+   3 { 255 div 3 1 roll } repeat setrgbcolor
+   } def
+
+/colormix { % weight(0..1) col1(R|G|B) col2(R|G|B) | col(R|G|B)
+   7 -1 roll dup /weightA x def /weightB x 1 x sub def
+   4 -1 roll weightA mul x weightB mul add 5 1 roll
+   3 -1 roll weightA mul x weightB mul add 4 1 roll
+   2 -1 roll weightA mul x weightB mul add 3 1 roll
+   } def
+
+/relcol { % i_col n_col | rel(0..1) : for one-dimensional choices
+   1 sub div 0 max 1 min
+   } def
+
+%%  Named colors:
+
+/black { 0 setgray } bind def
+/white { 1 setgray } bind def
+
+/red           { 255   0   0 setRGBcolor } bind def
+
+/siemensorange { 255 153   0 setRGBcolor } bind def
+/siemensblue   { 0   102 153 setRGBcolor } bind def
+/siemenstext   {   0  51 102 setRGBcolor } bind def
+/siemensred    { 165   0  33 setRGBcolor } bind def
+/siemenspink   { 221 102 102 setRGBcolor } bind def
+/siemensgrey   { 221 221 221 setRGBcolor } bind def
+/siemensdark   { 102 102 102 setRGBcolor } bind def
+/siemensgreen  {  33 153 102 setRGBcolor } bind def
+/siemensyellow { 255 221   0 setRGBcolor } bind def
+
+
+%%  One-dimensional linear color choices:
+
+/iCol1 { % i i_max | - : default -2010, round the circle, RGBR
+   relcol dup 1 x % rel 1 rel
+   360 mul 255 add cos 1 add dup mul neg .053 mul 1 add % modulate saturation
+   sethsbcolor
+   } def
+/iCol2 { % i i_max | - : cyan  - yellow - magenta
+   relcol 3 mul
+   dup 1 le {
+      dup 1 sub neg 0 3 2 roll } {
+      dup 2 le {
+         1 sub dup 1 sub neg 0 3 1 roll } {
+         2 sub dup 1 sub neg 0 3 0 roll } ifelse
+      } ifelse
+   0 setcmykcolor
+   } def
+/iCol3 { % i i_max | - : siemens
+   div /icnow x def
+   165 1 icnow sub mul
+   102   icnow     mul
+    33 120 icnow mul add setRGBcolor
+   } def
+/iCol4 { % i i_max | - : red to blue (subsequence of old scheme iCol1)
+   relcol
+   3 x sub 3 div 1 iCol1
+   } def
+
+
+%%  One-dimensional color choice from given array:
+
+/iColA { % i i_max arr | -
+   /aCol x def
+   relcol
+   aCol length 1 sub mul % position within array
+   dup cvi dup 3 1 roll % idx pos idx
+   sub x % offset idx
+   0 max aCol length 1 sub min % offset safe_idx
+   dup 1 add aCol length 1 sub min % offset i i+1
+   aCol x get exec
+   4 3 roll aCol x get exec colormix setRGBcolor
+   } def
+
+%% ditto with discontinuous values for h<0 and h>1
+
+/iColAA { % i i_max arr {low_col} {hig_col} | -
+   5 3 roll
+   div
+   dup 0 lt {
+      pop pop x pop exec
+   } {
+      dup 1 gt {
+         pop 3 1 roll pop pop exec
+      } {
+         1 % arr {l} {h} i i_max
+	 5 2 roll pop pop
+	 x 1 add x % ad-hoc correction for legacy definition of relcol
+	 iColA
+         } ifelse
+      } ifelse
+   } def
+
+%% Color arrays for non-linear one-dimensional choices:
+
+/aCol1 [ % red-blue
+   { 255   0   0 } %  1
+   { 240  10  10 } %  2
+   { 220  40  40 } %  3
+   { 205  65  90 } %  4
+   { 195  80 130 } %  5
+   { 180 110 180 } %  6
+   { 165 120 185 } %  7
+   { 150 130 190 } %  8
+   { 130 150 210 } %  9
+   { 110 125 220 } % 10
+   {  85 105 230 } % 11
+   {  70  90 255 } % 12
+   {   0   0 255 } % 13
+   ] def
+/aCol2 [ % orange-red-blue-darkblue
+   { 255 180   0 }
+   { 255 160   0 }
+   { 255 120   0 }
+   { 255  70   0 }
+   { 255   0   0 }
+   { 220  30  30 }
+   { 220  70  60 }
+   { 220 100 110 }
+   { 200 130 130 }
+   { 200 130 160 }
+   { 180 110 180 }
+   { 165 110 185 }
+   { 150 130 190 }
+   { 130 150 210 }
+   { 100 120 220 }
+   {  85 105 230 }
+   {  70  90 255 }
+   {   0   0 255 }
+   {   0   0 180 }
+   {  10  10 150 }
+   {  30  30 130 }
+   ] def
+/aCol3 [ % [fixed size: max_i=8] siemenscolors
+   { 165   0  33 } % siemensred
+   {  33 153 102 } % siemensgreen
+   { 0   102 153 } % siemensblue
+   {   0  51 102 } % siemenstext
+   { 255 153   0 } % siemensorange
+   { 102 102 102 } % siemensdark
+   { 255 221   0 } % siemensyellow
+   { 221 221 221 } % siemensgrey
+   { 221 102 102 } % siemenspink
+   ] def
+/aCol4 [ % green-blue-brown
+   { 120 160  60 }
+   {  90 185  40 }
+   {  50 215  20 }
+   {   0 245   0 }
+   {  10 235 112 }
+   {  20 235 143 }
+   {  30 230 173 }
+   {  40 225 194 }
+   {  50 205 215 }
+   {  40 153 204 }
+   {  40 102 153 }
+   {  40  82 122 }
+   {  90  74 101 }
+   { 140  68  80 }
+   { 170  59  60 }
+   { 190  50  40 }
+   { 180  65  40 }
+   { 160  80  40 }
+   { 140 100  40 }
+   { 120  80  30 }
+   { 100  60  20 }
+   ] def
+/aCol5 [ % [fixed size: max_i=7] old gnuplot default (see man gnuplot and rgb.txt)
+   { 255   0   0 } % red
+   {   0 255   0 } % green
+   {   0   0 255 } % blue
+   { 255   0 255 } % magenta
+   {   0 255 255 } % cyan
+   { 160  82  45 } % sienna
+   { 255 165   0 } % orange
+   { 255 127  80 } % coral
+   ] def
+/aCol6 [ % heat plot
+   { 100   0 100 } % violet
+   {  60  30 130 } % dark blue
+   {  30  50 220 } % blue
+   {  50 150 100 } % green
+   { 150 200 100 } % green
+   { 215 255  50 } % green/yellow
+   { 255 255   0 } % yellow
+   { 255 125   0 } % orange
+   { 255   0   0 } % red
+   ] def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Fonts
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% extend font encoding
+/ReEncode { % OldFont NewFont Encoding | -
+   /MyEncoding x def
+   x findfont % select OldFont
+   dup length dict begin
+      {def} forall
+      /Encoding MyEncoding def
+      currentdict
+      end
+   definefont pop % define as NewFont
+   } def
+
+% we assume that image scripts are Latin1 encoded
+/Helvetica             /MyFont             ISOLatin1Encoding ReEncode
+/Helvetica-Oblique     /MyFont-Oblique     ISOLatin1Encoding ReEncode
+/Helvetica-Bold        /MyFont-Bold        ISOLatin1Encoding ReEncode
+/Helvetica-BoldOblique /MyFont-BoldOblique ISOLatin1Encoding ReEncode
+
+/setPalatino {
+   /Palatino             /MyFont             ISOLatin1Encoding ReEncode
+   /Palatino-Italic      /MyFont-Oblique     ISOLatin1Encoding ReEncode
+   /Palatino-Bold        /MyFont-Bold        ISOLatin1Encoding ReEncode
+   /Palatino-BoldItalic  /MyFont-BoldOblique ISOLatin1Encoding ReEncode
+   } def
+
+%% Preset standard styles:
+
+% scale and set font; define fontsize, fontheight
+/setfontandsize { % font size | -
+   dup 0 le { pop 100 } if % fontsize <= 0 not allowed !
+   /fontnonnil true def
+   pt fm dup /fontsize x def
+   x findfont
+   x scalefont
+   setfont
+   gsave % determine fontheight - from the cookbook :
+      np 0 0 mv (1) true charpath flattenpath
+      pathbbox  % low_left_x, low_left_y, up_right_x, up_right_y
+      x pop x pop x pop
+      /fontheight x def
+      grestore
+   } def
+
+% standard settings for labelling axes
+/numlabcol { black } def
+/setnum { /MyFont            24 setfontandsize numlabcol } def
+/setlab { /MyFont            24 setfontandsize numlabcol } def
+
+% user commands (free choice of fontsize, but fixed font family)
+/setown { /MyFont             x setfontandsize } def
+/setbol { /MyFont-Bold        x setfontandsize } def
+/setboq { /MyFont-BoldOblique x setfontandsize } def
+/setobl { /MyFont-Oblique     x setfontandsize } def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Text blocks
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/showif { % string | - : increment xwidth or plot string
+   prepare
+      { stringwidth pop xwidth add /xwidth x def }
+      { show }
+   ifelse
+   } def
+/script { % matrix relpos_y | -
+   /yoffset x fontheight mul def
+   currentfont x makefont setfont
+   0 yoffset rm
+   } def
+/scred .71 def
+/subsc {
+   showif
+   [scred 0 0 scred 0 0] -.2 script
+   } def
+/supsc {
+   showif
+   [scred 0 0 scred 0 0] .6 script
+   } def
+/endsc {
+   showif
+   regularfont setfont
+   0 yoffset neg rm
+   } def
+/grec {
+   showif
+   /Symbol findfont fontsize scalefont setfont
+   } def
+/endgr {
+   showif
+   regularfont setfont
+   } def
+/endall {
+   showif
+   regularfont setfont
+   } def
+/build { % string xrel yrel obj | - : plot obj above/below string
+   /obj x def /yrelbui x def /xrelbui x def
+   dup showif
+   prepare
+      { pop }
+      { stringwidth pop xrelbui neg mul fontheight yrelbui mul % relpos for obj
+        currentpoint 4 2 roll % save position after string
+      rm obj pop       % obj must end with () that will be pop'ed
+      mv               % back to saved position
+      }
+   ifelse
+   } def
+/gbuild { % string xrel yrel obj | - : plot obj above/below string
+   /obj x def /yrelbui x def /xrelbui x def
+   /Symbol findfont fontsize scalefont setfont
+   dup showif
+   prepare
+      { pop regularfont setfont }
+      { stringwidth pop xrelbui neg mul fontheight yrelbui mul % relpos for obj
+        currentpoint 4 2 roll % save position after string
+        regularfont setfont
+      rm obj pop       % obj must end with () that will be pop'ed
+      mv               % back to saved position
+      }
+   ifelse
+   } def
+/hut { % ..) (<Char>) hut (..            %%%  MISERABEL PROGRAMMIERT
+   x showif
+   1.4 .6 {(\136) show ()} build
+   } def
+/ghut { % ..) (<grec-Char>) ghut (..      %%%  BREITE PASST NUR FUER Phi(t)
+   x showif
+   .8 .65 {(\136) show ()} gbuild
+   } def
+/tilde {
+   x showif
+   1. .6 {(~) show ()} build
+   } def
+/gtilde {
+   x showif
+   1. .6 {(~) show ()} gbuild
+   } def
+/spce { % string n spce - ; insert n times ( )
+   {showif (  )} repeat
+   } def
+
+% the following macros use the symbol/curve plotting mechanism
+/pins { % string symins - ; symbol must be selected by pset
+   showif
+   ( ) showif ( ) .5 .5 { currentxy 0 p black ()} build ( ) showif
+   } def
+/clenins { % string len clenins - ; curve must be selected by cset
+   x showif % I suppose that pins is preceeded by 8 spaces
+   dup ( ) stringwidth pop mul 2 add /xstrich x xmm div def
+            % length of inserted curve :
+            % -1 space : curve begins and ends in  middle of ( )
+            % +3 spaces: pins requires 3 times ( )
+   ( ) 0 .5 { currentxy currentxy 0 ci x xstrich add x 0 cf () } build
+   2 add {( ) showif} repeat
+   } def
+/cins { % string symins - ; curve must be selected by cset
+   showif 8 % I suppose that pins is preceeded by 8 spaces
+   dup ( ) stringwidth pop mul 2 add /xstrich x xmm div 10 div def
+   % nov03, ohne zu verstehen, "10 div" eingefuegt
+            % length of inserted curve :
+            % -1 space : curve begins and ends in  middle of ( )
+            % +3 spaces: pins requires 3 times ( )
+   ( ) 0 .5 { currentxy currentxy 0 ci x xstrich add x 0 cf () } build
+   2 add {( ) showif} repeat
+   } def
+
+/block { % x y ob xrel yrel | -
+   /yrel x def /xrel x def /blabla x def
+    /ypos x ym def /xpos x xm def
+   /regularfont currentfont def /yoffset 0 def % initialize for security
+   /prepare true def /xwidth 0 def 0 0 mv % to prevent empty-path-error
+    blabla endall % first pass : determine xwidth
+   boxif { /boxwidth  xwidth (M) stringwidth pop boxxr mul 2 mul add def
+           /boxheight fontheight 1 boxyr 2 mul add mul def
+           np xpos xwidth xrel mul sub boxwidth xwidth sub 2 div sub
+           ypos fontheight .5 boxyr add mul sub mv
+           boxwidth 0 rl 0 boxheight rl boxwidth neg 0 rl cp
+           boxproc
+    } if
+    xpos xwidth xrel mul sub ypos fontheight yrel mul sub mv
+    /prepare false def
+    blabla endall % second pass : plot
+   /boxif false def
+   } def
+/rblock { % x y ang ob proc rblock -
+   5 3 roll
+   gsave
+      xym translate
+      3 2 roll rotate
+      0 0 4 2 roll exec
+      grestore
+   } def
+
+/Box { % x y {exe}
+   /boxif true def
+   /boxproc x def /boxyr x def /boxxr x def
+   } def
+/nBox { .6 .6 3 2 roll Box } def
+/boxif false def
+/textW { % obj | length : calculate only length.
+   /blabla x def
+   /regularfont currentfont def /yoffset 0 def % initialize for security
+   /prepare true def /xwidth 0 def 0 0 mv % to prevent empty-path-error
+   blabla endall
+   xwidth % has been determined
+   } def
+/textw { % obj | y : dito, in 0..10-units
+   textW xmm div
+   } def
+
+% horizontal text: x y ob | -
+/textLB { 0. 0. block } bind def
+/textCB { .5 0. block } bind def
+/textRB { 1. 0. block } bind def
+/textLM { 0. .5 block } bind def
+/textCM { .5 .5 block } bind def
+/textRM { 1. .5 block } bind def
+/textLT { 0. 1. block } bind def
+/textCT { .5 1. block } bind def
+/textRT { 1. 1. block } bind def
+
+% rotated text: x y ang ob | -
+/rtextLB { {textLB} rblock } bind def
+/rtextLM { {textLM} rblock } bind def
+/rtextRB { {textRB} rblock } bind def
+/rtextRM { {textRM} rblock } bind def
+/rtextCM { {textCM} rblock } bind def
+
+%%  Language selection:
+
+% preset
+/language { % choose_this of_so_many | - % select current language
+   /langMax x def
+   /langChc x def
+   } def
+1 1 language % default
+% choose text from sequence
+/langSel { % text_1 .. text_M | text_C : choose text, M=langMax, C=langChc
+   langMax dup langChc sub 1 add roll
+   langMax 1 sub { pop } repeat
+   } def
+/L  { langSel } bind def
+
+%%  Text composition shortcuts:
+
+/g  { x grec endgr} bind def
+/sb { x subsc endsc} bind def
+/sp { x supsc endsc} bind def
+/sbgr { x grec () subsc endsc () endgr} bind def
+/spgr { x grec () supsc endsc () endgr} bind def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Text macros
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/Celsius { showif (\26x)g(C) showif } bind def
+/hbar {
+   showif
+   (h) 1.2 .66 {
+      currentpoint fontheight .11 mul setline np mv
+      fontheight dup .8 mul x .3 mul rl
+      st ()
+      } build
+   } bind def
+
+%%  for neutron scattering:
+
+/hbarw { hbar () grec (w) endgr } bind def
+/wbar { grec (w) endgr ( / 2) grec (p) endgr } bind def
+/taumean { () (\341t\361) g } bind def
+/Sqw { showif (S\(q,) grec (w) endgr (\)) showif } bind def
+/Sqn { showif (S\(q,) grec (n) endgr (\)) showif } bind def
+/SQw { showif (S\(Q,) grec (w) endgr (\)) showif } bind def
+/Sttw { showif (S\(2) grec (q) endgr (,) grec (w) endgr (\)) showif } bind def
+/Sttn { showif (S\(2) grec (q) endgr (,) grec (n) endgr (\)) showif } bind def
+/Xqw { grec (c) endgr (''\(q,) grec (w) endgr (\)) showif } bind def
+/Xqn { grec (c) endgr (''\(q,) grec (n) endgr (\)) showif } bind def
+/ueV{ grec (m) endgr (eV) showif} bind def
+/inueV { showif (\() grec (m) endgr (eV\)) showif } bind def
+/inmeVr { showif (\(meV) supsc (-1) endsc (\)) showif } bind def
+/inueVr { showif (\() grec (m) endgr (eV)
+          supsc (-1) endsc (\)) showif } bind def
+/inGHzr { showif (\(GHz) (-1) sp (\)) showif } def
+
+/Angstr { showif (\305) showif } bind def
+/Angr { showif (\305) supsc (-1) endsc } bind def
+/inAngr { showif (\() Angr (\)) showif } bind def
+/Angrr { showif (\305) supsc (-2) endsc } bind def
+/inAngrr { showif (\() Angrr (\)) showif } bind def
+/wmin {grec (w) endgr () subsc (min) endsc} def
+/winpi { grec (w) endgr ( / 2) grec (p) endgr } def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Coordinate Frame                                                         %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%  Layout presets:
+
+/xyTicLen {0.10 fm} def
+/xyTacLen {0.20 fm} def
+/txllen {0.20 fm} def
+/tyllen {0.20 fm} def
+/linsetAxx {black 0.7 setline} def
+/linsetTic {black 0.7 setline} def
+/linsetTac {black 0.7 setline} def
+/linsetGri {black 0.4 setline} def
+
+%%  Start-up commands:
+
+/Resets {
+   /yNumLengthL 0 def /yNumLengthH 0 def
+   /xNumHeightL .3 def /xNumHeightH 0 def
+   /xNumHeightRel 2.4 def
+   /aMean 5 def
+   black
+   } def
+/BoxBackground {
+   0 10 0 10 rect gsave setboxbackgroundcolor fill grestore
+} def
+/setboxbackgroundcolor { white } def
+
+/zValues { pop pop } def
+/whiteframe { 1 0 0 10 10 graybox } def
+
+/abc {abclab setown abcx abcy 3 2 roll textCM} def % usage ((a)) abc
+/abcset { % x y siz abcset - : preset for abc
+   /abclab x def /abcy x def /abcx x def
+   } def
+
+%%  Ticks:
+
+% set tick array - internal macros
+/tiputs { % rel_pos_of_tick | pos_of_tick : innermost routine for /taproc
+   tastep mul taloop add
+   } def
+/taproclin { % (#tick/tack) | - : define /taproc for use in SetVec
+   1 x div /tistep x def
+   /taproc { 0 tistep .999 { tiputs } for } def
+   } def
+/taproclog { % (#ticks/tacks) | - : define /taproc for use in SetVec
+      dup 3 gt { pop /taproc { 1 1 9 { log tiputs } for } def
+   }{ dup 1 gt { pop /taproc { 0 tiputs 2 log tiputs 5 log tiputs } def
+   }{ dup 0 gt { pop /taproc { 0 tiputs } def
+   }{            neg taproclin
+   } ifelse } ifelse } ifelse
+   } def
+/SetVec { % tafro tatoo nta /vector | - : set /vector
+   4 1 roll
+   /nta x def /tatoo x def /tafro x def
+   /tastep tatoo tafro sub nta 1 sub div def
+   [
+      0 1 nta {
+         tastep mul tafro add /taloop x def
+         taproc exec
+         } for
+      ] def
+   } def
+% set tick array - user commands
+/SetTicVecLin { taproclin /TicVec SetVec } def
+/SetTicVecLog { taproclog /TicVec SetVec } def
+
+% set tack-and-number array
+/SetTacVec { % [ pos {label} pos {label} ... ] | -
+   /TacVec x def
+   } def
+
+% define axes
+   % note on angles : 0 = x-axis, 90 = y-axis
+/OneAxx { % fro to xpos ypos aang tang | - : presets for Axx, Tic, Tac, Num
+   % store arguments
+   /tAng x def /aAng x def
+   /yPos x def /xPos x def
+   /aTo x def /aFro x def
+   % set constants
+   /xTicLen tAng cos xyTicLen mul def /yTicLen tAng sin xyTicLen mul def
+   /xTacLen tAng cos xyTacLen mul def /yTacLen tAng sin xyTacLen mul def
+   /xAng aAng cos def /yAng aAng sin def
+   /aMean aFro aTo add 2 div def
+   } def
+
+% draw axis (with parameters preset by OneAxx or ArrAxx)
+/Axx { % - | -
+   linsetAxx
+   gsave
+      xPos yPos offset
+      mmscale
+      aAng rotate
+      % draw a line
+      aFro 0 np mv
+      aTo  0 li st
+      grestore
+   } def
+
+% draw ticks (positions given by SetTicVec, parameters preset by OneAxx/..)
+/Tic { % - | - : draw tick as defined in TicProc
+   linsetTic
+   TicVec {
+      dup dup aFro lt x aTo gt or {pop} {TicProc} ifelse
+      } forall
+   } def
+/TicProc { % aPos | - : default procedure to plot one tick
+   np
+   xPos yPos xym mv
+   dup xAng mul x yAng mul xym rm % eat argument, go to start pos.
+   xTicLen yTicLen rl st
+   } def
+/xGric { % yFro yTo | - : draw a grid line (instead of an x tick)
+   linsetGri
+   TicVec {
+      3 copy dup 5 -1 roll aFro lt x aTo gt or {pop pop pop} {
+         dup % y1 y2 x x
+         4 -1 roll xym np mv % y2 x
+         x xym li st
+         } ifelse
+      } forall
+   pop pop
+   } def
+/yGric { % xFro xTo | - : draw a grid line (instead of an y tick)
+   linsetGri
+   TicVec {
+      3 copy dup 5 -1 roll aFro lt x aTo gt or {pop pop pop} {
+         dup % x1 x2 y y
+         4 -1 roll x xym np mv % x2 y
+         xym li st
+         } ifelse
+      } forall
+   pop pop
+   } def
+
+% draw tacks (positions given by SetTacVec, parameters preset by OneAxx/..)
+/TacExe { % Proc | - % Execute Proc for all pairs of elements of TacVec
+                     % (but only if inside aFro..aTo)
+   /TacProc x def
+   /ispair true def % toggle: take pos, take label, take pos, take label ...
+   TacVec {
+      ispair
+         {
+            /aPos x def
+            /ispair false def
+         } {
+            aPos dup aFro lt x aTo gt or
+            {pop} {TacProc} ifelse
+            /ispair true def
+         } ifelse
+      } forall
+   } def
+/Tac {
+   linsetTac
+   { pop xPos yPos xym mv
+      aPos dup xAng mul x yAng mul xym rm
+      xTacLen yTacLen rl st
+      } TacExe
+   } def
+% special tack routines, only for rectangular axes
+/xTacC { % : centered tack on x axis
+   linsetTac
+   { pop aPos xm yPos ym txllen 2 div sub np mv 0 txllen rl st } TacExe
+   } def
+/xGrid { % : rule instead of tack on x axis
+   linsetTac
+   { pop aPos xm np yPos ym mv 0 10 xym rl st } TacExe
+   } def
+/yTacC { % : centered tack on y axis
+   linsetTac
+   { pop xPos xm tyllen 2 div sub aPos ym np mv tyllen 0 rl st } TacExe
+   } def
+/yGrid { % : rule instead of tack on low y axis
+   linsetTac
+   { pop aPos ym np xPos xm x mv 10 0 xym rl st } TacExe
+   } def
+
+% draw numbers (pos-txt pairs given by SetTacVec)
+/Num { % Generic but useless. Adjust for your application.
+   setnum
+   fontheight ymm div yDisRel mul tAng sin mul /yDist x def
+   {  dup textW xDisRel mul tAng cos mul /xDist x def
+      xPos aPos xAng mul add xDist sub
+      yPos aPos yAng mul add yDist sub 3 2 roll textCM
+      } TacExe
+   } def
+/setnumDisRel { % xDisRel yDisRel | - : adjust just a little bit
+   /yDisRel x def /xDisRel x def
+   } def
+1.2 1.2 setnumDisRel % default setting
+% explicit Num routines for rectangular case
+/xNumL { % : numbers on low x axis
+   setnum
+   {  fontheight ymm div % conversion -> user_scale
+      dup /xNumHeightL x def
+      -.6 mul yPos add aPos x 3 2 roll textCT
+      } TacExe
+   } def
+/xNumH { % : numbers on high x axis
+   setnum
+   {  fontheight ymm div % conversion -> user_scale
+      dup /xNumHeightH x def
+      .6 mul yPos add aPos x 3 2 roll textCB
+      } TacExe
+   } def
+/yNumL { % : numbers on low y axis
+   setnum
+   { fontsize -.3 mul xmm div xPos add aPos 3 2 roll textRM
+     xwidth dup yNumLengthL gt {/yNumLengthL x def} {pop} ifelse
+     } TacExe
+   } def
+/yNumLD { % : calculate only yNumLength (used for adjustement)
+   setnum
+   { textW dup yNumLengthL gt {/yNumLengthL x def} {pop} ifelse
+     } TacExe
+   } def
+/yDumL { % {(..)} yDumL : compare yNumLength with one arg (used for adjustement)
+   setnum
+   textW dup yNumLengthL gt {/yNumLengthL x def} {pop} ifelse
+   } def
+/yNumH { % : numbers on high y axis
+   setnum
+   { fontsize .3 mul xmm div xPos add aPos 3 2 roll textLM
+     xwidth dup yNumLengthH gt {/yNumLengthH x def} {pop} ifelse
+     } TacExe
+   } def
+/yNumHD { % : calculate only yNumLength (used for adjustement)
+   setnum
+   {textW dup yNumLengthH gt {/yNumLengthH x def} {pop} ifelse
+     } TacExe
+   } def
+/yDumH { % {(..)} yDumH : compare yNumLength with one arg (used for adjustement)
+   setnum
+   textW dup yNumLengthH gt {/yNumLengthH x def} {pop} ifelse
+   } def
+
+% draw labels
+/xCL { % xlabel | - ; plots coordinate name below the x-axis.
+   setlab
+   aMean xNumHeightL xNumHeightRel neg mul
+   3 -1 roll textCT
+   } def
+/xCH { % xlabel | - ; plots coordinate name above the x-axis.
+   setlab
+   aMean xNumHeightH xNumHeightRel mul 10 add
+   3 -1 roll textCB
+   } def
+/yCL { % ylabel | - ; plots coordinate name to the left of the y-axis.
+   gsave
+      setlab
+      yNumLengthL neg fontsize -.85 mul add % yNumLengthL calculated in yN
+      aMean ym translate
+      0 0 mv
+      90 rotate
+      0 x 0 x textCB
+   grestore
+   } def
+/YCH { % ylabel xpos | - ; plots coordinate name to the right of a vertical axis
+   gsave
+      setlab
+      yNumLengthH fontsize .85 mul add x xm add
+      aMean ym translate
+      0 0 mv
+      90 rotate
+      0 x 0 x textCT
+   grestore
+   } def
+/yCH { 10 YCH } def % ylabel | - ; plots coordinate name to the right of the y-axis.
+/yCF { % ylabel | - ; plots coordinate name *falling* right of the y-axis.
+   gsave
+      setlab
+      yNumLengthH fontsize .85 mul add 10 xm add
+      aMEan ym translate
+      0 0 mv
+      -90 rotate
+      0 x 0 x textCB
+   grestore
+   } def
+
+/knautschy { % x0 y0 y_knau y_tot knautschy - : insert an S in dived y-axis
+   % the total height of the generated object is y_tot
+   % of which y_knau(.le. y_tot) is for the real knautsch,
+   % the remainder is for vertical prolongations.
+   x ym 4 div dup /tmpy x def 5 sqrt mul /tmpx x def
+   /tmpa x ym tmpy 4 mul sub 2 div def
+   np ym x xm x mv 0 tmpa rl tmpx tmpy rl tmpx -2 mul tmpy 2 mul rl
+   tmpx tmpy rl 0 tmpa rl st
+   } def
+/separy { % x0 y0 sep lng ang lin - : insert an // in dived y-axis
+   setline
+   /spang x def
+   /splng x def
+   /spsep x def
+   2 copy spsep sub gsave offset spang rotate
+      splng -.5 mul fm 0 np mv splng fm 0 rl st grestore
+   spsep add gsave offset spang rotate
+      splng -.5 mul fm 0 np mv splng fm 0 rl st grestore
+   } def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Data Plotting (Symbols and Curves)                                       %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%  Initializations:
+
+% asymmetric error bars?
+/err_asy false def % overwrite this if data are quadruples x y d- d+
+
+%%  Presets:
+
+% global preset
+/SymGSet { % sradglo slinglo serrglo | -
+   /serrglo x def % plot error bars? 0=never, 1=always, 2=as_given_in_pset
+   /slinglo x def % symbol linewidth multiplier
+   /sradglo x def % symbol size multiplier
+   } def
+
+%%  Retrieve presets from style array:
+
+/pstyle { pStyles setstyle } def
+/cstyle { cStyles setstyle } def
+/setstyle { % chosen_number array | - : set p or c as predefined in array.
+   dup length % i A n
+   3 2 roll % A n i
+   dup 0 le {
+      pop pop pop ostyle % chosen_number<=0 means: don't plot
+      } {
+      1 sub x % A i-1 n
+      mod get % A(i-1)
+      exec
+      } ifelse
+   } def
+
+%% Set plot symbol:
+
+/pset { % styp sfill serr srad slin | -
+   % arg -> symbol linewidth
+   /slin x slinglo mul def
+   % arg -> symbol size
+   /srad x fm 0.16 mul sradglo mul def
+   % arg -> plot error bar?
+   2 serrglo ne { pop serrglo } if % if (serrglo=2) use serr else use serrglo
+   /plot_errorbar x 1 eq { { errorbar } } { { pop pop pop pop } } ifelse def
+   % arg -> fill the symbol? (0=open, 1=full, 2=colored_with_black_border)
+   /sfill x def
+   % adjust srad: it's the _outer_ radius
+   % TROUBLE sfill 1 ne {/srad srad slin fm pt sub def} if
+   % arg -> symbol type
+   /ps {ps_nil} def % default: don't plot (maybe we only want an error bar)
+   dup  1 eq {/ps {ps_square}     def} if
+   dup  2 eq {/ps {ps_diamond}    def} if
+   dup  3 eq {/ps {ps_circle}     def} if
+   dup  4 eq {/ps {ps_triangle}   def} if
+   dup  5 eq {/ps {ps_cedez}      def} if
+   dup  6 eq {/ps {ps_eieruhr}    def} if
+   dup  7 eq {/ps {ps_valve}      def} if
+   dup  8 eq {/ps {ps_tfwd}       def} if
+   dup  9 eq {/ps {ps_tbwd}       def} if
+   dup 10 eq {/ps {ps_pentagram}  def} if
+   dup 11 eq {/ps {ps_plus}       def} if
+   dup 12 eq {/ps {ps_cross}      def} if
+   dup 13 eq {/ps {ps_star}       def} if
+   dup 14 eq {/ps {ps_pentagon}   def} if
+   dup 15 eq {/ps {ps_horiz}      def} if
+   dup 16 eq {/ps {ps_verti}      def} if
+   pop
+   %
+   /t { % x y d[- d+] | -  : plot a symbol and eventually an error bar.
+       err_asy not { dup } if
+       4 copy pop pop plot_symbol
+       plot_errorbar
+      } bind def
+   /ti { t } bind def
+   /tf { t black } bind def
+   } def
+
+%%  Set curve:
+
+/lset { % lwidth dashes | -
+   0 setdash
+   dup 0 gt {
+      pt fm setlinewidth
+      % pop error bar and convert frame coord -> paper coord
+      /txy { err_asy { pop } if pop xym } def % x y d[- d+] | x' y'
+      % commands to plot points (can be overwritten by nopoints):
+      /ti { np txy mv } def % x y d[- d+] | - : start curve
+      /t  { txy li }    def % x y d[- d+] | - : continue curve
+      /tf { txy li st } def % x y d[- d+] | - : terminate and plot curve
+      } {
+         ostyle
+      } ifelse
+   } def
+
+%%  Plot nothing:
+
+/ostyle { % - | -
+   /ti { nopoint } def
+   /t  { nopoint } def
+   /tf { nopoint } def
+} def
+/nopoint { % x y d[- d+] | -
+   pop pop pop err_asy { pop } if
+} def
+
+%%  Plot an asymmetric vertical error bar:
+
+/errorbar { % x y d- d+ | -
+   gsave
+      slin setline
+      3 copy pop pop
+      dup 0 gt x 10 lt and {
+         4 copy
+         x pop add 10. 2 copy gt { x } if pop ym x xm x
+         2 copy x .05 sub x np mv .1 0 rl st
+         np mv
+         pop sub 0. 2 copy lt { x } if pop ym x xm x
+         2 copy lineto st
+         x .05 sub x np mv .1 0 rl st
+         } {
+         pop pop pop pop
+         } ifelse
+      grestore
+} def
+
+%%  Plot a data symbol:
+
+/plot_symbol { % x y | -
+    gsave
+       offset
+       srad dup scale
+       slin srad div setline % factor 1/srad compensates "scale"
+       ps % the actual plot symbol, defined by 'pset'
+       grestore
+   } def
+
+/fill_symbol {
+   sfill dup
+      0 eq {
+         pop st
+      } {
+         1 eq {
+            fill
+         } {
+            gsave fill grestore
+            gsave black st grestore
+         } ifelse
+      } ifelse
+   } def
+
+%%  The different symbols, designed for unit area (no arguments):
+
+/ps_nil {
+    } bind def
+
+/ps_square {
+   .5 .5 np mv
+   0 -1 rl
+   -1 0 rl
+   0  1 rl cp fill_symbol
+   } bind def
+
+/ps_diamond {
+   gsave 45 rotate ps_square grestore
+   } bind def
+
+/ps_circle {
+   0 0 np .564 0 360 arc cp fill_symbol
+   } bind def
+
+/ps_triangle {
+   .77 dup dup 90 pol2xy np mv
+   210 pol2xy li
+   330 pol2xy li cp fill_symbol
+   } bind def
+
+/ps_cedez {
+   gsave 180 rotate ps_triangle grestore
+   } bind def
+
+/ps_tfwd {
+   gsave 30 rotate ps_triangle grestore
+   } bind def
+
+/ps_tbwd {
+   gsave 210 rotate ps_triangle grestore
+   } bind def
+
+/ps_eieruhr {
+   -.7 -.7 np mv
+    .7 -.7 li
+   -.7  .7 li
+    .7  .7 li cp fill_symbol
+   } bind def
+
+/ps_valve {
+   gsave 90 rotate ps_eieruhr grestore
+   } bind def
+
+/ps_pentagram {
+   .8 dup dup dup dup
+    90 pol2xy np mv
+   234 pol2xy li
+    18 pol2xy li
+   162 pol2xy li
+   306 pol2xy li cp fill_symbol
+   } bind def
+
+/ps_pentagon {
+   .8 dup dup dup dup
+    18 pol2xy np mv
+    90 pol2xy li
+   162 pol2xy li
+   234 pol2xy li
+   306 pol2xy li cp fill_symbol
+   } bind def
+
+/ps_plus {
+   gsave 45 rotate ps_cross grestore
+   } bind def
+
+/ps_cross {
+   .5 .5 np mv
+   -1 -1 rl st
+  -.5 .5 np mv
+    1 -1 rl st
+   } bind def
+
+/ps_star {
+   .7 dup   0 pol2xy np mv 180 pol2xy li st
+   .7 dup 120 pol2xy np mv 300 pol2xy li st
+   .7 dup 240 pol2xy np mv  60 pol2xy li st
+   } bind def
+
+/ps_horiz {
+   -.7 0 np mv
+   1.4 0 rl st
+   } bind def
+
+/ps_verti {
+   0 -.7 np mv
+   0 1.4 rl st
+   } bind def
+
+%%  Set column plotting (use this instead of pset)
+/setcolumn{ % shift width exec | %
+   % usage: 0 .2 { gsave { .5 setgray fill } grestore cp } setcolumn
+   /colexec x def
+   /colwidth x xm def
+   /colshift x xm def
+   /t {
+      pop xym
+      np x colshift add colwidth 2 div sub dup 3 2 roll mv
+      colwidth 0 rl
+      colwidth add 0 li
+      colwidth neg 0 rl
+      cp colexec
+   } def
+   /ti { t } bind def
+   /tf { t black } bind def
+} def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  2D plots                                                                 %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/t2d {
+    icCol rect fill
+    black
+} def
+
+/ColorLegend { % - | - [plot color legend to rectangle hxlow hxhig 0 10]
+   /ncol 100 def
+   1 1 ncol {
+      dup ncol div 10 mul icCol
+      dup ncol div 10 mul
+      x 1 sub ncol div 10 mul
+      hxlow hxhig 4 2 roll rect fill
+      } for
+   } def
+/hColorLegend { % ditto, horizontally, to rectangle 0 10 hylow hyhig
+   /ncol 100 def
+   1 1 ncol {
+      dup ncol div 10 mul icCol
+      dup ncol div 10 mul
+      x 1 sub ncol div 10 mul
+      hylow hyhig rect fill
+      } for
+   } def
+% Usage:
+% hColorLegend
+%  hylow hyhig  0 0  90   0 OneAxx Axx
+%  hylow hyhig 10 0  90 180 OneAxx Axx
+%  0 10 0 hyhig 0  90 OneAxx Axx Tic Tac
+%  0 10 0 0     0  90 OneAxx Axx Tic Tac xNumL
+% {(intensity)} xCL
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  List                                                                     %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/NewList { % xins yins size advance NewList -
+   /nl_advance x def setown /nl_yins x def /nl_xins x def
+   /nl_xshift fontsize xmm div .9 mul def
+   /nl_xrline 0.33 def
+   /nl_ystep fontheight ymm div nl_advance mul def
+   /newline {
+       /nl_yins nl_yins nl_ystep sub def
+      } def
+   /fracline { % frac | -
+      fontheight ymm div nl_advance mul mul /nl_yins x nl_yins x sub def
+      } def
+   } def
+/newlist { 1.65 NewList } def
+/TxLine { % text TxLine -
+   nl_xins nl_yins 3 -1 roll textLM newline
+   } bind def
+/TxCLine { % text TxLine -
+   nl_xins nl_yins 3 -1 roll textCM newline
+   } bind def
+/PtTxLine { % pstyle text | -
+   x pstyle
+   nl_xins nl_xshift .5 mul add nl_yins 0 t
+   black nl_xins nl_xshift 1.5 mul add nl_yins 3 2 roll textLM
+   newline
+   } bind def
+/PttttTxLine { % pstyle text | - %% chain of very small symbols
+   x pstyle
+   nl_xins nl_xshift .10 mul add nl_yins 0 t
+   nl_xins nl_xshift .26 mul add nl_yins 0 t
+   nl_xins nl_xshift .42 mul add nl_yins 0 t
+   nl_xins nl_xshift .58 mul add nl_yins 0 t
+   nl_xins nl_xshift .74 mul add nl_yins 0 t
+   nl_xins nl_xshift .90 mul add nl_yins 0 t
+   black nl_xins nl_xshift 1.5 mul add nl_yins 3 2 roll textLM
+   newline
+   } bind def
+/PtPtCvTxLine { % pstyle pstyle cstyle text | -
+   4 3 roll pstyle nl_xins nl_yins 0 t
+   3 2 roll pstyle nl_xins nl_xshift add nl_yins 0 t
+   x cstyle
+   nl_xins nl_xshift 2 mul add
+   dup dup nl_xshift nl_xrline mul sub nl_yins 0 ti
+   nl_xshift nl_xrline mul add nl_yins 0 tf
+   nl_xshift add nl_yins 3 2 roll black textLM
+   newline
+   } bind def
+/PtCvTxLine { % pstyle cstyle text | -
+   3 2 roll pstyle nl_xins nl_yins 0 t
+   x cstyle
+   nl_xins nl_xshift 1 mul add
+   dup dup nl_xshift -.33 mul add nl_yins 0 ti
+   nl_xshift 0.33 mul add nl_yins 0 tf
+   nl_xshift add nl_yins 3 2 roll black textLM
+   newline
+   } bind def
+/PtPtTxLine { % pstyle pstyle text | -
+   3 2 roll pstyle nl_xins nl_yins 0 t
+   x pstyle nl_xins nl_xshift add nl_yins 0 t
+   black nl_xins nl_xshift 2 mul add nl_yins 3 2 roll textLM
+   newline
+   } bind def
+/CvTxLine { % cstyle text | -
+   x cstyle
+   nl_xins fontsize xmm div nl_xrline mul 0 mul sub nl_yins 0 ti
+   nl_xins fontsize xmm div nl_xrline mul 3 mul add nl_yins 0 tf
+   black nl_xins nl_xshift 1.5 mul add nl_yins 3 2 roll textLM
+   newline
+   } bind def
+/Cv2TxLine { % cstyle text | -
+   x cstyle
+   nl_xins fontsize xmm div nl_xrline mul sub nl_yins 0 ti
+   nl_xins fontsize xmm div nl_xrline mul add nl_xshift add nl_yins 0 tf
+   black nl_xins nl_xshift 2 mul add nl_yins 3 2 roll textLM
+   newline
+   } bind def
+/PCTxLine { % pstyle(with plset) text | -
+   x pstyle
+   nl_xins fontsize xmm div nl_xrline 2 mul mul sub nl_yins 0 ci
+   nl_xins fontsize xmm div nl_xrline 2 mul mul add nl_yins 0 cf
+   nl_xins yins 0 t
+   black nl_xins
+      fontsize xmm div 1.9 mul % instead of xshift
+      add nl_yins 3 2 roll textLM
+   newline
+   } bind def
+/infSet { % oooinfo | - : set whether(1) or not(0) to plot info block
+   /oooinfo x def
+   } def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Boxes
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/rect { % xl xh yl yh | - [path -> rectangle]
+   ym /qqyh x def
+   ym /qqyl x def
+   xm /qqxh x def
+   xm /qqxl x def
+   np
+   qqxl qqyl mv
+   qqxh qqyl li
+   qqxh qqyh li
+   qqxl qqyh li
+   cp
+   } def
+/oval { %  xl xh yl yh dr | - [path -> oval]
+   fm /qqdr x def
+   ym /qqyh x def
+   ym /qqyl x def
+   xm /qqxh x def
+   xm /qqxl x def
+   qqxl qqyl qqdr add np mv
+   qqxl qqyh qqdr sub li
+   qqxl qqdr add qqyh qqdr sub qqdr 180 90 arcn
+   qqxh qqdr sub qqyh li
+   qqxh qqdr sub qqyh qqdr sub qqdr 90 0 arcn
+   qqxh qqyl qqdr add li
+   qqxh qqdr sub qqyl qqdr add qqdr 0 -90 arcn
+   qqxl qqdr add qqyl li
+   qqxl qqdr add qqyl qqdr add qqdr -90 -180 arcn
+   cp
+   } def
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Arrows
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/pfeilangle 36.87 def
+/pfeilspitze { % x[local] y[local] rot siz
+   % draw with current linestyle, as set e.g. by linsetAxx
+   x 4 2 roll % siz rot x y
+   gsave
+     xym translate 180 add rotate dup dup dup
+     [] 0 setdash
+     pfeilangle cos mul x pfeilangle sin mul np mv
+     0 0 li pfeilangle cos mul x pfeilangle sin neg mul li st
+   grestore
+   } def
+/pfeiL { % (arrow anchored at base) x y rot siz len
+   gsave
+      dup xm x ym mul sqrt % (scale len)
+      5 3 roll
+      xym translate % (origin at base) rot siz len
+      3 2 roll
+      rotate % (draw rightwards) siz len
+      dup 0 translate % (origin at head) siz len
+      x 0 0 0 4 3 roll pfeilspitze % len
+      0 0 np mv neg 0 li st
+   grestore
+   } def
+/Pfeil { % (arrow anchored at head) x y rot siz len
+   dup xm x ym mul sqrt 5 copy
+   pop pfeilspitze
+   x pop
+   x 4 2 roll % len rot x y
+   gsave
+      xym translate 180 add rotate
+      0 0 np mv 0 li st
+   grestore
+   } def
+
+/bemasz { % x y L ang text | - %% precede by '24 setown 1 [] lset /pfeilangle 90 def'
+   gsave
+   5 3 roll offset % consumes x and y
+   x rotate % consumes ang | L text
+   dup textw .5 mul fontheight .4 mul add /bmszDT x def % => half text width
+   0 0 3 2 roll textCM % L
+   .5 mul /bmszDX x def % => half bemasz length
+   bmszDX     0   0 fontheight .67 mul bmszDX bmszDT sub Pfeil
+   bmszDX neg 0 180 fontheight .67 mul bmszDX bmszDT sub Pfeil
+   grestore
+   } def
+
+end % WuGdict...
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%  Mark "ewu", the end of the wups.. macro definition file                  %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/pub/src/CMakeLists.txt b/pub/src/CMakeLists.txt
index e65bfd3b9ee32c1e0151b5fb4f11588a925d17cc..0e815c1afcd442dc74d97a9d198dc34c205c09d4 100644
--- a/pub/src/CMakeLists.txt
+++ b/pub/src/CMakeLists.txt
@@ -2,16 +2,16 @@
 
 CONFIGURE_FILE ("config_src.hpp.in" "${CMAKE_CURRENT_BINARY_DIR}/config_src.hpp")
 
-include_directories(${CMAKE_CURRENT_BINARY_DIR} ${Frida_SOURCE_DIR}/lib)
+include_directories(
+    ${CMAKE_CURRENT_BINARY_DIR}
+    ${Frida_SOURCE_DIR}/lib
+    ${Frida_SOURCE_DIR}/ThirdParty
+    )
 
 set(src_files frida2.cpp)
 
 add_executable(frida frida2.cpp)
 
-target_link_libraries(frida
-    libtrivia
-    libreadplus
-    ${GSL_LIBRARIES}
-    libfrida)
+target_link_libraries(frida ${fridacore_LIBRARY})
 
 install(TARGETS frida DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
diff --git a/pub/src/config_src.hpp.in b/pub/src/config_src.hpp.in
index f43b33df12f93a111fe3a4333a5bae29b39681d0..5db452e7426c3fb89e46ba598ec0f12fb0e55f78 100644
--- a/pub/src/config_src.hpp.in
+++ b/pub/src/config_src.hpp.in
@@ -1 +1,2 @@
 #define CONFDIR "@CMAKE_INSTALL_PREFIX@/share/frida"
+#define VERSION "@Frida_VERSION@"
diff --git a/pub/src/frida2.cpp b/pub/src/frida2.cpp
index fca862ba0a7bc52eb169aba307d235947933c2ff..273df2e4a197eb9307d3f3e3a2fe8923b6e8de54 100644
--- a/pub/src/frida2.cpp
+++ b/pub/src/frida2.cpp
@@ -31,6 +31,8 @@
 
 
 #include <string>
+#include <vector>
+#include <tclap/CmdLine.h>
 #include "config_src.hpp"
 #include "toplevel.hpp"
 
@@ -38,18 +40,37 @@
 
 int main(int argc, char* argv[])
 {
-    // Initialize runtime environment.
-    CFrida frida;
+    try {
+	TCLAP::CmdLine cmd("Flexible rapid interactive data analysis", ' ', VERSION, true);
+	TCLAP::SwitchArg batchSwitch("b","batch","Batch mode: exit on error", cmd, false);
+        TCLAP::UnlabeledMultiArg<std::string> multi("script", "Script files", false, "");
+        cmd.add( multi );
+        cmd.parse(argc, argv);
+
+	bool batchMode = batchSwitch.getValue();
+        std::vector<std::string> scripts = multi.getValue();
+
+        // Initialize runtime environment.
+        CFrida frida;
 
 #ifdef CONFDIR
-    // Execute initialization script.
-    frida.execute_file( CONFDIR "/frida.ini" );
+        // Execute initialization script.
+        frida.execute_file( CONFDIR "/frida.ini", batchMode );
 #endif
 
-    // Execute scripts from command line (used in particular by shebang files).
-    for( int iarg=1; iarg<argc; ++iarg )
-        frida.execute_file( argv[iarg] );
+        // Execute scripts from command line (used in particular by shebang files).
+        for( const std::string& script: scripts )
+            frida.execute_file( script, batchMode );
+
+        // Interactive main loop.
+        frida.interactive();
 
-    // Interactive main loop.
-    frida.interactive();
+    } catch (TCLAP::ArgException &e) {
+        std::cerr << "error: " << e.error() << " for arg " << e.argId() << "\n";
+        exit(1);
+    } catch (...) {
+        std::cerr << "Unexpected uncatched exception in main program\n";
+        exit(1);
+    }
+    exit(0);
 }
diff --git a/pub/trivia/CMakeLists.txt b/pub/trivia/CMakeLists.txt
index b2818757cf2bad12e4a69dafa0b1377a4bcf4cc8..93b95855639826ff2da6cfa04bc550cd5f743728 100644
--- a/pub/trivia/CMakeLists.txt
+++ b/pub/trivia/CMakeLists.txt
@@ -1,34 +1,42 @@
 # frida: trivia/CMakeLists.txt
 
+set(library_name fridatrivia)
+set(${library_name}_LIBRARY ${library_name} PARENT_SCOPE)
+set(${library_name}_LIBRARY_TYPE SHARED)
+
 include_directories(${Frida_SOURCE_DIR}/trivia ${CMAKE_CURRENT_BINARY_DIR})
 
 set(src_files
-file_ops.cpp
-integrate.cpp
-math.cpp
-rng.cpp
-string_convs.cpp
-string_ops.cpp
-vector_ops.cpp
-yaml_out.cpp
-)
+    file_ops.cpp
+    integrate.cpp
+    math.cpp
+    rng.cpp
+    string_convs.cpp
+    string_ops.cpp
+    vector_ops.cpp
+    yaml_out.cpp
+    )
 
 set(inc_files
-file_ops.hpp
-integrate.hpp
-math.hpp
-rng.hpp
-singleton.hpp
-string_convs.hpp
-string_ops.hpp
-vector_ops.hpp
-yaml_out.hpp
-)
+    file_ops.hpp
+    integrate.hpp
+    math.hpp
+    rng.hpp
+    singleton.hpp
+    string_convs.hpp
+    string_ops.hpp
+    vector_ops.hpp
+    yaml_out.hpp
+    )
 
-add_library(libtrivia SHARED ${src_files})
+add_library(${library_name} SHARED ${src_files})
 
-set_target_properties(libtrivia PROPERTIES OUTPUT_NAME trivia)
+set_target_properties(${library_name} PROPERTIES OUTPUT_NAME ${library_name})
 
-target_link_libraries(libtrivia)
+target_link_libraries(${library_name}
+    ${GSL_LIBRARIES}
+    ${YAMLCPP_LIBRARY}
+    ${Boost_FILESYSTEM_LIBRARY}
+)
 
-install(TARGETS libtrivia DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
+install(TARGETS ${library_name} LIBRARY DESTINATION ${destination_lib} COMPONENT Libraries)
diff --git a/pub/trivia/file_ops.cpp b/pub/trivia/file_ops.cpp
index 3e43738c95454a8bbaf09fbf449eda8ccbd8d5f7..adee27f390d484cad2d8039d9595ff8544485b77 100644
--- a/pub/trivia/file_ops.cpp
+++ b/pub/trivia/file_ops.cpp
@@ -7,10 +7,11 @@
 
 #include <sys/stat.h>
 #include <wordexp.h>
-
 #include <iostream>
-
 #include <boost/format.hpp>
+#include <boost/filesystem.hpp>
+
+namespace fs = boost::filesystem;
 
 using boost::format;
 using std::string;
@@ -76,29 +77,6 @@ bool triv::file_exists(const string& path)
     return 1;
 }
 
-//! Analyses a file name: divides "dir/short.ext" into "dir", "short", "ext".
-
-void triv::fname_divide(const string& fname, string* fdir, string* fshort, string* fext)
-// each of the three output arguments, when called with a nullptr, will not be computed
-{
-    size_t idir = fname.rfind("/") + 1;
-    if (fdir)
-        *fdir = fname.substr(0, idir);
-
-    size_t iext = fname.rfind(string(".")) + 1;
-    if (iext <= idir) {
-        if (fext)
-            *fext = "";
-        if (fshort)
-            *fshort = fname.substr(idir);
-    } else {
-        if (fext)
-            *fext = fname.substr(iext);
-        if (fshort)
-            *fshort = fname.substr(idir, iext - idir - 1);
-    }
-}
-
 
 //! Returns a unique file name obtained by Posix shell expansion of a given pattern.
 
@@ -151,13 +129,13 @@ string triv::next_tmp_file(const string& path_format)
     const int tmpmax = 1024;
     for (int i = 0; i < tmpmax; ++i) {
         string fname = str(format(path_format) % i);
-        if (!triv::file_exists(fname))
+        if (!triv::file_exists(triv::wordexp_unique(fname)))
             return fname;
         if (i == tmpmax / 2)
-            cerr << "WARNING: there more than " << i << " temporay files of form " << path_format
-                 << "; please clean up soon\n";
+            cerr << "WARNING: there more than " << i << " files of form '" << path_format
+                 << "'; please clean up soon\n";
     }
-    throw "Too many temporary files in use";
+    throw "Too many files of type '" + path_format + "' in use";
 }
 
 
@@ -175,8 +153,7 @@ vector<string> triv::glob_file_list(const string& patterns, const string& extens
         throw string("empty file list");
     vector<string> vExtension = split(extensions);
     for (string pat : vPattern) {
-        string fmain, fext;
-        fname_divide(pat, nullptr, &fmain, &fext);
+        string fext = fs::path(pat).extension().string();
         if (fext == "" && vExtension.size()) {
             for (string ext : vExtension)
                 extended_patterns += pat + "." + ext + " ";
diff --git a/pub/trivia/file_ops.hpp b/pub/trivia/file_ops.hpp
index ee9a1e22201f210196ad4f9abe5530f59423470c..2af595e21002aec2da096d2148f628d02b4d42f5 100644
--- a/pub/trivia/file_ops.hpp
+++ b/pub/trivia/file_ops.hpp
@@ -8,6 +8,9 @@
 #ifndef FILE_OPS_H
 #define FILE_OPS_H
 
+#include <string>
+#include <vector>
+
 namespace triv
 {
 
@@ -17,8 +20,6 @@ std::string system_read(std::string cmd, bool debug = false);
 
 // File names, globbing:
 bool file_exists(const std::string& fname);
-void fname_divide(
-    const std::string& fname, std::string* fdir, std::string* fshort, std::string* fext);
 std::vector<std::string> glob_file_list(const std::string& patterns, const std::string& extensions);
 std::string wordexp_unique(const std::string& s);
 std::vector<std::string> wordexp_multi(const std::string& s);
diff --git a/pub/trivia/integrate.cpp b/pub/trivia/integrate.cpp
index 3993cfb16bd72710eb7a79751441d0e8e4311a7f..f5ce5ed81df9155052e3439910e47c6955167756 100644
--- a/pub/trivia/integrate.cpp
+++ b/pub/trivia/integrate.cpp
@@ -52,6 +52,8 @@ double triv::integrate(
         case 6:
             rule = GSL_INTEG_GAUSS15;
             break;
+        default:
+            throw "Impossible case";
         }
         // QAG adaptive integration
         gsl_integration_qag(&F, low, hig, epsabs, epsrel, nwork, rule, work, &val, &err);
diff --git a/pub/trivia/vector_ops.cpp b/pub/trivia/vector_ops.cpp
index 36f30708ecc7a4df6f4a04cdae0987e252cc7c42..49a0d6b6c27a962b103c798dff63a23286debdcd 100644
--- a/pub/trivia/vector_ops.cpp
+++ b/pub/trivia/vector_ops.cpp
@@ -167,3 +167,17 @@ std::string triv::indices_to_s(const vector<int>& v)
     }
     return ret;
 }
+
+//! Determines minimal positive value and maximal value in vector v.
+//! Results must be tested for finiteness.
+void triv::getPosminMax(const std::vector<double>& v, double& minval, double&maxval)
+{
+    minval = +INFINITY;
+    maxval = -INFINITY;
+    for (auto t = v.begin(); t<v.end(); ++t) {
+        if (*t<=0)
+            continue;
+        minval = std::min(minval, *t);
+        maxval = std::max(maxval, *t);
+    }
+}
diff --git a/pub/trivia/vector_ops.hpp b/pub/trivia/vector_ops.hpp
index d26ccb05d064b22612fcd320f88fe4a61a0ac5e3..b47e28bb9b59d5d8dc138ec66e04e334ed9b89c4 100644
--- a/pub/trivia/vector_ops.hpp
+++ b/pub/trivia/vector_ops.hpp
@@ -8,25 +8,66 @@
 #ifndef VECTOR_OPS_H
 #define VECTOR_OPS_H
 
+#include <cmath>
 #include <vector>
+#include <functional>
+#include <algorithm>
 
 namespace triv
 {
+    void insert_in_sorted(std::vector<double>* V, double val);
+    void make_unique(std::vector<double>* V, double tolabs = 1e-100, double tolrel = 1e-10);
+    bool is_ascending(const std::vector<double>& V);
+    bool is_equidist(double* step, const std::vector<double>& V);
+    std::vector<size_t> sorted_indices(std::vector<double> const& V);
+    std::vector<int> iota_list(int number_of_entries);
+    std::vector<double> histogram_limits(const std::vector<double>& channel_centers);
+    void increment_indices(std::vector<int>& v, int incr, int siz);
+    std::string indices_to_s(const std::vector<int>& v);
 
-void insert_in_sorted(std::vector<double>* V, double val);
-void make_unique(std::vector<double>* V, double tolabs = 1e-100, double tolrel = 1e-10);
-bool is_ascending(const std::vector<double>& V);
-bool is_equidist(double* step, const std::vector<double>& V);
-std::vector<size_t> sorted_indices(std::vector<double> const& V);
-std::vector<int> iota_list(int number_of_entries);
-std::vector<double> histogram_limits(const std::vector<double>& channel_centers);
-void increment_indices(std::vector<int>& v, int incr, int siz);
-std::string indices_to_s(const std::vector<int>& v);
-
-template <class A> bool contains(const std::vector<A>& v, const A e)
-{
-    return std::find(v.begin(), v.end(), e) != v.end();
-}
+    template <class T> void getMinMax(const std::vector<T>& v, T& minval, T&maxval);
+    void getPosminMax(const std::vector<double>& v, double& minval, double&maxval);
+    template <class T> bool contains(const std::vector<T>& v, const T e);
+    template <class T, class Pred> std::vector<T> merge_sorted(
+        const std::vector<T>& a, const std::vector<T>& b, Pred a_before_b);
+
+//**************************************************************************************************
+//  Template implementation
+//**************************************************************************************************
+
+    template <class T>
+    void getMinMax(const std::vector<T>& v, T& minval, T&maxval)
+    {
+        if (v.size()==0)
+            throw "BUG: attempt to determine min and max of empty vector";
+        minval = v.front();
+        maxval = v.front();
+        for (auto t = v.begin()+1; t<v.end(); ++t) {
+            minval = std::min(minval, *t);
+            maxval = std::max(maxval, *t);
+        }
+    }
+
+    template <class T>
+    bool contains(const std::vector<T>& v, const T e)
+    {
+        return std::find(v.begin(), v.end(), e) != v.end();
+    }
+
+    template <class T, class Pred>
+    std::vector<T> merge_sorted(const std::vector<T>& a, const std::vector<T>& b, Pred a_before_b)
+    {
+        std::vector<T> ret;
+        auto ia=a.begin();
+        auto ib=b.begin();
+        for (;ia!=a.end() && ib!=b.end();)
+            ret.push_back( a_before_b(*ia,*ib) ? *(ia++) : *(ib++) );
+        for (;ia!=a.end();)
+            ret.push_back( *(ia++) );
+        for (;ib!=b.end();)
+            ret.push_back( *(ib++) );
+        return ret;
+    }
 }
 
 #endif // VECTOR_OPS_H
diff --git a/pub/utest/CMakeLists.txt b/pub/utest/CMakeLists.txt
index 0bb8d006fb4ffdbbf2769fc32d8d6387bf220b18..1ced2ef640c84db9166a5e1e70d1b9a98f8513bf 100644
--- a/pub/utest/CMakeLists.txt
+++ b/pub/utest/CMakeLists.txt
@@ -25,10 +25,7 @@ link_directories(
 
 set(test_link_libs
     gtest_main
-    libtrivia
-    libreadplus
-    ${GSL_LIBRARIES}
-    libfrida
+    ${fridacore_LIBRARY}
     )
 
 # We glob test sources, though this is often considered evil.
@@ -40,6 +37,6 @@ list(SORT test_sources)
 foreach(test_src ${test_sources})
     # remove directory path and suffix, to retain just the name of the test
     string(REGEX REPLACE ".*/" "" test_name "${test_src}")
-    string(REGEX REPLACE ".cpp$" "" test_name "${test_name}")
+    string(REGEX REPLACE "\\.cpp$" "" test_name "${test_name}")
     cxx_test(${test_name} "${test_link_libs}")
 endforeach(test_src)
diff --git a/pub/utest/test002_vecops.cpp b/pub/utest/test002_vecops.cpp
index 2eeb43315cbcbd8d1a2763d8958baa0e2b1a5c3e..26dc785f8f4ffd41724ec9f412e9486dea2f557f 100644
--- a/pub/utest/test002_vecops.cpp
+++ b/pub/utest/test002_vecops.cpp
@@ -11,3 +11,31 @@ TEST(VecOpsTest, HistoLimits) {
     EXPECT_NEAR(15., l[3], 1e-14 );
     EXPECT_NEAR(19., l[4], 1e-14 );
 }
+
+TEST(VecOpsTest, InsertSorted) {
+    std::vector<double> A { 1.1, 1.3, 1.8 };
+    std::vector<double> B { 2.1, 2.2, 2.4, 2.7 };
+    auto f = [](const double a, const double b) -> bool { return (a-(long)(a))<=(b-(long(b))); };
+    std::vector<double> C = triv::merge_sorted(A, B, f);
+    EXPECT_EQ( C[0], A[0] );
+    EXPECT_EQ( C[1], B[0] );
+    EXPECT_EQ( C[2], B[1] );
+    EXPECT_EQ( C[3], A[1] );
+    EXPECT_EQ( C[4], B[2] );
+    EXPECT_EQ( C[5], B[3] );
+    EXPECT_EQ( C[6], A[2] );
+}
+
+TEST(VecOpsTest, InsertSortedInplace) {
+    std::vector<double> A { 1.1, 1.3, 1.8 };
+    std::vector<double> B { 2.1, 2.2, 2.4, 2.7 };
+    auto f = [](const double a, const double b) -> bool { return (a-(long)(a))<=(b-(long(b))); };
+    A = triv::merge_sorted(A, B, f);
+    EXPECT_EQ( A[0], 1.1  );
+    EXPECT_EQ( A[1], B[0] );
+    EXPECT_EQ( A[2], B[1] );
+    EXPECT_EQ( A[3], 1.3  );
+    EXPECT_EQ( A[4], B[2] );
+    EXPECT_EQ( A[5], B[3] );
+    EXPECT_EQ( A[6], 1.8  );
+}